mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-21 22:39:12 +00:00
Add ability to assign icons
More progress Open IconPicker dialog on click Add ability to reset Fix changing icons Cleanup Add ability to assign icons after import PR fixes
This commit is contained in:
parent
b916697391
commit
1a6f85ccb6
20 changed files with 717 additions and 15 deletions
|
@ -82,6 +82,8 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.GroupManagerActivity"
|
android:name=".ui.GroupManagerActivity"
|
||||||
android:label="@string/title_activity_manage_groups" />
|
android:label="@string/title_activity_manage_groups" />
|
||||||
|
<activity android:name=".AssignIconsActivity"
|
||||||
|
android:label="@string/title_activity_assign_icons"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.PanicResponderActivity"
|
android:name=".ui.PanicResponderActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
package com.beemdevelopment.aegis;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import androidx.activity.OnBackPressedCallback;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.beemdevelopment.aegis.helpers.MetricsHelper;
|
||||||
|
import com.beemdevelopment.aegis.icons.IconPack;
|
||||||
|
import com.beemdevelopment.aegis.ui.AegisActivity;
|
||||||
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
|
import com.beemdevelopment.aegis.ui.dialogs.IconPickerDialog;
|
||||||
|
import com.beemdevelopment.aegis.ui.glide.IconLoader;
|
||||||
|
import com.beemdevelopment.aegis.ui.models.AssignIconEntry;
|
||||||
|
import com.beemdevelopment.aegis.ui.views.AssignIconAdapter;
|
||||||
|
import com.beemdevelopment.aegis.ui.views.IconAdapter;
|
||||||
|
import com.beemdevelopment.aegis.util.IOUtils;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.ListPreloader;
|
||||||
|
import com.bumptech.glide.RequestBuilder;
|
||||||
|
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader;
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
import com.bumptech.glide.util.ViewPreloadSizeProvider;
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class AssignIconsActivity extends AegisActivity implements AssignIconAdapter.Listener {
|
||||||
|
private AssignIconAdapter _adapter;
|
||||||
|
private ArrayList<AssignIconEntry> _entries = new ArrayList<>();
|
||||||
|
private RecyclerView _entriesView;
|
||||||
|
private AssignIconsActivity.BackPressHandler _backPressHandler;
|
||||||
|
private ViewPreloadSizeProvider<AssignIconEntry> _preloadSizeProvider;
|
||||||
|
private IconPack _favoriteIconPack;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (abortIfOrphan(savedInstanceState)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_assign_icons);
|
||||||
|
setSupportActionBar(findViewById(R.id.toolbar));
|
||||||
|
if (getSupportActionBar() != null) {
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<UUID> assignIconEntriesIds = (ArrayList<UUID>) getIntent().getSerializableExtra("entries");
|
||||||
|
for (UUID entryId: assignIconEntriesIds) {
|
||||||
|
VaultEntry vaultEntry = _vaultManager.getVault().getEntryByUUID(entryId);
|
||||||
|
_entries.add(new AssignIconEntry(vaultEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
_backPressHandler = new AssignIconsActivity.BackPressHandler();
|
||||||
|
getOnBackPressedDispatcher().addCallback(this, _backPressHandler);
|
||||||
|
|
||||||
|
IconPreloadProvider modelProvider1 = new IconPreloadProvider();
|
||||||
|
EntryIconPreloadProvider modelProvider2 = new EntryIconPreloadProvider();
|
||||||
|
_preloadSizeProvider = new ViewPreloadSizeProvider<>();
|
||||||
|
RecyclerViewPreloader<IconPack.Icon> preloader1 = new RecyclerViewPreloader(this, modelProvider1, _preloadSizeProvider, 10);
|
||||||
|
RecyclerViewPreloader<VaultEntry> preloader2 = new RecyclerViewPreloader(this, modelProvider2, _preloadSizeProvider, 10);
|
||||||
|
|
||||||
|
_adapter = new AssignIconAdapter(this);
|
||||||
|
_entriesView = findViewById(R.id.list_assign_icons);
|
||||||
|
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||||
|
_entriesView.setLayoutManager(layoutManager);
|
||||||
|
_entriesView.setAdapter(_adapter);
|
||||||
|
_entriesView.setNestedScrollingEnabled(false);
|
||||||
|
_entriesView.addItemDecoration(new SpacesItemDecoration(8));
|
||||||
|
_entriesView.addOnScrollListener(preloader1);
|
||||||
|
_entriesView.addOnScrollListener(preloader2);
|
||||||
|
|
||||||
|
Optional<IconPack> favoriteIconPack = _iconPackManager.getIconPacks().stream()
|
||||||
|
.sorted(Comparator.comparing(IconPack::getName))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (!favoriteIconPack.isPresent()) {
|
||||||
|
throw new RuntimeException(String.format("Started %s without any icon packs present", AssignIconsActivity.class.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
_favoriteIconPack = favoriteIconPack.get();
|
||||||
|
|
||||||
|
for (AssignIconEntry entry : _entries) {
|
||||||
|
IconPack.Icon suggestedIcon = findSuggestedIcon(entry);
|
||||||
|
if (suggestedIcon != null) {
|
||||||
|
entry.setNewIcon(suggestedIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_adapter.addEntries(_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IconPack.Icon findSuggestedIcon(AssignIconEntry entry) {
|
||||||
|
List<IconPack.Icon> suggestedIcons = _favoriteIconPack.getSuggestedIcons(entry.getEntry().getIssuer());
|
||||||
|
if (suggestedIcons.size() > 0) {
|
||||||
|
return suggestedIcons.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAndFinish() throws IOException {
|
||||||
|
ArrayList<UUID> uuids = new ArrayList<>();
|
||||||
|
for (AssignIconEntry selectedEntry : _entries) {
|
||||||
|
VaultEntry entry = selectedEntry.getEntry();
|
||||||
|
if(selectedEntry.getNewIcon() != null) {
|
||||||
|
byte[] iconBytes;
|
||||||
|
try (FileInputStream inStream = new FileInputStream(selectedEntry.getNewIcon().getFile())){
|
||||||
|
iconBytes = IOUtils.readFile(inStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.setIcon(iconBytes, selectedEntry.getNewIcon().getIconType());
|
||||||
|
uuids.add(entry.getUUID());
|
||||||
|
|
||||||
|
_vaultManager.getVault().replaceEntry(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra("entryUUIDs", uuids);
|
||||||
|
|
||||||
|
if (saveAndBackupVault()) {
|
||||||
|
setResult(RESULT_OK, intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discardAndFinish() {
|
||||||
|
Dialogs.showDiscardDialog(this,
|
||||||
|
(dialog, which) -> {
|
||||||
|
try {
|
||||||
|
saveAndFinish();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(this, R.string.saving_assign_icons_error, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(dialog, which) -> finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.menu_groups, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
discardAndFinish();
|
||||||
|
break;
|
||||||
|
case R.id.action_save:
|
||||||
|
try {
|
||||||
|
saveAndFinish();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(this, R.string.saving_assign_icons_error, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAssignIconEntryClick(AssignIconEntry entry) {
|
||||||
|
BottomSheetDialog dialog = IconPickerDialog.create(this, Collections.singletonList(_favoriteIconPack), entry.getEntry().getIssuer(), false, new IconAdapter.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onIconSelected(IconPack.Icon icon) {
|
||||||
|
entry.setNewIcon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCustomSelected() { }
|
||||||
|
});
|
||||||
|
Dialogs.showSecureDialog(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSetPreloadView(View view) {
|
||||||
|
_preloadSizeProvider.setView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BackPressHandler extends OnBackPressedCallback {
|
||||||
|
public BackPressHandler() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleOnBackPressed() {
|
||||||
|
discardAndFinish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EntryIconPreloadProvider implements ListPreloader.PreloadModelProvider<VaultEntry> {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public List<VaultEntry> getPreloadItems(int position) {
|
||||||
|
VaultEntry entry = _entries.get(position).getEntry();
|
||||||
|
if (entry.hasIcon()) {
|
||||||
|
return Collections.singletonList(entry);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public RequestBuilder<Drawable> getPreloadRequestBuilder(@NonNull VaultEntry entry) {
|
||||||
|
return Glide.with(AssignIconsActivity.this)
|
||||||
|
.asDrawable()
|
||||||
|
.load(entry)
|
||||||
|
.set(IconLoader.ICON_TYPE, entry.getIconType())
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.skipMemoryCache(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IconPreloadProvider implements ListPreloader.PreloadModelProvider<IconPack.Icon> {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public List<IconPack.Icon> getPreloadItems(int position) {
|
||||||
|
AssignIconEntry entry = _entries.get(position);
|
||||||
|
if (entry.getNewIcon() != null) {
|
||||||
|
return Collections.singletonList(entry.getNewIcon());
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public RequestBuilder<Drawable> getPreloadRequestBuilder(@NonNull IconPack.Icon icon) {
|
||||||
|
return Glide.with(AssignIconsActivity.this)
|
||||||
|
.asDrawable()
|
||||||
|
.load(icon.getFile())
|
||||||
|
.set(IconLoader.ICON_TYPE, icon.getIconType())
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.skipMemoryCache(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SpacesItemDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
private final int _space;
|
||||||
|
|
||||||
|
public SpacesItemDecoration(int dpSpace) {
|
||||||
|
|
||||||
|
this._space = MetricsHelper.convertDpToPixels(AssignIconsActivity.this, dpSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
outRect.left = _space;
|
||||||
|
outRect.right = _space;
|
||||||
|
outRect.bottom = _space;
|
||||||
|
|
||||||
|
if (parent.getChildLayoutPosition(view) == 0) {
|
||||||
|
outRect.top = _space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,10 @@ public class IconPackManager {
|
||||||
return packs.get(0);
|
return packs.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasIconPack() {
|
||||||
|
return _iconPacks.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
public List<IconPack> getIconPacks() {
|
public List<IconPack> getIconPacks() {
|
||||||
return new ArrayList<>(_iconPacks);
|
return new ArrayList<>(_iconPacks);
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,7 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
IconViewHelper.setLayerType(_iconView, _origEntry.getIconType());
|
IconViewHelper.setLayerType(_iconView, _origEntry.getIconType());
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.asDrawable()
|
.asDrawable()
|
||||||
.load(_origEntry)
|
.load(_origEntry.getIcon())
|
||||||
.set(IconLoader.ICON_TYPE, _origEntry.getIconType())
|
.set(IconLoader.ICON_TYPE, _origEntry.getIconType())
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.skipMemoryCache(false)
|
.skipMemoryCache(false)
|
||||||
|
@ -500,7 +500,7 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BottomSheetDialog dialog = IconPickerDialog.create(this, iconPacks, _textIssuer.getText().toString(), new IconAdapter.Listener() {
|
BottomSheetDialog dialog = IconPickerDialog.create(this, iconPacks, _textIssuer.getText().toString(), true, new IconAdapter.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public void onIconSelected(IconPack.Icon icon) {
|
public void onIconSelected(IconPack.Icon icon) {
|
||||||
selectIcon(icon);
|
selectIcon(icon);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.beemdevelopment.aegis.ui;
|
package com.beemdevelopment.aegis.ui;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -14,12 +15,14 @@ import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.AssignIconsActivity;
|
||||||
import com.beemdevelopment.aegis.R;
|
import com.beemdevelopment.aegis.R;
|
||||||
import com.beemdevelopment.aegis.helpers.FabScrollHelper;
|
import com.beemdevelopment.aegis.helpers.FabScrollHelper;
|
||||||
import com.beemdevelopment.aegis.importers.DatabaseImporter;
|
import com.beemdevelopment.aegis.importers.DatabaseImporter;
|
||||||
import com.beemdevelopment.aegis.importers.DatabaseImporterEntryException;
|
import com.beemdevelopment.aegis.importers.DatabaseImporterEntryException;
|
||||||
import com.beemdevelopment.aegis.importers.DatabaseImporterException;
|
import com.beemdevelopment.aegis.importers.DatabaseImporterException;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
|
import com.beemdevelopment.aegis.ui.models.AssignIconEntry;
|
||||||
import com.beemdevelopment.aegis.ui.models.ImportEntry;
|
import com.beemdevelopment.aegis.ui.models.ImportEntry;
|
||||||
import com.beemdevelopment.aegis.ui.tasks.RootShellTask;
|
import com.beemdevelopment.aegis.ui.tasks.RootShellTask;
|
||||||
import com.beemdevelopment.aegis.ui.views.ImportEntriesAdapter;
|
import com.beemdevelopment.aegis.ui.views.ImportEntriesAdapter;
|
||||||
|
@ -244,8 +247,30 @@ public class ImportEntriesActivity extends AegisActivity {
|
||||||
String toastMessage = getResources().getQuantityString(R.plurals.imported_entries_count, selectedEntries.size(), selectedEntries.size());
|
String toastMessage = getResources().getQuantityString(R.plurals.imported_entries_count, selectedEntries.size(), selectedEntries.size());
|
||||||
Toast.makeText(this, toastMessage, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, toastMessage, Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
|
||||||
setResult(RESULT_OK, null);
|
setResult(RESULT_OK, null);
|
||||||
|
|
||||||
|
if (_iconPackManager.hasIconPack()) {
|
||||||
|
ArrayList<UUID> assignIconEntriesIds = new ArrayList<>();
|
||||||
|
Intent assignIconIntent = new Intent(getBaseContext(), AssignIconsActivity.class);
|
||||||
|
for (ImportEntry entry : selectedEntries) {
|
||||||
|
assignIconEntriesIds.add(entry.getEntry().getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
assignIconIntent.putExtra("entries", assignIconEntriesIds);
|
||||||
|
|
||||||
|
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.import_assign_icons_dialog_title)
|
||||||
|
.setMessage(R.string.import_assign_icons_dialog_text)
|
||||||
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||||
|
startActivity(assignIconIntent);
|
||||||
finish();
|
finish();
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.no, ((dialogInterface, i) -> finish()))
|
||||||
|
.create());
|
||||||
|
} else {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.view.ActionMode;
|
import androidx.appcompat.view.ActionMode;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.AssignIconsActivity;
|
||||||
import com.beemdevelopment.aegis.CopyBehavior;
|
import com.beemdevelopment.aegis.CopyBehavior;
|
||||||
import com.beemdevelopment.aegis.AccountNamePosition;
|
import com.beemdevelopment.aegis.AccountNamePosition;
|
||||||
import com.beemdevelopment.aegis.Preferences;
|
import com.beemdevelopment.aegis.Preferences;
|
||||||
|
@ -76,6 +77,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
private static final int CODE_DECRYPT = 4;
|
private static final int CODE_DECRYPT = 4;
|
||||||
private static final int CODE_PREFERENCES = 5;
|
private static final int CODE_PREFERENCES = 5;
|
||||||
private static final int CODE_SCAN_IMAGE = 6;
|
private static final int CODE_SCAN_IMAGE = 6;
|
||||||
|
private static final int CODE_ASSIGN_ICONS = 7;
|
||||||
|
|
||||||
|
|
||||||
// Permission request codes
|
// Permission request codes
|
||||||
private static final int CODE_PERM_CAMERA = 0;
|
private static final int CODE_PERM_CAMERA = 0;
|
||||||
|
@ -232,6 +235,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
break;
|
break;
|
||||||
case CODE_SCAN_IMAGE:
|
case CODE_SCAN_IMAGE:
|
||||||
onScanImageResult(data);
|
onScanImageResult(data);
|
||||||
|
break;
|
||||||
|
case CODE_ASSIGN_ICONS:
|
||||||
|
onAssignEntriesResult(data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
@ -317,6 +324,17 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
startActivityForResult(intent, requestCode);
|
startActivityForResult(intent, requestCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startAssignIconsActivity(int requestCode, List<VaultEntry> entries) {
|
||||||
|
ArrayList<UUID> assignIconEntriesIds = new ArrayList<>();
|
||||||
|
Intent assignIconIntent = new Intent(getBaseContext(), AssignIconsActivity.class);
|
||||||
|
for (VaultEntry entry : entries) {
|
||||||
|
assignIconEntriesIds.add(entry.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
assignIconIntent.putExtra("entries", assignIconEntriesIds);
|
||||||
|
startActivityForResult(assignIconIntent, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
private void startIntroActivity() {
|
private void startIntroActivity() {
|
||||||
if (!_isDoingIntro) {
|
if (!_isDoingIntro) {
|
||||||
Intent intro = new Intent(this, IntroActivity.class);
|
Intent intro = new Intent(this, IntroActivity.class);
|
||||||
|
@ -353,6 +371,17 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onAssignEntriesResult(Intent data) {
|
||||||
|
if (_loaded) {
|
||||||
|
ArrayList<UUID> entryUUIDs = (ArrayList<UUID>) data.getSerializableExtra("entryUUIDs");
|
||||||
|
|
||||||
|
for (UUID entryUUID: entryUUIDs) {
|
||||||
|
VaultEntry entry = _vaultManager.getVault().getEntryByUUID(entryUUID);
|
||||||
|
_entryListView.replaceEntry(entryUUID, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onScanImageResult(Intent intent) {
|
private void onScanImageResult(Intent intent) {
|
||||||
if (intent.getData() != null) {
|
if (intent.getData() != null) {
|
||||||
startDecodeQrCodeImages(Collections.singletonList(intent.getData()));
|
startDecodeQrCodeImages(Collections.singletonList(intent.getData()));
|
||||||
|
@ -916,6 +945,11 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
_actionMode.getMenu().findItem(R.id.action_copy).setVisible(!multipleSelected);
|
_actionMode.getMenu().findItem(R.id.action_copy).setVisible(!multipleSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setAssignIconsMenuItemVisibility() {
|
||||||
|
MenuItem assignIconsMenuItem = _actionMode.getMenu().findItem(R.id.action_assign_icons);
|
||||||
|
assignIconsMenuItem.setVisible(_iconPackManager.hasIconPack());
|
||||||
|
}
|
||||||
|
|
||||||
private void setFavoriteMenuItemVisiblity() {
|
private void setFavoriteMenuItemVisiblity() {
|
||||||
MenuItem toggleFavoriteMenuItem = _actionMode.getMenu().findItem(R.id.action_toggle_favorite);
|
MenuItem toggleFavoriteMenuItem = _actionMode.getMenu().findItem(R.id.action_toggle_favorite);
|
||||||
|
|
||||||
|
@ -948,6 +982,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
_actionMode = startSupportActionMode(_actionModeCallbacks);
|
_actionMode = startSupportActionMode(_actionModeCallbacks);
|
||||||
_actionModeBackPressHandler.setEnabled(true);
|
_actionModeBackPressHandler.setEnabled(true);
|
||||||
setFavoriteMenuItemVisiblity();
|
setFavoriteMenuItemVisiblity();
|
||||||
|
setAssignIconsMenuItemVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1142,6 +1177,12 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
mode.finish();
|
mode.finish();
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case R.id.action_assign_icons:
|
||||||
|
startAssignIconsActivity(CODE_ASSIGN_ICONS, _selectedEntries);
|
||||||
|
mode.finish();
|
||||||
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class IconPickerDialog {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BottomSheetDialog create(Activity activity, List<IconPack> iconPacks, String issuer, IconAdapter.Listener listener) {
|
public static BottomSheetDialog create(Activity activity, List<IconPack> iconPacks, String issuer, boolean showAddCustom, IconAdapter.Listener listener) {
|
||||||
View view = LayoutInflater.from(activity).inflate(R.layout.dialog_icon_picker, null);
|
View view = LayoutInflater.from(activity).inflate(R.layout.dialog_icon_picker, null);
|
||||||
TextView textIconPack = view.findViewById(R.id.text_icon_pack);
|
TextView textIconPack = view.findViewById(R.id.text_icon_pack);
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ public class IconPickerDialog {
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
recyclerView.setLayoutManager(layoutManager);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
recyclerView.addOnScrollListener(preloader);
|
recyclerView.addOnScrollListener(preloader);
|
||||||
adapter.loadIcons(iconPacks.get(0));
|
adapter.loadIcons(iconPacks.get(0), showAddCustom);
|
||||||
textIconPack.setText(iconPacks.get(0).getName());
|
textIconPack.setText(iconPacks.get(0).getName());
|
||||||
|
|
||||||
view.findViewById(R.id.btn_icon_pack).setOnClickListener(v -> {
|
view.findViewById(R.id.btn_icon_pack).setOnClickListener(v -> {
|
||||||
|
@ -139,7 +139,7 @@ public class IconPickerDialog {
|
||||||
PopupMenu popupMenu = new PopupMenu(activity, v);
|
PopupMenu popupMenu = new PopupMenu(activity, v);
|
||||||
popupMenu.setOnMenuItemClickListener(item -> {
|
popupMenu.setOnMenuItemClickListener(item -> {
|
||||||
IconPack pack = iconPacks.get(iconPackNames.indexOf(item.getTitle().toString()));
|
IconPack pack = iconPacks.get(iconPackNames.indexOf(item.getTitle().toString()));
|
||||||
adapter.loadIcons(pack);
|
adapter.loadIcons(pack, showAddCustom);
|
||||||
|
|
||||||
String query = iconSearch.getText().toString();
|
String query = iconSearch.getText().toString();
|
||||||
if (!query.isEmpty()) {
|
if (!query.isEmpty()) {
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.beemdevelopment.aegis.ui.models;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.icons.IconPack;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class AssignIconEntry implements Serializable {
|
||||||
|
private final VaultEntry _entry;
|
||||||
|
|
||||||
|
private IconPack.Icon _newIcon;
|
||||||
|
|
||||||
|
private transient AssignIconEntry.Listener _listener;
|
||||||
|
|
||||||
|
public void setOnResetListener(AssignIconEntry.Listener listener) {
|
||||||
|
_listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssignIconEntry(VaultEntry entry) {
|
||||||
|
_entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VaultEntry getEntry() {
|
||||||
|
return _entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconPack.Icon getNewIcon() { return _newIcon; }
|
||||||
|
|
||||||
|
public void setNewIcon(IconPack.Icon icon) {
|
||||||
|
_newIcon = icon;
|
||||||
|
|
||||||
|
if (_listener != null) {
|
||||||
|
_listener.onNewIconChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onNewIconChanged();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.beemdevelopment.aegis.ui.views;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.R;
|
||||||
|
import com.beemdevelopment.aegis.ui.models.AssignIconEntry;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class AssignIconAdapter extends RecyclerView.Adapter<AssignIconHolder> {
|
||||||
|
private AssignIconAdapter.Listener _listener;
|
||||||
|
private ArrayList<AssignIconEntry> _entries;
|
||||||
|
|
||||||
|
public AssignIconAdapter(AssignIconAdapter.Listener listener) {
|
||||||
|
_listener = listener;
|
||||||
|
_entries = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEntries(Collection<AssignIconEntry> entries) {
|
||||||
|
_entries.addAll(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AssignIconHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_assign_icon_entry, parent, false);
|
||||||
|
AssignIconHolder holder = new AssignIconHolder(view);
|
||||||
|
// NOTE: This assumes that the old and new icon views are the same size
|
||||||
|
_listener.onSetPreloadView(holder.getOldIconView());
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(AssignIconHolder holder, int position) {
|
||||||
|
holder.setData(_entries.get(position));
|
||||||
|
holder.itemView.setOnClickListener(view -> {
|
||||||
|
_listener.onAssignIconEntryClick(_entries.get(position));
|
||||||
|
});
|
||||||
|
_entries.get(position).setOnResetListener(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onAssignIconEntryClick(AssignIconEntry entry);
|
||||||
|
void onSetPreloadView(View view);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.beemdevelopment.aegis.ui.views;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.amulyakhare.textdrawable.TextDrawable;
|
||||||
|
import com.beemdevelopment.aegis.R;
|
||||||
|
import com.beemdevelopment.aegis.helpers.TextDrawableHelper;
|
||||||
|
import com.beemdevelopment.aegis.icons.IconType;
|
||||||
|
import com.beemdevelopment.aegis.ui.glide.IconLoader;
|
||||||
|
import com.beemdevelopment.aegis.ui.models.AssignIconEntry;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
|
||||||
|
public class AssignIconHolder extends RecyclerView.ViewHolder implements AssignIconEntry.Listener {
|
||||||
|
private View _view;
|
||||||
|
|
||||||
|
private AssignIconEntry _entry;
|
||||||
|
private TextView _issuer;
|
||||||
|
private TextView _accountName;
|
||||||
|
private ImageView _oldIcon;
|
||||||
|
private ImageView _newIcon;
|
||||||
|
private ImageView _btnReset;
|
||||||
|
|
||||||
|
public AssignIconHolder(final View view) {
|
||||||
|
super(view);
|
||||||
|
|
||||||
|
_view = view.findViewById(R.id.rlCardEntry);
|
||||||
|
|
||||||
|
_issuer = view.findViewById(R.id.tvIssuer);
|
||||||
|
_accountName = view.findViewById(R.id.tvAccountName);
|
||||||
|
_oldIcon = view.findViewById(R.id.ivOldImage);
|
||||||
|
_newIcon = view.findViewById(R.id.ivNewImage);
|
||||||
|
_btnReset = view.findViewById(R.id.btnReset);
|
||||||
|
_btnReset.setOnClickListener(l -> _entry.setNewIcon(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(AssignIconEntry entry) {
|
||||||
|
_entry = entry;
|
||||||
|
_issuer.setText(entry.getEntry().getIssuer());
|
||||||
|
_accountName.setText(entry.getEntry().getName());
|
||||||
|
|
||||||
|
if(!entry.getEntry().hasIcon()) {
|
||||||
|
TextDrawable drawable = TextDrawableHelper.generate(entry.getEntry().getIssuer(), entry.getEntry().getName(), _oldIcon);
|
||||||
|
_oldIcon.setImageDrawable(drawable);
|
||||||
|
} else {
|
||||||
|
Glide.with(_view.getContext())
|
||||||
|
.asDrawable()
|
||||||
|
.load(entry.getEntry())
|
||||||
|
.set(IconLoader.ICON_TYPE, entry.getEntry().getIconType())
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.into(_oldIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
setNewIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setNewIcon() {
|
||||||
|
if (_entry.getNewIcon() != null) {
|
||||||
|
Glide.with(_view.getContext())
|
||||||
|
.asDrawable()
|
||||||
|
.load(_entry.getNewIcon().getFile())
|
||||||
|
.set(IconLoader.ICON_TYPE, _entry.getNewIcon().getIconType())
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.skipMemoryCache(false)
|
||||||
|
.into(_newIcon);
|
||||||
|
} else {
|
||||||
|
Glide.with(_view.getContext())
|
||||||
|
.asDrawable()
|
||||||
|
.load(R.drawable.ic_icon_unselected)
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.skipMemoryCache(false)
|
||||||
|
.into(_newIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
_btnReset.setVisibility(_entry.getNewIcon() != null ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getOldIconView() {
|
||||||
|
return _oldIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNewIconChanged() {
|
||||||
|
setNewIcon();
|
||||||
|
}
|
||||||
|
}
|
|
@ -200,7 +200,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
||||||
IconViewHelper.setLayerType(_profileDrawable, _entry.getIconType());
|
IconViewHelper.setLayerType(_profileDrawable, _entry.getIconType());
|
||||||
Glide.with(fragment)
|
Glide.with(fragment)
|
||||||
.asDrawable()
|
.asDrawable()
|
||||||
.load(_entry)
|
.load(_entry.getIcon())
|
||||||
.set(IconLoader.ICON_TYPE, _entry.getIconType())
|
.set(IconLoader.ICON_TYPE, _entry.getIconType())
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.skipMemoryCache(false)
|
.skipMemoryCache(false)
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class IconAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
/**
|
/**
|
||||||
* Loads all icons from the given icon pack into this adapter. Any icons added before this call will be overwritten.
|
* Loads all icons from the given icon pack into this adapter. Any icons added before this call will be overwritten.
|
||||||
*/
|
*/
|
||||||
public void loadIcons(IconPack pack) {
|
public void loadIcons(IconPack pack, boolean showAddCustom) {
|
||||||
_pack = pack;
|
_pack = pack;
|
||||||
_query = null;
|
_query = null;
|
||||||
_icons = new ArrayList<>(_pack.getIcons());
|
_icons = new ArrayList<>(_pack.getIcons());
|
||||||
|
@ -60,7 +60,11 @@ public class IconAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
List<IconPack.Icon> suggested = pack.getSuggestedIcons(_issuer);
|
List<IconPack.Icon> suggested = pack.getSuggestedIcons(_issuer);
|
||||||
|
|
||||||
|
if (showAddCustom) {
|
||||||
suggested.add(0, new DummyIcon(_context.getString(R.string.icon_custom)));
|
suggested.add(0, new DummyIcon(_context.getString(R.string.icon_custom)));
|
||||||
|
}
|
||||||
|
|
||||||
if (suggested.size() > 0) {
|
if (suggested.size() > 0) {
|
||||||
CategoryHeader category = new CategoryHeader(_context.getString(R.string.suggested));
|
CategoryHeader category = new CategoryHeader(_context.getString(R.string.suggested));
|
||||||
category.setIsCollapsed(false);
|
category.setIsCollapsed(false);
|
||||||
|
@ -90,7 +94,7 @@ public class IconAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
_query = query;
|
_query = query;
|
||||||
|
|
||||||
if (_query == null) {
|
if (_query == null) {
|
||||||
loadIcons(_pack);
|
loadIcons(_pack, false);
|
||||||
} else {
|
} else {
|
||||||
_icons = _pack.getIcons().stream()
|
_icons = _pack.getIcons().stream()
|
||||||
.filter(i -> i.isSuggestedFor(query))
|
.filter(i -> i.isSuggestedFor(query))
|
||||||
|
|
5
app/src/main/res/drawable/baseline_arrow_right_24.xml
Normal file
5
app/src/main/res/drawable/baseline_arrow_right_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="#000000" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M10,17l5,-5 -5,-5v10z"/>
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/ic_icon_unselected.xml
Normal file
5
app/src/main/res/drawable/ic_icon_unselected.xml
Normal file
File diff suppressed because one or more lines are too long
9
app/src/main/res/drawable/ic_reset_image.xml
Normal file
9
app/src/main/res/drawable/ic_reset_image.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M120,360L120,120L200,120L200,254Q250,192 322.5,156Q395,120 480,120Q598,120 690.5,187Q783,254 820,360L733,360Q699,288 632,244Q565,200 480,200Q423,200 372.5,221Q322,242 284,280L360,280L360,360L120,360ZM240,720L720,720L570,520L450,680L360,560L240,720ZM200,880Q167,880 143.5,856.5Q120,833 120,800L120,480L200,480L200,800Q200,800 200,800Q200,800 200,800L760,800Q760,800 760,800Q760,800 760,800L760,480L840,480L840,800Q840,833 816.5,856.5Q793,880 760,880L200,880Z"/>
|
||||||
|
</vector>
|
6
app/src/main/res/drawable/rounded_background.xml
Normal file
6
app/src/main/res/drawable/rounded_background.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="?attr/cardBackground"/>
|
||||||
|
<corners android:radius="4dp"/>
|
||||||
|
<padding android:left="8dp" android:top="8dp" android:right="8dp" android:bottom="8dp"/>
|
||||||
|
</shape>
|
27
app/src/main/res/layout/activity_assign_icons.xml
Normal file
27
app/src/main/res/layout/activity_assign_icons.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/background"
|
||||||
|
tools:context="com.beemdevelopment.aegis.AssignIconsActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/ThemeOverlay.Aegis.AppBar">
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorAppBar" />
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/list_assign_icons"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
98
app/src/main/res/layout/card_assign_icon_entry.xml
Normal file
98
app/src/main/res/layout/card_assign_icon_entry.xml
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/rounded_background"
|
||||||
|
android:elevation="4dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:background="?attr/cardBackground"
|
||||||
|
android:id="@+id/rlCardEntry"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingStart="14dp">
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvIssuer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textColor="?attr/primaryText"
|
||||||
|
android:text="Issuer"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="18sp"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAccountName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textColor="@color/secondary_text"
|
||||||
|
android:text="AccountName"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<!-- Row with 3 columns -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/ivOldImage"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
app:tint="?attr/iconColorPrimary"
|
||||||
|
android:alpha="0.7"
|
||||||
|
android:src="@drawable/baseline_arrow_right_24"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_gravity="center_vertical"/>
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/ivNewImage"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnReset"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:src="@drawable/ic_reset_image"
|
||||||
|
app:tint="?attr/iconColorPrimary"
|
||||||
|
android:paddingStart="15dp"
|
||||||
|
android:paddingEnd="15dp"
|
||||||
|
android:paddingTop="12.5dp"
|
||||||
|
android:paddingBottom="12.5dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
android:layout_gravity="center_vertical"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -22,18 +22,25 @@
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_delete"
|
android:id="@+id/action_assign_icons"
|
||||||
android:title="@string/action_delete"
|
android:title="@string/assign_icons"
|
||||||
android:orderInCategory="100"
|
android:orderInCategory="100"
|
||||||
android:icon="@drawable/ic_delete_white"
|
|
||||||
android:tint="?attr/iconColorPrimary"
|
android:tint="?attr/iconColorPrimary"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_share_qr"
|
android:id="@+id/action_share_qr"
|
||||||
android:title="@string/action_transfer"
|
android:title="@string/action_transfer"
|
||||||
android:orderInCategory="100"
|
android:orderInCategory="110"
|
||||||
android:icon="@drawable/ic_qr_code_full"
|
android:icon="@drawable/ic_qr_code_full"
|
||||||
android:tint="?attr/iconColorPrimary"
|
android:tint="?attr/iconColorPrimary"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_delete"
|
||||||
|
android:title="@string/action_delete"
|
||||||
|
android:orderInCategory="400"
|
||||||
|
android:icon="@drawable/ic_delete_white"
|
||||||
|
android:tint="?attr/iconColorPrimary"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
</menu>
|
</menu>
|
|
@ -171,6 +171,7 @@
|
||||||
<string name="set_up_biometric">Set up biometric unlock</string>
|
<string name="set_up_biometric">Set up biometric unlock</string>
|
||||||
<string name="copy">Copy</string>
|
<string name="copy">Copy</string>
|
||||||
<string name="edit">Edit</string>
|
<string name="edit">Edit</string>
|
||||||
|
<string name="assign_icons">Assign icons</string>
|
||||||
<string name="favorite" comment="Verb">Favorite</string>
|
<string name="favorite" comment="Verb">Favorite</string>
|
||||||
<string name="unfavorite" comment="Verb">Unfavorite</string>
|
<string name="unfavorite" comment="Verb">Unfavorite</string>
|
||||||
<string name="error_all_caps">ERROR</string>
|
<string name="error_all_caps">ERROR</string>
|
||||||
|
@ -205,6 +206,7 @@
|
||||||
<string name="discard_changes">Discard changes?</string>
|
<string name="discard_changes">Discard changes?</string>
|
||||||
<string name="discard_changes_description">Your changes have not been saved</string>
|
<string name="discard_changes_description">Your changes have not been saved</string>
|
||||||
<string name="saving_profile_error">Error saving profile</string>
|
<string name="saving_profile_error">Error saving profile</string>
|
||||||
|
<string name="saving_assign_icons_error">Error assigning icons</string>
|
||||||
<string name="welcome">Welcome</string>
|
<string name="welcome">Welcome</string>
|
||||||
<string name="app_description">Aegis is a free, secure and open source 2FA app</string>
|
<string name="app_description">Aegis is a free, secure and open source 2FA app</string>
|
||||||
<string name="setup_completed">Setup completed</string>
|
<string name="setup_completed">Setup completed</string>
|
||||||
|
@ -461,6 +463,7 @@
|
||||||
<string name="title_activity_scan_qr">Scan a QR code</string>
|
<string name="title_activity_scan_qr">Scan a QR code</string>
|
||||||
<string name="title_activity_manage_slots">Manage key slots</string>
|
<string name="title_activity_manage_slots">Manage key slots</string>
|
||||||
<string name="title_activity_import_entries">Import entries</string>
|
<string name="title_activity_import_entries">Import entries</string>
|
||||||
|
<string name="title_activity_assign_icons">Assign icons</string>
|
||||||
<string name="dialog_wipe_entries_title">Wipe entries</string>
|
<string name="dialog_wipe_entries_title">Wipe entries</string>
|
||||||
<string name="dialog_wipe_entries_message">Your vault already contains entries. Do you want to remove these entries before importing this file?\n\n<b>In doing so, you will permanently lose access to the existing entries in the vault.</b></string>
|
<string name="dialog_wipe_entries_message">Your vault already contains entries. Do you want to remove these entries before importing this file?\n\n<b>In doing so, you will permanently lose access to the existing entries in the vault.</b></string>
|
||||||
<string name="dialog_wipe_entries_checkbox">Wipe vault contents</string>
|
<string name="dialog_wipe_entries_checkbox">Wipe vault contents</string>
|
||||||
|
@ -491,6 +494,8 @@
|
||||||
<string name="importer_help_steam"><b>Steam v3.0 and newer are not supported</b>. Supply a copy of <b>/data/data/com.valvesoftware.android.steam.community/files/Steamguard-*.json</b>, located in the internal storage directory of Steam.</string>
|
<string name="importer_help_steam"><b>Steam v3.0 and newer are not supported</b>. Supply a copy of <b>/data/data/com.valvesoftware.android.steam.community/files/Steamguard-*.json</b>, located in the internal storage directory of Steam.</string>
|
||||||
<string name="importer_help_totp_authenticator">Supply a TOTP Authenticator export file.</string>
|
<string name="importer_help_totp_authenticator">Supply a TOTP Authenticator export file.</string>
|
||||||
<string name="importer_help_winauth">Supply a WinAuth export file.</string>
|
<string name="importer_help_winauth">Supply a WinAuth export file.</string>
|
||||||
|
<string name="import_assign_icons_dialog_title">Assign icons</string>
|
||||||
|
<string name="import_assign_icons_dialog_text">Do you want to assign icons to the imported entries?</string>
|
||||||
|
|
||||||
<string name="importer_encrypted_exception_google_authenticator">Encrypted entry was skipped: %s</string>
|
<string name="importer_encrypted_exception_google_authenticator">Encrypted entry was skipped: %s</string>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue