From 13d06d8905b52396eeaee7ec21c1724004bceb44 Mon Sep 17 00:00:00 2001 From: MrLetsplay Date: Thu, 21 Sep 2023 21:02:08 +0200 Subject: [PATCH] Add menu drawer --- .../cringe_authenticator/MainActivity.java | 6 +- .../fragment/MenuDrawerFragment.java | 134 ++++++++++++++++++ .../fragment/MenuFragment.java | 2 +- .../grouplist/GroupListAdapter.java | 11 +- .../util/NavigationUtil.java | 9 ++ .../main/res/layout/fragment_menu_drawer.xml | 63 ++++++++ app/src/main/res/menu/menu_otps.xml | 2 +- 7 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuDrawerFragment.java create mode 100644 app/src/main/res/layout/fragment_menu_drawer.xml diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java index b14e80b..70f6315 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java @@ -27,6 +27,7 @@ import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeChoice import com.cringe_studios.cringe_authenticator.fragment.AboutFragment; import com.cringe_studios.cringe_authenticator.fragment.GroupFragment; import com.cringe_studios.cringe_authenticator.fragment.HomeFragment; +import com.cringe_studios.cringe_authenticator.fragment.MenuDrawerFragment; import com.cringe_studios.cringe_authenticator.fragment.MenuFragment; import com.cringe_studios.cringe_authenticator.fragment.NamedFragment; import com.cringe_studios.cringe_authenticator.fragment.SettingsFragment; @@ -143,7 +144,8 @@ public class MainActivity extends BaseActivity { setSupportActionBar(binding.toolbar); - binding.fabMenu.setOnClickListener(view -> NavigationUtil.navigate(this, MenuFragment.class, null)); + //binding.fabMenu.setOnClickListener(view -> NavigationUtil.navigate(this, MenuFragment.class, null)); TODO: remove old menu + binding.fabMenu.setOnClickListener(view -> NavigationUtil.openMenu(this, null)); binding.fabScan.setOnClickListener(view -> scanCode()); binding.fabScanImage.setOnClickListener(view -> scanCodeFromImage()); binding.fabInput.setOnClickListener(view -> inputCode()); @@ -155,6 +157,8 @@ public class MainActivity extends BaseActivity { }else { NavigationUtil.navigate(this, HomeFragment.class, null); } + + new MenuDrawerFragment().show(getSupportFragmentManager(), null); } @Override diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuDrawerFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuDrawerFragment.java new file mode 100644 index 0000000..7a2f81e --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuDrawerFragment.java @@ -0,0 +1,134 @@ +package com.cringe_studios.cringe_authenticator.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.cringe_studios.cringe_authenticator.R; +import com.cringe_studios.cringe_authenticator.databinding.FragmentMenuDrawerBinding; +import com.cringe_studios.cringe_authenticator.grouplist.GroupListAdapter; +import com.cringe_studios.cringe_authenticator.grouplist.GroupListItem; +import com.cringe_studios.cringe_authenticator.util.DialogUtil; +import com.cringe_studios.cringe_authenticator.util.FabUtil; +import com.cringe_studios.cringe_authenticator.util.NavigationUtil; +import com.cringe_studios.cringe_authenticator.util.SettingsUtil; +import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + +import java.util.List; +import java.util.UUID; + +public class MenuDrawerFragment extends BottomSheetDialogFragment { + + private FragmentMenuDrawerBinding binding; + + private GroupListAdapter groupListAdapter; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentMenuDrawerBinding.inflate(inflater); + + groupListAdapter = new GroupListAdapter(requireContext(), binding.menuItems, group -> { + Bundle bundle = new Bundle(); + bundle.putString(GroupFragment.BUNDLE_GROUP, group); + NavigationUtil.navigate(this, GroupFragment.class, bundle); + getParentFragmentManager().beginTransaction().remove(this).commit(); + }, () -> SettingsUtil.setGroups(requireContext(), groupListAdapter.getItems()), this::updateToolbarOptions); + binding.menuItems.setAdapter(groupListAdapter); + + binding.menuAdd.setOnClickListener(view -> this.addGroup()); + binding.menuEdit.setOnClickListener(view -> this.editGroup()); + binding.menuDelete.setOnClickListener(view -> this.removeSelectedGroups()); + + loadGroups(); + updateToolbarOptions(); + + return binding.getRoot(); + } + + private void updateToolbarOptions() { + binding.menuEdit.setVisibility(isEditing() && !hasSelectedMultipleItems() ? View.VISIBLE : View.GONE); + binding.menuDelete.setVisibility(isEditing() ? View.VISIBLE : View.GONE); + } + + private void loadGroups() { + List items = SettingsUtil.getGroups(requireContext()); + + for(String item : items) { + groupListAdapter.add(item); + } + } + + public void addGroup() { + DialogUtil.showCreateGroupDialog(getLayoutInflater(), null, groupName -> { + String id = UUID.randomUUID().toString(); + SettingsUtil.addGroup(requireContext(), id, groupName); + groupListAdapter.add(id); + }, null); + } + + public void editGroup() { + if(!groupListAdapter.isEditing()) return; + + List items = groupListAdapter.getSelectedGroups(); + if(items.size() != 1) return; + + String group = items.get(0).getGroupId(); + + DialogUtil.showCreateGroupDialog(getLayoutInflater(), SettingsUtil.getGroupName(requireContext(), group), newName -> { // TODO: edit group dialog (with "Edit Group" title) + renameGroup(group, newName); + groupListAdapter.finishEditing(); + }, null); + } + + public void removeSelectedGroups() { + if(!groupListAdapter.isEditing()) return; + + new StyledDialogBuilder(requireContext()) + .setTitle(R.string.group_delete_title) + .setMessage(R.string.group_delete_message) + .setPositiveButton(R.string.yes, (d, w) -> { + for(GroupListItem item : groupListAdapter.getSelectedGroups()) { + removeGroup(item.getGroupId()); + } + + groupListAdapter.finishEditing(); + }) + .setNegativeButton(R.string.no, (d, w) -> {}) + .show(); + } + + public void removeGroup(String group) { + SettingsUtil.removeGroup(requireContext(), group); + groupListAdapter.remove(group); + } + + public void renameGroup(String group, String newName) { + SettingsUtil.setGroupName(requireContext(), group, newName); + groupListAdapter.update(group); + } + + public boolean isEditing() { + return groupListAdapter.isEditing(); + } + + public void finishEditing() { + groupListAdapter.finishEditing(); + } + + public boolean hasSelectedMultipleItems() { + return groupListAdapter.getSelectedGroups().size() > 1; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + this.binding = null; + } + +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java index cba533f..ff358f6 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java @@ -44,7 +44,7 @@ public class MenuFragment extends NamedFragment { Bundle bundle = new Bundle(); bundle.putString(GroupFragment.BUNDLE_GROUP, group); NavigationUtil.navigate(this, GroupFragment.class, bundle); - }, () -> SettingsUtil.setGroups(requireContext(), groupListAdapter.getItems())); + }, () -> SettingsUtil.setGroups(requireContext(), groupListAdapter.getItems()), requireActivity()::invalidateMenu); binding.menuItems.setAdapter(groupListAdapter); loadGroups(); diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java index c22f84a..139ff10 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java @@ -42,13 +42,16 @@ public class GroupListAdapter extends RecyclerView.Adapter { private Runnable saveGroups; + private Runnable updateToolbarOptions; + private boolean editing; - public GroupListAdapter(Context context, RecyclerView recyclerView, Consumer navigateToGroup, Runnable saveGroups) { + public GroupListAdapter(Context context, RecyclerView recyclerView, Consumer navigateToGroup, Runnable saveGroups, Runnable updateToolbarOptions) { this.context = context; this.recyclerView = recyclerView; this.navigateToGroup = navigateToGroup; this.saveGroups = saveGroups; + this.updateToolbarOptions = updateToolbarOptions; this.inflater = LayoutInflater.from(context); this.items = new ArrayList<>(); this.handler = new Handler(Looper.getMainLooper()); @@ -78,7 +81,7 @@ public class GroupListAdapter extends RecyclerView.Adapter { }else { holder.setSelected(!holder.isSelected()); if(getSelectedGroups().isEmpty()) editing = false; - ((BaseActivity) context).invalidateMenu(); + updateToolbarOptions.run(); } }); @@ -87,7 +90,7 @@ public class GroupListAdapter extends RecyclerView.Adapter { holder.setSelected(true); editing = true; - ((BaseActivity) context).invalidateMenu(); + updateToolbarOptions.run(); return true; }); } @@ -131,7 +134,7 @@ public class GroupListAdapter extends RecyclerView.Adapter { item.setSelected(false); } - ((BaseActivity) context).invalidateMenu(); + updateToolbarOptions.run(); } public List getSelectedGroups() { diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java index 6a5b877..03ced84 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java @@ -6,8 +6,10 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; import com.cringe_studios.cringe_authenticator.R; +import com.cringe_studios.cringe_authenticator.fragment.MenuDrawerFragment; import com.cringe_studios.cringe_authenticator.fragment.NamedFragment; public class NavigationUtil { @@ -25,6 +27,13 @@ public class NavigationUtil { }); } + public static void openMenu(AppCompatActivity activity, Bundle args) { + FragmentManager manager = activity.getSupportFragmentManager(); + MenuDrawerFragment fragment = instantiateFragment(manager, MenuDrawerFragment.class, args); + + fragment.show(manager, null); + } + public static void navigate(Fragment currentFragment, Class fragmentClass, Bundle args) { navigate((AppCompatActivity) currentFragment.requireActivity(), fragmentClass, args); } diff --git a/app/src/main/res/layout/fragment_menu_drawer.xml b/app/src/main/res/layout/fragment_menu_drawer.xml new file mode 100644 index 0000000..d18476d --- /dev/null +++ b/app/src/main/res/layout/fragment_menu_drawer.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_otps.xml b/app/src/main/res/menu/menu_otps.xml index e2d898f..3fa989d 100644 --- a/app/src/main/res/menu/menu_otps.xml +++ b/app/src/main/res/menu/menu_otps.xml @@ -7,7 +7,7 @@ android:icon="@drawable/baseline_add_24" android:title="@string/action_new_group" android:onClick="addOTP" - app:showAsAction="always" /> + app:showAsAction="ifRoom" />