Merge pull request #173 from michaelschattgen/feature-tapholdswipe

Overhaul entry interaction
This commit is contained in:
Alexander Bakker 2019-08-28 23:27:14 +02:00 committed by GitHub
commit c12c6ab107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 246 additions and 117 deletions

View file

@ -3,8 +3,15 @@ package com.beemdevelopment.aegis.helpers;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.beemdevelopment.aegis.db.DatabaseEntry;
import com.beemdevelopment.aegis.ui.views.EntryAdapter;
import java.util.Map;
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private DatabaseEntry _selectedEntry;
private final ItemTouchHelperAdapter _adapter;
private boolean _positionChanged = false;
private boolean _isLongPressDragEnabled = true;
@ -22,6 +29,10 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
_isLongPressDragEnabled = enabled;
}
public void setSelectedEntry(DatabaseEntry entry) {
_selectedEntry = entry;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
@ -30,7 +41,15 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
int swipeFlags = 0;
int position = viewHolder.getAdapterPosition();
EntryAdapter adapter = (EntryAdapter)recyclerView.getAdapter();
if (adapter.getEntryAt(position) != _selectedEntry)
{
dragFlags = 0;
}
return makeMovementFlags(dragFlags, swipeFlags);
}
@ -56,4 +75,6 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
_positionChanged = false;
}
}
}

View file

@ -0,0 +1,23 @@
package com.beemdevelopment.aegis.helpers;
import android.content.res.Resources;
import android.graphics.Color;
import android.util.TypedValue;
import androidx.annotation.ColorInt;
import com.beemdevelopment.aegis.R;
public class ThemeHelper {
private ThemeHelper() {
}
public static int getThemeColor(int attributeId, Resources.Theme currentTheme) {
TypedValue typedValue = new TypedValue();
currentTheme.resolveAttribute(attributeId, typedValue, true);
@ColorInt int color = typedValue.data;
return color;
}
}

View file

@ -1,6 +1,7 @@
package com.beemdevelopment.aegis.ui;
import android.Manifest;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@ -11,6 +12,7 @@ import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
@ -18,6 +20,10 @@ import android.widget.LinearLayout;
import android.widget.SearchView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ActionMode;
import androidx.core.view.MenuItemCompat;
import com.beemdevelopment.aegis.AegisApplication;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.SortCategory;
@ -71,6 +77,9 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
private String _checkedGroup;
private boolean _searchSubmitted;
private DatabaseEntry _selectedEntry;
private ActionMode _actionMode;
private Menu _menu;
private SearchView _searchView;
private FloatingActionsMenu _fabMenu;
@ -78,6 +87,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
private FabScrollHelper _fabScrollHelper;
private ActionMode.Callback _actionModeCallbacks = new ActionModeCallbacks();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -483,43 +494,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
super.onBackPressed();
}
private BottomSheetDialog createBottomSheet(final DatabaseEntry entry) {
BottomSheetDialog dialog = new BottomSheetDialog(this);
dialog.setContentView(R.layout.bottom_sheet_edit_entry);
dialog.setCancelable(true);
dialog.getWindow().setLayout(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
dialog.show();
dialog.findViewById(R.id.copy_button).setOnClickListener(view -> {
dialog.dismiss();
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text/plain", entry.getInfo().getOtp());
clipboard.setPrimaryClip(clip);
Toast.makeText(this, getString(R.string.code_copied), Toast.LENGTH_SHORT).show();
});
dialog.findViewById(R.id.delete_button).setOnClickListener(view -> {
dialog.dismiss();
Dialogs.showDeleteEntryDialog(this, (d, which) -> {
deleteEntry(entry);
// update the filter list if the group no longer exists
if (entry.getGroup() != null) {
if (!_db.getGroups().contains(entry.getGroup())) {
updateGroupFilterMenu();
}
}
});
});
dialog.findViewById(R.id.edit_button).setOnClickListener(view -> {
dialog.dismiss();
startEditProfileActivity(CODE_EDIT_ENTRY, entry, false);
});
return dialog;
}
private void deleteEntry(DatabaseEntry entry) {
DatabaseEntry oldEntry = _db.removeEntry(entry);
saveDatabase();
@ -682,7 +656,29 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
@Override
public void onEntryClick(DatabaseEntry entry) {
createBottomSheet(entry).show();
if (_selectedEntry != null) {
if (_selectedEntry == entry) {
_actionMode.finish();
}
return;
}
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text/plain", entry.getInfo().getOtp());
clipboard.setPrimaryClip(clip);
Toast.makeText(this, getString(R.string.code_copied), Toast.LENGTH_SHORT).show();
}
@Override
public void onLongEntryClick(DatabaseEntry entry) {
if (_selectedEntry != null) {
return;
}
_selectedEntry = entry;
_entryListView.setActionModeState(true, entry);
_actionMode = this.startSupportActionMode(_actionModeCallbacks);
}
@Override
@ -707,6 +703,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
@Override
public void onLocked() {
if (_actionMode != null) {
_actionMode.finish();
}
_entryListView.clearEntries();
_loaded = false;
@ -716,4 +716,50 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
super.onLocked();
}
private class ActionModeCallbacks implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_action_mode, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
startEditProfileActivity(CODE_EDIT_ENTRY, _selectedEntry, false);
mode.finish();
return true;
case R.id.action_delete:
Dialogs.showDeleteEntryDialog(MainActivity.this, (d, which) -> {
deleteEntry(_selectedEntry);
if (_selectedEntry.getGroup() != null) {
if (!_db.getGroups().contains(_selectedEntry.getGroup())) {
updateGroupFilterMenu();
}
}
mode.finish();
});
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
_entryListView.setActionModeState(false, null);
_selectedEntry = null;
_actionMode = null;
}
}
}

View file

@ -24,6 +24,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
private EntryListView _view;
private List<DatabaseEntry> _entries;
private List<DatabaseEntry> _shownEntries;
private DatabaseEntry _selectedEntry;
private boolean _showAccountName;
private boolean _tapToReveal;
private int _tapToRevealTime;
@ -185,6 +186,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
if (_sortCategory == category) {
return;
}
_sortCategory = category;
if (apply) {
updateShownEntries();
@ -274,6 +276,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
@Override
public void onBindViewHolder(final EntryHolder holder, int position) {
DatabaseEntry entry = _shownEntries.get(position);
holder.setFocused(entry == _selectedEntry);
boolean showProgress = !isPeriodUniform() && entry.getInfo() instanceof TotpInfo;
holder.setData(entry, _showAccountName, showProgress, _tapToReveal);
holder.setTapToRevealTime(_tapToRevealTime);
@ -283,7 +287,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
if (_tapToReveal && holder.isCodeHidden()) {
if (_tapToReveal && holder.isCodeHidden() && _selectedEntry == null) {
holder.revealCode();
} else {
_view.onEntryClick(_shownEntries.get(position));
@ -294,6 +298,11 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
@Override
public boolean onLongClick(View v) {
int position = holder.getAdapterPosition();
if (_selectedEntry == null) {
setSelectedEntry(_shownEntries.get(position));
holder.setFocused(true);
}
return _view.onLongEntryClick(_shownEntries.get(position));
}
});
@ -360,6 +369,18 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
return period;
}
public void setSelectedEntry(DatabaseEntry entry) {
if (entry == null) {
notifyItemChanged(_shownEntries.indexOf(_selectedEntry));
}
_selectedEntry = entry;
}
public boolean isDragAndDropAllowed() {
return _sortCategory == SortCategory.CUSTOM && _groupFilter == null && _searchFilter == null;
}
public boolean isPeriodUniform() {
return getUniformPeriod() != -1;
}

View file

@ -10,6 +10,7 @@ import com.amulyakhare.textdrawable.TextDrawable;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.db.DatabaseEntry;
import com.beemdevelopment.aegis.helpers.TextDrawableHelper;
import com.beemdevelopment.aegis.helpers.ThemeHelper;
import com.beemdevelopment.aegis.helpers.UiRefresher;
import com.beemdevelopment.aegis.otp.HotpInfo;
import com.beemdevelopment.aegis.otp.OtpInfo;
@ -33,6 +34,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
private int _tapToRevealTime;
private PeriodProgressBar _progressBar;
private View _view;
private UiRefresher _refresher;
private Handler _hiddenHandler;
@ -40,6 +42,8 @@ public class EntryHolder extends RecyclerView.ViewHolder {
public EntryHolder(final View view) {
super(view);
_view = view.findViewById(R.id.rlCardEntry);
_profileName = view.findViewById(R.id.profile_account_name);
_profileCode = view.findViewById(R.id.profile_code);
_profileIssuer = view.findViewById(R.id.profile_issuer);
@ -49,6 +53,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
_progressBar = view.findViewById(R.id.progressBar);
int primaryColorId = view.getContext().getResources().getColor(R.color.colorPrimary);
_progressBar.getProgressDrawable().setColorFilter(primaryColorId, PorterDuff.Mode.SRC_IN);
_view.setBackground(_view.getContext().getResources().getDrawable(R.color.card_background));
_refresher = new UiRefresher(new UiRefresher.Listener() {
@Override
@ -135,6 +140,15 @@ public class EntryHolder extends RecyclerView.ViewHolder {
}
}
public void setFocused(boolean focused) {
if (focused) {
_view.setBackgroundColor(ThemeHelper.getThemeColor(R.attr.cardBackgroundFocused, _view.getContext().getTheme()));
} else {
_view.setBackgroundColor(ThemeHelper.getThemeColor(R.attr.cardBackground, _view.getContext().getTheme()));
}
_view.setSelected(focused);
}
public void destroy() {
_refresher.destroy();
}

View file

@ -8,6 +8,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.Toast;
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.SortCategory;
@ -128,6 +129,12 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
}
}
public void setActionModeState(boolean enabled, DatabaseEntry entry) {
_touchCallback.setSelectedEntry(entry);
_touchCallback.setIsLongPressDragEnabled(enabled && _adapter.isDragAndDropAllowed());
_adapter.setSelectedEntry(entry);
}
public void setSortCategory(SortCategory sortCategory, boolean apply) {
_touchCallback.setIsLongPressDragEnabled(sortCategory == SortCategory.CUSTOM);
_adapter.setSortCategory(sortCategory, apply);
@ -164,9 +171,9 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
_listener.onEntryClick(entry);
}
@Override
public boolean onLongEntryClick(DatabaseEntry entry) {
return false;
_listener.onLongEntryClick(entry);
return true;
}
@Override
@ -265,6 +272,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
void onEntryMove(DatabaseEntry entry1, DatabaseEntry entry2);
void onEntryDrop(DatabaseEntry entry);
void onEntryChange(DatabaseEntry entry);
void onLongEntryClick(DatabaseEntry entry);
void onScroll(int dx, int dy);
}

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>

View file

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="?attr/background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:id="@+id/copy_button"
android:clickable="true"
android:focusable="true"
android:background="?attr/background"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_content_copy_black_24dp"
android:tint="?attr/iconColorPrimary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/copy"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/background"
android:id="@+id/edit_button"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_create_black_24dp"
android:tint="?attr/iconColorPrimary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:id="@+id/delete_button"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_delete_black_24dp"
android:tint="?attr/iconColorPrimary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/delete"/>
</LinearLayout>
</LinearLayout>

View file

@ -11,6 +11,7 @@
<LinearLayout
android:orientation="horizontal"
android:background="?attr/cardBackground"
android:id="@+id/rlCardEntry"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_width="match_parent"

View file

@ -11,6 +11,7 @@
<LinearLayout
android:orientation="horizontal"
android:background="?attr/cardBackground"
android:id="@+id/rlCardEntry"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:layout_width="match_parent"

View file

@ -11,6 +11,7 @@
<LinearLayout
android:orientation="horizontal"
android:background="?attr/cardBackground"
android:id="@+id/rlCardEntry"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:layout_width="match_parent"

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_edit"
android:orderInCategory="90"
android:icon="@drawable/ic_mode_edit"
android:title="Edit"
app:showAsAction="always" />
<item
android:id="@+id/action_delete"
android:title="@string/action_delete"
android:orderInCategory="100"
android:icon="@drawable/ic_delete_white"
android:tint="?attr/iconColorPrimary"
app:showAsAction="always"/>
</menu>

View file

@ -4,6 +4,7 @@
<attr name="secondaryText" format="color" />
<attr name="backgroundColor" format="color" />
<attr name="cardBackground" format="color" />
<attr name="cardBackgroundFocused" format="color" />
<attr name="codePrimaryText" format="color" />
<attr name="iconColorPrimary" format="color" />
<attr name="iconColorInverted" format="color" />

View file

@ -16,6 +16,7 @@
<color name="divider">#BDBDBD</color>
<color name="background">#f2f2f2</color>
<color name="card_background">#ffffff</color>
<color name="card_background_focused">#DBDBDB</color>
<color name="colorSwirlPrimary">#434343</color>
<color name="colorSwirlError">#FF5252</color>
@ -31,6 +32,8 @@
<color name="code_primary_text_dark">#ffffff</color>
<color name="card_background_dark">#424242</color>
<color name="card_background_focused_dark">#6B6B6B</color>
<color name="card_background_focused_true_dark">#1B1B1B</color>
<color name="primary_text_dark">#ffffff</color>
<color name="hint_text_dark">#a7a7a7</color>
<color name="secondary_text_dark">#FF5252</color>

View file

@ -6,6 +6,10 @@
<item name="background">@null</item>
</style>
<style name="AppTheme.ActionMode" parent="@style/Widget.AppCompat.ActionMode">
<item name="android:actionModeBackground">@color/colorPrimary</item>
</style>
<style name="Theme.Intro" parent="Theme.AppCompat.NoActionBar">
<item name="swirl_ridgeColor">@color/primary_text_inverted</item>
<item name="swirl_errorColor">@color/colorSwirlError</item>
@ -20,18 +24,44 @@
<item name="primaryText">@color/primary_text</item>
<item name="secondaryText">@color/secondary_text</item>
<item name="cardBackground">@color/card_background</item>
<item name="cardBackgroundFocused">@color/card_background_focused</item>
<item name="codePrimaryText">@color/code_primary_text</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="background">@color/background</item>
<item name="bottomSheetDialogTheme">@style/Theme.Design.Light.BottomSheetDialog</item>
<item name="iconColorPrimary">@color/icon_primary</item>
<item name="iconColorInverted">@color/icon_primary_inverted</item>
<item name="swirl_ridgeColor">@color/colorSwirlPrimary</item>
<item name="swirl_errorColor">@color/colorSwirlError</item>
<item name="actionModeStyle">@style/ActionModeStyle</item>
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
</style>
<style name="ActionModeStyle" parent="@style/Widget.AppCompat.Light.ActionMode.Inverse">
<item name="background">@color/colorPrimary</item>
<item name="titleTextStyle">@style/ActionModeTitleTextStyle</item>
<item name="iconColorPrimary">@color/icon_primary</item>
<item name="iconColorInverted">@color/icon_primary_inverted</item>
</style>
<style name="ActionModeStyle.Dark" parent="@style/Widget.AppCompat.Light.ActionMode.Inverse">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="background">@color/colorPrimary</item>
<item name="titleTextStyle">@style/ActionModeTitleTextStyle</item>
<item name="iconColorPrimary">@color/icon_primary</item>
<item name="iconColorInverted">@color/icon_primary_inverted</item>
</style>
<style name="ActionModeStyle.TrueBlack" parent="@style/Widget.AppCompat.Light.ActionMode.Inverse">
<item name="colorPrimary">@color/background_true_dark</item>
<item name="background">@color/background_true_dark</item>
<item name="titleTextStyle">@style/ActionModeTitleTextStyle</item>
<item name="iconColorPrimary">@color/icon_primary</item>
<item name="iconColorInverted">@color/icon_primary_inverted</item>
</style>
<style name="ActionModeTitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionMode.Title">
<item name="android:textColor">@android:color/white</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
@ -53,27 +83,30 @@
<item name="primaryText">@color/primary_text_dark</item>
<item name="secondaryText">@color/secondary_text_dark</item>
<item name="cardBackground">@color/card_background_dark</item>
<item name="cardBackgroundFocused">@color/card_background_focused_dark</item>
<item name="codePrimaryText">@color/code_primary_text_dark</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="background">@color/background_dark</item>
<item name="bottomSheetDialogTheme">@style/Theme.Design.BottomSheetDialog</item>
<item name="iconColorPrimary">@color/icon_primary_dark</item>
<item name="iconColorInverted">@color/icon_primary_dark_inverted</item>
<item name="swirl_ridgeColor">@color/colorSwirlPrimaryDark</item>
<item name="swirl_errorColor">@color/colorSwirlErrorDark</item>
<item name="actionModeStyle">@style/ActionModeStyle.Dark</item>
</style>
<style name="AppTheme.TrueBlack" parent="AppTheme.Dark">
<item name="colorPrimary">@color/background_true_dark</item>
<item name="cardBackground">@color/background_true_dark</item>
<item name="background">@color/background_true_dark</item>
<item name="bottomSheetDialogTheme">@style/Theme.Design.BottomSheetDialog</item>
<item name="cardBackgroundFocused">@color/card_background_focused_true_dark</item>
<item name="colorPrimaryDark">@color/background_true_dark</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
<item name="actionModeStyle">@style/ActionModeStyle.TrueBlack</item>
</style>
<style name="AppTheme.TrueBlack.Preferences" parent="AppTheme.TrueBlack">