Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions app/src/main/java/com/beemdevelopment/aegis/helpers/FabMenuHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package com.beemdevelopment.aegis.helpers;

import android.animation.ValueAnimator;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.Map;
import java.util.SequencedMap;
import java.util.SequencedSet;
import java.util.function.Consumer;

public class FabMenuHelper {
private final static long ANIMATION_DURATION = 300L;
private final static long ANIMATION_ACTION_DELAY = 50L;
private final View _scrim;
private final View _menuItemsContainer;
private final FloatingActionButton _mainFab;
private final SequencedSet<View> _actions;
private Consumer<Boolean> _stateListener;
private boolean _isOpen = false;

public FabMenuHelper(
View scrim,
ViewGroup menuItemsContainer,
FloatingActionButton fab,
SequencedMap<View, Runnable> actions
) {
_scrim = scrim;
_menuItemsContainer = menuItemsContainer;
_mainFab = fab;
_actions = actions.sequencedKeySet();

for (View action : _actions) {
action.setVisibility(View.GONE);
action.setAlpha(0f);
action.setScaleX(0f);
action.setScaleY(0f);
}

setupClickListeners(actions);
}

public void setOnFabMenuStateChangeListener(Consumer<Boolean> listener) {
_stateListener = listener;
}

private void setupClickListeners(Map<View, Runnable> actions) {
_mainFab.setOnClickListener(v -> toggle());
_scrim.setOnClickListener(v -> close());

actions.forEach((action, onClick) -> {
action.setOnClickListener(v -> {
if (onClick != null) {
onClick.run();
}
close();
});
});
}

public void toggle() {
if (_isOpen) {
close();
} else {
open();
}
}

public void open() {
if (_isOpen) {
return;
}

_isOpen = true;

_scrim.animate()
.alpha(0.5f)
.setDuration(ANIMATION_DURATION)
.withStartAction(() -> _scrim.setVisibility(View.VISIBLE))
.start();

_menuItemsContainer.setVisibility(View.VISIBLE);

long delay = 0L;
for (View action : _actions.reversed()) {
animateActionIn(action, delay);
delay += ANIMATION_ACTION_DELAY;
}

animateFabIconForward(_mainFab);

if (_stateListener != null) {
_stateListener.accept(true);
}
}

public void close() {
if (!_isOpen) {
return;
}

_isOpen = false;

_scrim.animate()
.alpha(0f)
.setDuration(ANIMATION_DURATION)
.withEndAction(() -> _scrim.setVisibility(View.GONE))
.start();

long delay = 0L;
for (View action : _actions) {
animateActionOut(action, delay);
delay += ANIMATION_ACTION_DELAY;
}

animateFabIconBackward(_mainFab);

_mainFab.postDelayed(() -> {
if (!_isOpen) {
_menuItemsContainer.setVisibility(View.GONE);
}
}, ANIMATION_DURATION);

if (_stateListener != null) {
_stateListener.accept(false);
}
}

private void animateFabIconForward(FloatingActionButton fab) {
animateFabIcon(fab, 0f, 45f);
}

private void animateFabIconBackward(FloatingActionButton fab) {
animateFabIcon(fab, 45f, 0f);
}

private void animateFabIcon(FloatingActionButton fab, float from, float to) {
Drawable drawable = _mainFab.getDrawable();
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
fab.setScaleType(ImageView.ScaleType.MATRIX);
Matrix matrix = new Matrix();
ValueAnimator anim = ValueAnimator.ofFloat(from, to);
anim.setDuration(100L);

anim.addUpdateListener(valueAnimator -> {
Float angle = (Float) valueAnimator.getAnimatedValue();
matrix.reset();
matrix.postRotate(angle, width / 2f, height / 2f);
fab.setImageMatrix(matrix);
});

anim.start();
}

private void animateActionIn(View action, long delay) {
action.animate()
.alpha(1f)
.scaleX(1f)
.scaleY(1f)
.setDuration(ANIMATION_DURATION)
.setStartDelay(delay)
.withStartAction(() -> action.setVisibility(View.VISIBLE))
.start();
}

private void animateActionOut(View action, long delay) {
action.animate()
.alpha(0f)
.scaleX(0f)
.scaleY(0f)
.setDuration(ANIMATION_DURATION)
.setStartDelay(delay)
.withEndAction(() -> action.setVisibility(View.GONE))
.start();
}

public boolean isOpen() {
return _isOpen;
}
}
68 changes: 47 additions & 21 deletions app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
Expand All @@ -46,6 +47,7 @@
import com.beemdevelopment.aegis.SortCategory;
import com.beemdevelopment.aegis.helpers.BitmapHelper;
import com.beemdevelopment.aegis.helpers.DropdownHelper;
import com.beemdevelopment.aegis.helpers.FabMenuHelper;
import com.beemdevelopment.aegis.helpers.FabScrollHelper;
import com.beemdevelopment.aegis.helpers.PermissionHelper;
import com.beemdevelopment.aegis.helpers.ViewHelper;
Expand All @@ -69,7 +71,6 @@
import com.beemdevelopment.aegis.vault.VaultGroup;
import com.beemdevelopment.aegis.vault.VaultRepository;
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.color.MaterialColors;
Expand All @@ -84,9 +85,11 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SequencedMap;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -117,13 +120,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
private Set<UUID> _prefGroupFilter;

private FabScrollHelper _fabScrollHelper;
private FabMenuHelper _fabMenuHelper;

private ActionMode _actionMode;
private ActionMode.Callback _actionModeCallbacks = new ActionModeCallbacks();

private LockBackPressHandler _lockBackPressHandler;
private SearchViewBackPressHandler _searchViewBackPressHandler;
private ActionModeBackPressHandler _actionModeBackPressHandler;
private FabMenuBackPressHandler _fabMenuBackPressHandler;

private final ActivityResultLauncher<Intent> authResultLauncher =
registerForActivityResult(new StartActivityForResult(), activityResult -> {
Expand Down Expand Up @@ -207,6 +212,8 @@ protected void onCreate(Bundle savedInstanceState) {
getOnBackPressedDispatcher().addCallback(this, _searchViewBackPressHandler);
_actionModeBackPressHandler = new ActionModeBackPressHandler();
getOnBackPressedDispatcher().addCallback(this, _actionModeBackPressHandler);
_fabMenuBackPressHandler = new FabMenuBackPressHandler();
getOnBackPressedDispatcher().addCallback(this, _fabMenuBackPressHandler);

_entryListView = (EntryListView) getSupportFragmentManager().findFragmentById(R.id.key_profiles);
_entryListView.setListener(this);
Expand All @@ -226,27 +233,30 @@ protected void onCreate(Bundle savedInstanceState) {
_entryListView.setSearchBehaviorMask(_prefs.getSearchBehaviorMask());
_prefGroupFilter = _prefs.getGroupFilter();

View scrimOverlayLayout = LayoutInflater.from(this).inflate(R.layout.scrim_layout, null);
View scrimOverlay = scrimOverlayLayout.findViewById(R.id.scrim);
addContentView(scrimOverlayLayout, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));

View fabMenuLayout = LayoutInflater.from(this).inflate(R.layout.fab_menu, null);
addContentView(fabMenuLayout, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));

ViewGroup menuItemsContainer = findViewById(R.id.fab_menu_items_container);

FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(v -> {
View view = getLayoutInflater().inflate(R.layout.dialog_add_entry, null);
BottomSheetDialog dialog = new BottomSheetDialog(this);
dialog.setContentView(view);

view.findViewById(R.id.fab_enter).setOnClickListener(v1 -> {
dialog.dismiss();
startEditEntryActivityForManual();
});
view.findViewById(R.id.fab_scan_image).setOnClickListener(v2 -> {
dialog.dismiss();
startScanImageActivity();
});
view.findViewById(R.id.fab_scan).setOnClickListener(v3 -> {
dialog.dismiss();
startScanActivity();
});

Dialogs.showSecureDialog(dialog);
});

SequencedMap<View, Runnable> actions = new LinkedHashMap<>();
actions.put(findViewById(R.id.fab_menu_item_scan), this::startScanActivity);
actions.put(findViewById(R.id.fab_menu_item_scan_image), this::startScanImageActivity);
actions.put(findViewById(R.id.fab_menu_item_enter), this::startEditEntryActivityForManual);

_fabMenuHelper = new FabMenuHelper(scrimOverlay, menuItemsContainer, fab, actions);
_fabMenuHelper.setOnFabMenuStateChangeListener(_fabMenuBackPressHandler::setEnabled);

_groupChip = findViewById(R.id.groupChipGroup);
_fabScrollHelper = new FabScrollHelper(fab);
Expand Down Expand Up @@ -1314,6 +1324,9 @@ public void onLocked(boolean userInitiated) {
if (_searchView != null && !_searchView.isIconified()) {
collapseSearchView();
}
if (_fabMenuHelper != null && _fabMenuHelper.isOpen()) {
_fabMenuHelper.close();
}

_entryListView.clearEntries();
_loaded = false;
Expand Down Expand Up @@ -1399,6 +1412,19 @@ public void handleOnBackPressed() {
}
}

private class FabMenuBackPressHandler extends OnBackPressedCallback {
public FabMenuBackPressHandler() {
super(false);
}

@Override
public void handleOnBackPressed() {
if (_fabMenuHelper != null && _fabMenuHelper.isOpen()) {
_fabMenuHelper.close();
}
}
}

private class ActionModeCallbacks implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
Expand Down
8 changes: 0 additions & 8 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,4 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_outline_add_24" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Loading