Skip to content

Add configurable tap action behaviour#1786

Open
michaelschattgen wants to merge 1 commit intobeemdevelopment:masterfrom
michaelschattgen:feature/tap-config
Open

Add configurable tap action behaviour#1786
michaelschattgen wants to merge 1 commit intobeemdevelopment:masterfrom
michaelschattgen:feature/tap-config

Conversation

@michaelschattgen
Copy link
Copy Markdown
Member

image

This PR adds the ability to set the single tap and double tap behaviour respectively. This allows us to branch out to other tap actions like the one mentioned in (but not exclusive to) #1688.

Hopefully this PR fixes issues like the ones described in #1223, #1569, #1064, #1667 and probably many more that I can't find right now.

I also added a preferences migration for people who already have set up their 'Copy to clipboard' to either single tap or double tap.

@michaelschattgen michaelschattgen marked this pull request as draft April 14, 2026 21:16
@michaelschattgen michaelschattgen marked this pull request as ready for review April 14, 2026 21:34
Copy link
Copy Markdown
Member

@alexbakker alexbakker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't taken a close look at the code yet, but I noticed some issues while doing some initial testing:

  • Deselecting the final selected entry no longer closes the action menu
  • Entries can no longer be unhighlighted/unrevealed manually
  • Navigation to the tap actions preferences submenu is not animated
  • Double tapping a hidden entry to copy it, reveals it.
    • Settings: Tap to reveal = true, Highlight when tapped = false, Single tap = none, Double tap = Copy, Reserve first tap for reveal = false
  • There appears to be a delay for single tap actions
  • "Reserve first tap for reveal" also applies to highlighting an entry, but only if you first enable tap to reveal, enable "reserve first tap" and then disable tap to reveal again.

Comment on lines 173 to 464
@@ -200,7 +225,6 @@
if (_searchFilter != null) {
String[] tokens = _searchFilter.toLowerCase().split("\\s+");

// Return true if not all tokens match at least one of the relevant fields
return !Arrays.stream(tokens)
.allMatch(token ->
((_searchBehaviorMask & Preferences.SEARCH_IN_ISSUER) != 0 && issuer.contains(token)) ||
@@ -287,9 +311,6 @@
_entryList = newEntryList;
updatePeriodUniformity();

// This scroll position trick is required in order to not have the recycler view
// jump to some random position after a large change (like resorting entries)
// Related: https://issuetracker.google.com/issues/70149059
int scrollPos = _view.getScrollPosition();
diffRes.dispatchUpdatesTo(this);
_view.scrollToPosition(scrollPos);
@@ -353,8 +374,6 @@

@Override
public void onItemDrop(int position) {
// moving entries is not allowed when a filter is applied
// footer cant be moved, nor can items be moved below it
if (!_groupFilter.isEmpty() || _entryList.isPositionFooter(position) || _entryList.isPositionErrorCard(position)) {
return;
}
@@ -365,22 +384,18 @@

@Override
public void onItemMove(int firstPosition, int secondPosition) {
// Moving entries is not allowed when a filter is applied. The footer can't be
// moved, nor can items be moved below it
if (!_groupFilter.isEmpty()
|| _entryList.isPositionFooter(firstPosition) || _entryList.isPositionFooter(secondPosition)
|| _entryList.isPositionErrorCard(firstPosition) || _entryList.isPositionErrorCard(secondPosition)) {
return;
}

// Notify the vault about the entry position change first
int firstIndex = _entryList.translateEntryPosToIndex(firstPosition);
int secondIndex = _entryList.translateEntryPosToIndex(secondPosition);
VaultEntry firstEntry = _entryList.getShownEntries().get(firstIndex);
VaultEntry secondEntry = _entryList.getShownEntries().get(secondIndex);
_view.onEntryMove(firstEntry, secondEntry);

// Then update the visual end
List<VaultEntry> newEntries = new ArrayList<>(_entryList.getEntries());
CollectionUtils.move(newEntries, newEntries.indexOf(firstEntry), newEntries.indexOf(secondEntry));
replaceEntryList(new EntryList(
@@ -446,7 +461,6 @@
boolean showProgress = entry.getInfo() instanceof TotpInfo && ((TotpInfo) entry.getInfo()).getPeriod() != getMostFrequentPeriod();
boolean showAccountName = true;
if (_onlyShowNecessaryAccountNames) {
// Only show account name when there's multiple entries found with the same issuer.
showAccountName = _entryList.getEntries().stream()
.filter(x -> x.getIssuer().equals(entry.getIssuer()))
.count() > 1;
@@ -464,43 +478,9 @@
entryHolder.itemView.setOnClickListener(new View.OnClickListener() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these comments removed?

Comment on lines 914 to 952
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these comments removed?

Comment on lines 307 to 594
@@ -396,7 +398,7 @@
<string name="pref_groups_multiselect_summary">Allow the selection of multiple groups at the same time</string>
<string name="pref_minimize_on_copy_title">Minimize on copy</string>
<string name="pref_minimize_on_copy_summary">Minimize the app after copying a token</string>
<string name="pref_copy_behavior_title">Copy tokens to the clipboard</string>
<string name="pref_copy_behavior_title" tools:ignore="UnusedResources">Copy tokens to the clipboard</string>
<string name="pref_search_behavior_title">Search behavior</string>
<string name="pref_pause_entry_title">Freeze tokens when tapped</string>
<string name="pref_pause_entry_summary">Pause automatic refresh of tokens by tapping them. Tokens will not update as long as they are focused. Requires \"Highlight tokens when tapped\" or \"Tap to reveal\".</string>
@@ -539,10 +541,6 @@
<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="import_from_clipboard_title">Import from clipboard</string>

<string name="import_from_clipboard_message">We found a valid otpauth uri on your clipboard.\n\n<b>Name</b>: %1$s\n<b>Issuer</b>: %2$s\n\nDo you want to use it to prefill this entry?</string>

<string name="panic_trigger_ignore_toast">Aegis received panic trigger but setting is disabled, ignoring</string>
<string name="pref_panic_trigger_title">Delete vault on panic trigger</string>
<string name="pref_panic_trigger_summary">Delete vault when a panic trigger is received from Ripple</string>
@@ -590,9 +588,9 @@
<string name="pref_grouping_size_three">Groups of 3</string>
<string name="pref_grouping_size_four">Groups of 4</string>

<string name="pref_copy_behavior_never">Never</string>
<string name="pref_copy_behavior_single_tap">Single tap</string>
<string name="pref_copy_behavior_double_tap">Double tap</string>
<string name="pref_copy_behavior_never" tools:ignore="UnusedResources">Never</string>
<string name="pref_copy_behavior_single_tap" tools:ignore="UnusedResources">Single tap</string>
<string name="pref_copy_behavior_double_tap" tools:ignore="UnusedResources">Double tap</string>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove strings that are no longer used.

Comment on lines +25 to +30
<Preference
android:key="pref_tap_actions_hint"
android:title="@string/pref_tap_actions_hint_title"
android:summary="@string/pref_tap_actions_hint_summary"
android:selectable="false"
app:iconSpaceReserved="false" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks a little bit too much like an actual preference you can tap. I'd suggest making this look the same as the D2D hint we have at the bottom of the Backups preference screen.

Comment on lines 914 to 952
public int getItemCount() {
// Always at least one item because of the footer
// Two in case there's also an error card
int baseCount = 1;
if (isErrorCardShown()) {
baseCount++;
}

return baseCount + getShownEntries().size();
}

@Nullable
public ErrorCardInfo getErrorCardInfo() {
return _errorCardInfo;
}

public boolean isErrorCardShown() {
return _errorCardInfo != null;
}

public boolean isPositionErrorCard(int position) {
return isErrorCardShown() && position == 0;
}

public boolean isPositionFooter(int position) {
return position == (getItemCount() - 1);
}

/**
* Translates the given entry position in the recycler view, to its index in the shown entries list.
*/
public int translateEntryPosToIndex(int position) {
if (position == NO_POSITION) {
return NO_POSITION;
}

if (isErrorCardShown()) {
position -= 1;
}

return position;
}

/**
* Translates the given entry index in the shown entries list, to its position in the recycler view.
*/
public int translateEntryIndexToPos(int index) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these comments removed?

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/pref_tap_actions_title">
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This title does not appear to get applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants