Add menu drawer

This commit is contained in:
MrLetsplay 2023-09-21 21:02:08 +02:00
parent 82cc4760cf
commit 13d06d8905
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
7 changed files with 220 additions and 7 deletions

View File

@ -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

View File

@ -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<String> 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<GroupListItem> 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;
}
}

View File

@ -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();

View File

@ -42,13 +42,16 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
private Runnable saveGroups;
private Runnable updateToolbarOptions;
private boolean editing;
public GroupListAdapter(Context context, RecyclerView recyclerView, Consumer<String> navigateToGroup, Runnable saveGroups) {
public GroupListAdapter(Context context, RecyclerView recyclerView, Consumer<String> 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<GroupListItem> {
}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<GroupListItem> {
holder.setSelected(true);
editing = true;
((BaseActivity) context).invalidateMenu();
updateToolbarOptions.run();
return true;
});
}
@ -131,7 +134,7 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
item.setSelected(false);
}
((BaseActivity) context).invalidateMenu();
updateToolbarOptions.run();
}
public List<GroupListItem> getSelectedGroups() {

View File

@ -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<? extends NamedFragment> fragmentClass, Bundle args) {
navigate((AppCompatActivity) currentFragment.requireActivity(), fragmentClass, args);
}

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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"
tools:context=".fragment.HomeFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingVertical="10dp">
<LinearLayout
android:id="@+id/menu_tools_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal"
android:paddingHorizontal="16dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/baseline_add_24"
android:background="@android:color/transparent"
android:padding="10dp"
android:layout_marginStart="10dp" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/baseline_edit_24"
android:background="@android:color/transparent"
android:padding="10dp"
android:layout_marginStart="10dp" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/baseline_delete_24"
android:background="@android:color/transparent"
android:padding="10dp"
android:layout_marginStart="10dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/menu_items"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/menu_tools_container" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -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" />
<item
android:id="@+id/action_settings"
android:orderInCategory="100"