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 1490c6e8..05f9b47e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -24,6 +24,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; +import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.CheckBox; import android.widget.Toast; @@ -42,6 +43,7 @@ import androidx.core.view.WindowInsetsCompat; import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.SortCategory; +import com.beemdevelopment.aegis.helpers.DropdownHelper; import com.beemdevelopment.aegis.helpers.FabScrollHelper; import com.beemdevelopment.aegis.helpers.PermissionHelper; import com.beemdevelopment.aegis.otp.GoogleAuthInfo; @@ -67,6 +69,8 @@ import com.google.android.material.chip.ChipGroup; import com.google.android.material.color.MaterialColors; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; import com.google.common.base.Strings; import java.util.ArrayList; @@ -79,6 +83,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; public class MainActivity extends AegisActivity implements EntryListView.Listener { @@ -489,6 +494,76 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene assignIconsResultLauncher.launch(assignIconIntent); } + private void startAssignGroupsDialog() { + View view = LayoutInflater.from(this).inflate(R.layout.dialog_select_group, null); + TextInputLayout groupSelectionLayout = view.findViewById(R.id.group_selection_layout); + AutoCompleteTextView groupsSelection = view.findViewById(R.id.group_selection_dropdown); + TextInputLayout newGroupLayout = view.findViewById(R.id.text_group_name_layout); + TextInputEditText newGroupText = view.findViewById(R.id.text_group_name); + + Collection groups = _vaultManager.getVault().getUsedGroups(); + List groupModels = new ArrayList<>(); + groupModels.add(new VaultGroupModel(getString(R.string.new_group))); + groupModels.addAll(groups.stream().map(VaultGroupModel::new).collect(Collectors.toList())); + DropdownHelper.fillDropdown(this, groupsSelection, groupModels); + + AtomicReference groupModelRef = new AtomicReference<>(); + groupsSelection.setOnItemClickListener((parent, view1, position, id) -> { + VaultGroupModel groupModel = (VaultGroupModel) parent.getItemAtPosition(position); + groupModelRef.set(groupModel); + + if (groupModel.isPlaceholder()) { + newGroupLayout.setVisibility(View.VISIBLE); + newGroupText.requestFocus(); + } else { + newGroupLayout.setVisibility(View.GONE); + } + + groupSelectionLayout.setError(null); + }); + + AlertDialog dialog = new MaterialAlertDialogBuilder(this) + .setTitle(R.string.assign_groups) + .setView(view) + .setPositiveButton(android.R.string.ok, null) + .setNegativeButton(android.R.string.cancel, null) + .create(); + + dialog.setOnShowListener(d -> { + Button btnPos = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + btnPos.setOnClickListener(v -> { + VaultGroupModel groupModel = groupModelRef.get(); + if (groupModel == null) { + groupSelectionLayout.setError(getString(R.string.error_required_field)); + return; + } + + if (groupModel.isPlaceholder()) { + String newGroupName = newGroupText.getText().toString().trim(); + if (newGroupName.isEmpty()) { + newGroupLayout.setError(getString(R.string.error_required_field)); + return; + } + + VaultGroup group = new VaultGroup(newGroupName); + _vaultManager.getVault().addGroup(group); + groupModel = new VaultGroupModel(group); + } + + for (VaultEntry selectedEntry : _selectedEntries) { + selectedEntry.addGroup(groupModel.getUUID()); + } + + dialog.dismiss(); + saveAndBackupVault(); + _actionMode.finish(); + setGroups(_vaultManager.getVault().getUsedGroups()); + }); + }); + + Dialogs.showSecureDialog(dialog); + } + private void startIntroActivity() { if (!_isDoingIntro) { Intent intro = new Intent(this, IntroActivity.class); @@ -1356,6 +1431,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } else if (itemId == R.id.action_assign_icons) { startAssignIconsActivity(_selectedEntries); mode.finish(); + } else if (itemId == R.id.action_assign_groups) { + startAssignGroupsDialog(); } else { return false; } diff --git a/app/src/main/res/layout/dialog_select_group.xml b/app/src/main/res/layout/dialog_select_group.xml new file mode 100644 index 00000000..4d754634 --- /dev/null +++ b/app/src/main/res/layout/dialog_select_group.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_action_mode.xml b/app/src/main/res/menu/menu_action_mode.xml index e9be8f18..ef65ccde 100644 --- a/app/src/main/res/menu/menu_action_mode.xml +++ b/app/src/main/res/menu/menu_action_mode.xml @@ -33,6 +33,12 @@ android:orderInCategory="100" app:showAsAction="never"/> + + Edit Select all Assign icons + Assign to group + Select a group you wish to assign the selected entries to. + Select group Favorite Unfavorite ERROR @@ -254,6 +257,7 @@ Copied Errors copied to the clipboard Version copied to the clipboard + This field is required An error occurred An error occurred while trying to unlock the vault An error occurred while trying to unlock the vault. Your vault file might be corrupt.