mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-24 07:46:07 +00:00
Material 3
Co-authored-by: Michael Schättgen <michael@schattgen.me>
This commit is contained in:
parent
f7bac4331e
commit
fcde086ae3
205 changed files with 1935 additions and 1723 deletions
|
@ -139,7 +139,6 @@ dependencies {
|
|||
implementation "androidx.camera:camera-camera2:$cameraxVersion"
|
||||
implementation "androidx.camera:camera-lifecycle:$cameraxVersion"
|
||||
implementation "androidx.camera:camera-view:$cameraxVersion"
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation "androidx.core:core:1.12.0"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
|
@ -162,8 +161,6 @@ dependencies {
|
|||
implementation 'com.google.android.material:material:1.11.0'
|
||||
implementation 'com.google.protobuf:protobuf-javalite:3.25.1'
|
||||
implementation 'com.google.zxing:core:3.5.2'
|
||||
implementation "com.mikepenz:iconics-core:3.2.5"
|
||||
implementation 'com.mikepenz:material-design-iconic-typeface:2.2.0.5@aar'
|
||||
implementation 'com.nulab-inc:zxcvbn:1.8.2'
|
||||
implementation 'de.hdodenhof:circleimageview:3.1.0'
|
||||
implementation 'de.psdev.licensesdialog:licensesdialog:2.2.0'
|
||||
|
|
|
@ -2,15 +2,19 @@ package com.beemdevelopment.aegis;
|
|||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.espresso.matcher.BoundedMatcher;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
|
||||
import com.beemdevelopment.aegis.crypto.CryptoUtils;
|
||||
import com.beemdevelopment.aegis.crypto.SCryptParameters;
|
||||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
||||
import com.beemdevelopment.aegis.ui.views.EntryHolder;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
||||
import com.beemdevelopment.aegis.vault.VaultManager;
|
||||
|
@ -20,6 +24,7 @@ import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
|||
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.vectors.VaultEntries;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
@ -178,4 +183,21 @@ public abstract class AegisTest {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected static Matcher<RecyclerView.ViewHolder> withOtpType(Class<? extends OtpInfo> otpClass) {
|
||||
return new BoundedMatcher<RecyclerView.ViewHolder, EntryHolder>(EntryHolder.class) {
|
||||
@Override
|
||||
public boolean matchesSafely(EntryHolder holder) {
|
||||
return holder != null
|
||||
&& holder.getEntry() != null
|
||||
&& holder.getEntry().getInfo().getClass().equals(otpClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText(String.format("with otp type '%s'", otpClass.getSimpleName()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.beemdevelopment.aegis;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
|
||||
import static androidx.test.espresso.Espresso.openContextualActionModeOverflowMenu;
|
||||
import static androidx.test.espresso.action.ViewActions.clearText;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
|
@ -18,19 +17,17 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
|||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.test.espresso.ViewInteraction;
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions;
|
||||
import androidx.test.espresso.matcher.RootMatchers;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.beemdevelopment.aegis.encoding.Base32;
|
||||
import com.beemdevelopment.aegis.encoding.Hex;
|
||||
|
@ -41,6 +38,7 @@ import com.beemdevelopment.aegis.otp.TotpInfo;
|
|||
import com.beemdevelopment.aegis.otp.YandexInfo;
|
||||
import com.beemdevelopment.aegis.rules.ScreenshotTestRule;
|
||||
import com.beemdevelopment.aegis.ui.MainActivity;
|
||||
import com.beemdevelopment.aegis.ui.views.EntryAdapter;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.beemdevelopment.aegis.vault.VaultRepository;
|
||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||
|
@ -55,6 +53,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import dagger.hilt.android.testing.HiltAndroidTest;
|
||||
|
||||
|
@ -104,13 +103,19 @@ public class OverallTest extends AegisTest {
|
|||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(1, clickChildViewWithId(R.id.buttonRefresh)));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnHolderItem(withOtpType(HotpInfo.class), clickChildViewWithId(R.id.buttonRefresh)));
|
||||
}
|
||||
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(0, longClick()));
|
||||
AtomicBoolean isErrorCardShown = new AtomicBoolean(false);
|
||||
_activityRule.getScenario().onActivity(activity -> {
|
||||
isErrorCardShown.set(((EntryAdapter)((RecyclerView) activity.findViewById(R.id.rvKeyProfiles)).getAdapter()).isErrorCardShown());
|
||||
});
|
||||
|
||||
int entryPosOffset = isErrorCardShown.get() ? 1 : 0;
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 0, longClick()));
|
||||
onView(withId(R.id.action_copy)).perform(click());
|
||||
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(1, longClick()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 1, longClick()));
|
||||
onView(withId(R.id.action_edit)).perform(click());
|
||||
onView(withId(R.id.text_name)).perform(clearText(), typeText("Bob"), closeSoftKeyboard());
|
||||
onView(withId(R.id.dropdown_group)).perform(click());
|
||||
|
@ -129,13 +134,13 @@ public class OverallTest extends AegisTest {
|
|||
changeGroupFilter(_groupName);
|
||||
changeGroupFilter(null);
|
||||
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(2, longClick()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(3, click()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(4, click()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 2, longClick()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 3, click()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 4, click()));
|
||||
onView(withId(R.id.action_share_qr)).perform(click());
|
||||
onView(withId(R.id.btnNext)).perform(click()).perform(click()).perform(click());
|
||||
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(0, longClick()));
|
||||
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 0, longClick()));
|
||||
onView(allOf(isDescendantOfA(withClassName(containsString("ActionBarContextView"))), withClassName(containsString("OverflowMenuButton")))).perform(click());
|
||||
onView(withText(R.string.action_delete)).perform(click());
|
||||
onView(withId(android.R.id.button1)).perform(click());
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
android:icon="@mipmap/${iconName}"
|
||||
android:label="Aegis"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Aegis.Launch"
|
||||
tools:replace="android:theme"
|
||||
tools:targetApi="tiramisu">
|
||||
<activity android:name=".ui.TransferEntriesActivity"
|
||||
android:label="@string/title_activity_transfer" />
|
||||
|
|
|
@ -22,8 +22,6 @@ import com.beemdevelopment.aegis.receivers.VaultLockReceiver;
|
|||
import com.beemdevelopment.aegis.ui.MainActivity;
|
||||
import com.beemdevelopment.aegis.util.IOUtils;
|
||||
import com.beemdevelopment.aegis.vault.VaultManager;
|
||||
import com.mikepenz.iconics.Iconics;
|
||||
import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -48,9 +46,6 @@ public abstract class AegisApplicationBase extends Application {
|
|||
super.onCreate();
|
||||
_vaultManager = EarlyEntryPoints.get(this, EntryPoint.class).getVaultManager();
|
||||
|
||||
Iconics.init(this);
|
||||
Iconics.registerFont(new MaterialDesignIconic());
|
||||
|
||||
VaultLockReceiver lockReceiver = new VaultLockReceiver();
|
||||
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
|
||||
ContextCompat.registerReceiver(this, lockReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
|
|
|
@ -145,6 +145,10 @@ public class Preferences {
|
|||
return CodeGrouping.valueOf(value);
|
||||
}
|
||||
|
||||
public void setCodeGroupSize(CodeGrouping codeGroupSize) {
|
||||
_prefs.edit().putString("pref_code_group_size_string", codeGroupSize.name()).apply();
|
||||
}
|
||||
|
||||
public boolean isIntroDone() {
|
||||
return _prefs.getBoolean("pref_intro", false);
|
||||
}
|
||||
|
@ -198,6 +202,10 @@ public class Preferences {
|
|||
_prefs.edit().putInt("pref_current_theme", theme.ordinal()).apply();
|
||||
}
|
||||
|
||||
public boolean isDynamicColorsEnabled() {
|
||||
return _prefs.getBoolean("pref_dynamic_colors", false);
|
||||
}
|
||||
|
||||
public ViewMode getCurrentViewMode() {
|
||||
return ViewMode.fromInteger(_prefs.getInt("pref_current_view_mode", 0));
|
||||
}
|
||||
|
@ -266,8 +274,16 @@ public class Preferences {
|
|||
return _prefs.getInt("pref_timeout", -1);
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return _prefs.getString("pref_lang", "system");
|
||||
}
|
||||
|
||||
public void setLanguage(String lang) {
|
||||
_prefs.edit().putString("pref_lang", lang).apply();
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
String lang = _prefs.getString("pref_lang", "system");
|
||||
String lang = getLanguage();
|
||||
|
||||
if (lang.equals("system")) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
|
|
|
@ -10,20 +10,14 @@ public class ThemeMap {
|
|||
}
|
||||
|
||||
public static final Map<Theme, Integer> DEFAULT = ImmutableMap.of(
|
||||
Theme.LIGHT, R.style.Theme_Aegis_Light_Default,
|
||||
Theme.DARK, R.style.Theme_Aegis_Dark_Default,
|
||||
Theme.AMOLED, R.style.Theme_Aegis_TrueDark_Default
|
||||
);
|
||||
|
||||
public static final Map<Theme, Integer> NO_ACTION_BAR = ImmutableMap.of(
|
||||
Theme.LIGHT, R.style.Theme_Aegis_Light_NoActionBar,
|
||||
Theme.DARK, R.style.Theme_Aegis_Dark_NoActionBar,
|
||||
Theme.AMOLED, R.style.Theme_Aegis_TrueDark_NoActionBar
|
||||
Theme.LIGHT, R.style.Theme_Aegis_Light,
|
||||
Theme.DARK, R.style.Theme_Aegis_Dark,
|
||||
Theme.AMOLED, R.style.Theme_Aegis_Amoled
|
||||
);
|
||||
|
||||
public static final Map<Theme, Integer> FULLSCREEN = ImmutableMap.of(
|
||||
Theme.LIGHT, R.style.Theme_Aegis_Light_Fullscreen,
|
||||
Theme.DARK, R.style.Theme_Aegis_Dark_Fullscreen,
|
||||
Theme.AMOLED, R.style.Theme_Aegis_TrueDark_Fullscreen
|
||||
Theme.AMOLED, R.style.Theme_Aegis_Amoled_Fullscreen
|
||||
);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public enum ViewMode {
|
|||
return 4;
|
||||
}
|
||||
|
||||
return 20;
|
||||
return 8;
|
||||
}
|
||||
|
||||
public int getColumnSpan() {
|
||||
|
|
|
@ -56,16 +56,20 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
// It's not clear when this can happen, but sometimes the ViewHolder
|
||||
// that's passed to this function has a position of -1, leading
|
||||
// to a crash down the line.
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
int position = viewHolder.getBindingAdapterPosition();
|
||||
if (position == NO_POSITION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swipeFlags = 0;
|
||||
|
||||
EntryAdapter adapter = (EntryAdapter) recyclerView.getAdapter();
|
||||
if (adapter == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swipeFlags = 0;
|
||||
if (adapter.isPositionFooter(position)
|
||||
|| adapter.getEntryAt(position) != _selectedEntry
|
||||
|| adapter.isPositionErrorCard(position)
|
||||
|| adapter.getEntryAtPos(position) != _selectedEntry
|
||||
|| !isLongPressDragEnabled()) {
|
||||
return makeMovementFlags(0, swipeFlags);
|
||||
}
|
||||
|
@ -76,12 +80,13 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||
RecyclerView.ViewHolder target) {
|
||||
if (target.getAdapterPosition() < _adapter.getShownFavoritesCount()){
|
||||
int targetIndex = _adapter.translateEntryPosToIndex(target.getBindingAdapterPosition());
|
||||
if (targetIndex < _adapter.getShownFavoritesCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int firstPosition = viewHolder.getLayoutPosition();
|
||||
int secondPosition = target.getAdapterPosition();
|
||||
int secondPosition = target.getBindingAdapterPosition();
|
||||
|
||||
_adapter.onItemMove(firstPosition, secondPosition);
|
||||
_positionChanged = true;
|
||||
|
@ -90,7 +95,7 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
_adapter.onItemDismiss(viewHolder.getAdapterPosition());
|
||||
_adapter.onItemDismiss(viewHolder.getBindingAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -98,7 +103,7 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
if (_positionChanged) {
|
||||
_adapter.onItemDrop(viewHolder.getAdapterPosition());
|
||||
_adapter.onItemDrop(viewHolder.getBindingAdapterPosition());
|
||||
_positionChanged = false;
|
||||
_adapter.refresh(false);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
|||
import com.beemdevelopment.aegis.ui.tasks.PBKDFTask;
|
||||
import com.beemdevelopment.aegis.util.IOUtils;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
@ -182,7 +183,7 @@ public class AndOtpImporter extends DatabaseImporter {
|
|||
context.getResources().getString(R.string.andotp_old_format)
|
||||
};
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(context)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.choose_andotp_importer)
|
||||
.setSingleChoiceItems(choices, 0, null)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
|
|
|
@ -4,8 +4,6 @@ import android.content.Context;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.util.Xml;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.crypto.CryptoUtils;
|
||||
import com.beemdevelopment.aegis.encoding.Base32;
|
||||
|
@ -18,6 +16,7 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
|||
import com.beemdevelopment.aegis.util.IOUtils;
|
||||
import com.beemdevelopment.aegis.util.PreferenceParser;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
@ -154,7 +153,7 @@ public class TotpAuthenticatorImporter extends DatabaseImporter {
|
|||
|
||||
@Override
|
||||
public void decrypt(Context context, DecryptListener listener) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(context)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(context)
|
||||
.setMessage(R.string.choose_totpauth_importer)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
Dialogs.showPasswordInputDialog(context, password -> {
|
||||
|
|
|
@ -13,17 +13,14 @@ import android.widget.Toast;
|
|||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.view.LayoutInflaterCompat;
|
||||
|
||||
import com.beemdevelopment.aegis.BuildConfig;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.Theme;
|
||||
import com.beemdevelopment.aegis.helpers.ThemeHelper;
|
||||
import com.beemdevelopment.aegis.licenses.GlideLicense;
|
||||
import com.beemdevelopment.aegis.licenses.ProtobufLicense;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.ChangelogDialog;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.LicenseDialog;
|
||||
import com.mikepenz.iconics.context.IconicsLayoutInflater2;
|
||||
|
||||
import de.psdev.licensesdialog.LicenseResolver;
|
||||
import de.psdev.licensesdialog.LicensesDialog;
|
||||
|
@ -40,7 +37,6 @@ public class AboutActivity extends AegisActivity {
|
|||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
LayoutInflaterCompat.setFactory2(getLayoutInflater(), new IconicsLayoutInflater2(getDelegate()));
|
||||
super.onCreate(savedInstanceState);
|
||||
if (abortIfOrphan(savedInstanceState)) {
|
||||
return;
|
||||
|
@ -132,11 +128,10 @@ public class AboutActivity extends AegisActivity {
|
|||
|
||||
private void showThirdPartyLicenseDialog() {
|
||||
String stylesheet = getString(R.string.custom_notices_format_style);
|
||||
int backgroundColorResource = getConfiguredTheme() == Theme.AMOLED ? R.attr.cardBackgroundFocused : R.attr.cardBackground;
|
||||
String backgroundColor = getThemeColorAsHex(backgroundColorResource);
|
||||
String textColor = getThemeColorAsHex(R.attr.primaryText);
|
||||
String licenseColor = getThemeColorAsHex(R.attr.cardBackgroundFocused);
|
||||
String linkColor = getThemeColorAsHex(androidx.appcompat.R.attr.colorAccent);
|
||||
String backgroundColor = getThemeColorAsHex(com.google.android.material.R.attr.colorSurfaceContainerLow);
|
||||
String textColor = getThemeColorAsHex(com.google.android.material.R.attr.colorOnSurface);
|
||||
String licenseColor = getThemeColorAsHex(com.google.android.material.R.attr.colorSurfaceContainerLow);
|
||||
String linkColor = getThemeColorAsHex(com.google.android.material.R.attr.colorAccent);
|
||||
|
||||
stylesheet = String.format(stylesheet, backgroundColor, textColor, licenseColor, linkColor);
|
||||
|
||||
|
|
|
@ -4,21 +4,31 @@ import android.annotation.SuppressLint;
|
|||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.core.view.ViewPropertyAnimatorCompat;
|
||||
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.Theme;
|
||||
import com.beemdevelopment.aegis.ThemeMap;
|
||||
import com.beemdevelopment.aegis.helpers.ThemeHelper;
|
||||
import com.beemdevelopment.aegis.icons.IconPackManager;
|
||||
import com.beemdevelopment.aegis.vault.VaultManager;
|
||||
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
||||
import com.google.android.material.color.DynamicColors;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
@ -42,6 +52,8 @@ public abstract class AegisActivity extends AppCompatActivity implements VaultMa
|
|||
@Inject
|
||||
protected IconPackManager _iconPackManager;
|
||||
|
||||
private ActionModeStatusGuardHack _statusGuardHack;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// set the theme and locale before creating the activity
|
||||
|
@ -50,6 +62,8 @@ public abstract class AegisActivity extends AppCompatActivity implements VaultMa
|
|||
setLocale(_prefs.getLocale());
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
_statusGuardHack = new ActionModeStatusGuardHack();
|
||||
|
||||
// set FLAG_SECURE on the window of every AegisActivity
|
||||
if (_prefs.isSecureScreenEnabled()) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
|
@ -106,6 +120,10 @@ public abstract class AegisActivity extends AppCompatActivity implements VaultMa
|
|||
protected void setTheme(Map<Theme, Integer> themeMap) {
|
||||
int theme = themeMap.get(getConfiguredTheme());
|
||||
setTheme(theme);
|
||||
|
||||
if (_prefs.isDynamicColorsEnabled()) {
|
||||
DynamicColors.applyToActivityIfAvailable(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected Theme getConfiguredTheme() {
|
||||
|
@ -169,6 +187,77 @@ public abstract class AegisActivity extends AppCompatActivity implements VaultMa
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSupportActionModeStarted(@NonNull ActionMode mode) {
|
||||
super.onSupportActionModeStarted(mode);
|
||||
_statusGuardHack.apply(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSupportActionModeFinished(@NonNull ActionMode mode) {
|
||||
super.onSupportActionModeFinished(mode);
|
||||
_statusGuardHack.apply(View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* When starting/finishing an action mode, forcefully cancel the fade in/out animation and
|
||||
* set the status bar color. This requires the abc_decor_view_status_guard colors to be set
|
||||
* to transparent.
|
||||
*
|
||||
* This should fix any inconsistencies between the color of the action bar and the status bar
|
||||
* when an action mode is active.
|
||||
*/
|
||||
private class ActionModeStatusGuardHack {
|
||||
private Field _fadeAnimField;
|
||||
private Field _actionModeViewField;
|
||||
|
||||
@ColorInt
|
||||
private final int _statusBarColor;
|
||||
|
||||
private ActionModeStatusGuardHack() {
|
||||
_statusBarColor = getWindow().getStatusBarColor();
|
||||
|
||||
try {
|
||||
_fadeAnimField = getDelegate().getClass().getDeclaredField("mFadeAnim");
|
||||
_fadeAnimField.setAccessible(true);
|
||||
_actionModeViewField = getDelegate().getClass().getDeclaredField("mActionModeView");
|
||||
_actionModeViewField.setAccessible(true);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void apply(int visibility) {
|
||||
if (_fadeAnimField == null || _actionModeViewField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewPropertyAnimatorCompat fadeAnim;
|
||||
ViewGroup actionModeView;
|
||||
try {
|
||||
fadeAnim = (ViewPropertyAnimatorCompat) _fadeAnimField.get(getDelegate());
|
||||
actionModeView = (ViewGroup) _actionModeViewField.get(getDelegate());
|
||||
} catch (IllegalAccessException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fadeAnim == null || actionModeView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
fadeAnim.cancel();
|
||||
|
||||
actionModeView.setVisibility(visibility);
|
||||
actionModeView.setAlpha(visibility == View.VISIBLE ? 1f : 0f);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
int statusBarColor = visibility == View.VISIBLE
|
||||
? ThemeHelper.getThemeColor(com.google.android.material.R.attr.colorSurfaceContainer, getTheme())
|
||||
: _statusBarColor;
|
||||
getWindow().setStatusBarColor(statusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports whether this Activity instance has become an orphan. This can happen if
|
||||
* the vault was killed/locked by an external trigger while the Activity was still open.
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.beemdevelopment.aegis.ui;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -20,11 +19,9 @@ import android.widget.Toast;
|
|||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.ThemeMap;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||
import com.beemdevelopment.aegis.crypto.MasterKey;
|
||||
|
@ -43,6 +40,7 @@ import com.beemdevelopment.aegis.vault.slots.Slot;
|
|||
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.vault.slots.SlotIntegrityException;
|
||||
import com.beemdevelopment.aegis.vault.slots.SlotList;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -163,10 +161,11 @@ public class AuthActivity extends AegisActivity {
|
|||
|
||||
biometricsButton.setOnClickListener(v -> {
|
||||
if (_prefs.isPasswordReminderNeeded()) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(getString(R.string.password_reminder_dialog_title))
|
||||
.setMessage(getString(R.string.password_reminder_dialog_message))
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which) -> {
|
||||
showBiometricPrompt();
|
||||
})
|
||||
|
@ -183,11 +182,6 @@ public class AuthActivity extends AegisActivity {
|
|||
outState.putBoolean("inhibitBioPrompt", _inhibitBioPrompt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetTheme() {
|
||||
setTheme(ThemeMap.NO_ACTION_BAR);
|
||||
}
|
||||
|
||||
private void selectPassword() {
|
||||
_textPassword.selectAll();
|
||||
|
||||
|
@ -240,9 +234,6 @@ public class AuthActivity extends AegisActivity {
|
|||
PopupWindow popup = new PopupWindow(popupLayout, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
popup.setFocusable(false);
|
||||
popup.setOutsideTouchable(true);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
|
||||
popup.setElevation(5.0f);
|
||||
}
|
||||
_textPassword.post(() -> {
|
||||
if (isFinishing()) {
|
||||
return;
|
||||
|
@ -302,10 +293,11 @@ public class AuthActivity extends AegisActivity {
|
|||
}
|
||||
|
||||
private void onInvalidPassword() {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(AuthActivity.this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(AuthActivity.this, R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(getString(R.string.unlock_vault_error))
|
||||
.setMessage(getString(R.string.unlock_vault_error_description))
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> selectPassword())
|
||||
.create());
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.amulyakhare.textdrawable.TextDrawable;
|
||||
import com.avito.android.krop.KropView;
|
||||
|
@ -68,6 +67,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
|
@ -164,7 +164,7 @@ public class EditEntryActivity extends AegisActivity {
|
|||
|
||||
ActionBar bar = getSupportActionBar();
|
||||
if (bar != null) {
|
||||
bar.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
bar.setHomeAsUpIndicator(R.drawable.ic_outline_close_24);
|
||||
bar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
|
@ -473,7 +473,7 @@ public class EditEntryActivity extends AegisActivity {
|
|||
} else if (itemId == R.id.action_edit_icon) {
|
||||
startIconSelection();
|
||||
} else if (itemId == R.id.action_reset_usage_count) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.action_reset_usage_count)
|
||||
.setMessage(R.string.action_reset_usage_count_dialog)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> resetUsageCount())
|
||||
|
@ -754,9 +754,10 @@ public class EditEntryActivity extends AegisActivity {
|
|||
}
|
||||
|
||||
private void onSaveError(String msg) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(getString(R.string.saving_profile_error))
|
||||
.setMessage(msg)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create());
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.view.View;
|
|||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -15,6 +14,7 @@ import com.beemdevelopment.aegis.R;
|
|||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.beemdevelopment.aegis.ui.views.GroupAdapter;
|
||||
import com.beemdevelopment.aegis.vault.VaultGroup;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
@ -84,9 +84,10 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter.
|
|||
|
||||
@Override
|
||||
public void onRemoveGroup(VaultGroup group) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.remove_group)
|
||||
.setMessage(R.string.remove_group_description)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
|
||||
_removedGroups.add(group.getUUID());
|
||||
_adapter.removeGroup(group);
|
||||
|
@ -98,9 +99,10 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter.
|
|||
}
|
||||
|
||||
public void onRemoveUnusedGroups() {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.remove_unused_groups)
|
||||
.setMessage(R.string.remove_unused_groups_description)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
|
||||
Set<VaultGroup> unusedGroups = new HashSet<>(_vaultManager.getVault().getGroups());
|
||||
unusedGroups.removeAll(_vaultManager.getVault().getUsedGroups());
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.widget.Toast;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -28,6 +27,7 @@ import com.beemdevelopment.aegis.util.UUIDMap;
|
|||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.beemdevelopment.aegis.vault.VaultGroup;
|
||||
import com.beemdevelopment.aegis.vault.VaultRepository;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
|
@ -62,7 +62,7 @@ public class ImportEntriesActivity extends AegisActivity {
|
|||
_view = findViewById(R.id.importEntriesRootView);
|
||||
|
||||
ActionBar bar = getSupportActionBar();
|
||||
bar.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
bar.setHomeAsUpIndicator(R.drawable.ic_outline_close_24);
|
||||
bar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
_adapter = new ImportEntriesAdapter();
|
||||
|
@ -101,10 +101,11 @@ public class ImportEntriesActivity extends AegisActivity {
|
|||
if (importer.isInstalledAppVersionSupported()) {
|
||||
startImportApp(importer);
|
||||
} else {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(getString(R.string.app_version_error, importerDef.getName()))
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(R.string.yes, (dialog1, which) -> {
|
||||
startImportApp(importer);
|
||||
})
|
||||
|
@ -215,7 +216,7 @@ public class ImportEntriesActivity extends AegisActivity {
|
|||
List<DatabaseImporterEntryException> errors = result.getErrors();
|
||||
if (errors.size() > 0) {
|
||||
String message = getResources().getQuantityString(R.plurals.import_error_dialog, errors.size(), errors.size());
|
||||
Dialogs.showMultiErrorDialog(this, R.string.import_error_title, message, errors, null);
|
||||
Dialogs.showMultiExceptionDialog(this, R.string.import_error_title, message, errors, null);
|
||||
}
|
||||
|
||||
findDuplicates(importEntries);
|
||||
|
@ -296,7 +297,7 @@ public class ImportEntriesActivity extends AegisActivity {
|
|||
|
||||
assignIconIntent.putExtra("entries", assignIconEntriesIds);
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.import_assign_icons_dialog_title)
|
||||
.setMessage(R.string.import_assign_icons_dialog_text)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.ThemeMap;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.beemdevelopment.aegis.ui.intro.IntroBaseActivity;
|
||||
import com.beemdevelopment.aegis.ui.intro.SlideFragment;
|
||||
|
@ -40,11 +39,6 @@ public class IntroActivity extends IntroBaseActivity {
|
|||
addSlide(DoneSlide.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetTheme() {
|
||||
setTheme(ThemeMap.NO_ACTION_BAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onBeforeSlideChanged(Class<? extends SlideFragment> oldSlide, @NonNull Class<? extends SlideFragment> newSlide) {
|
||||
// hide the keyboard before every slide change
|
||||
|
|
|
@ -25,8 +25,6 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
|
@ -37,8 +35,8 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
|
||||
import com.beemdevelopment.aegis.CopyBehavior;
|
||||
import com.beemdevelopment.aegis.AccountNamePosition;
|
||||
import com.beemdevelopment.aegis.CopyBehavior;
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.SortCategory;
|
||||
|
@ -51,11 +49,13 @@ import com.beemdevelopment.aegis.otp.OtpInfoException;
|
|||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
|
||||
import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment;
|
||||
import com.beemdevelopment.aegis.ui.models.ErrorCardInfo;
|
||||
import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask;
|
||||
import com.beemdevelopment.aegis.ui.views.EntryListView;
|
||||
import com.beemdevelopment.aegis.util.TimeUtils;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
|
@ -87,8 +87,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
private Menu _menu;
|
||||
private SearchView _searchView;
|
||||
private EntryListView _entryListView;
|
||||
private LinearLayout _btnErrorBar;
|
||||
private TextView _textErrorBar;
|
||||
|
||||
private FabScrollHelper _fabScrollHelper;
|
||||
|
||||
|
@ -223,9 +221,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
Dialogs.showSecureDialog(dialog);
|
||||
});
|
||||
|
||||
_btnErrorBar = findViewById(R.id.btn_error_bar);
|
||||
_textErrorBar = findViewById(R.id.text_error_bar);
|
||||
|
||||
_fabScrollHelper = new FabScrollHelper(fab);
|
||||
_selectedEntries = new ArrayList<>();
|
||||
}
|
||||
|
@ -458,7 +453,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
boolean isSingleBatch = GoogleAuthInfo.Export.isSingleBatch(googleAuthExports);
|
||||
if (!isSingleBatch && errors.size() > 0) {
|
||||
errors.add(getString(R.string.unrelated_google_auth_batches_error));
|
||||
Dialogs.showMultiMessageDialog(this, R.string.import_error_title, getString(R.string.no_tokens_can_be_imported), errors, null);
|
||||
Dialogs.showMultiErrorDialog(this, R.string.import_error_title, getString(R.string.no_tokens_can_be_imported), errors, null);
|
||||
return;
|
||||
} else if (!isSingleBatch) {
|
||||
Dialogs.showErrorDialog(this, R.string.import_google_auth_failure, getString(R.string.unrelated_google_auth_batches_error));
|
||||
|
@ -473,7 +468,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
}
|
||||
|
||||
if ((errors.size() > 0 && results.size() > 1) || errors.size() > 1) {
|
||||
Dialogs.showMultiMessageDialog(this, R.string.import_error_title, getString(R.string.unable_to_read_qrcode_files, uris.size() - errors.size(), uris.size()), errors, dialogDismissHandler);
|
||||
Dialogs.showMultiErrorDialog(this, R.string.import_error_title, getString(R.string.unable_to_read_qrcode_files, uris.size() - errors.size(), uris.size()), errors, dialogDismissHandler);
|
||||
} else if (errors.size() > 0) {
|
||||
Dialogs.showErrorDialog(this, getString(R.string.unable_to_read_qrcode_file, results.get(0).getFileName()), errors.get(0), dialogDismissHandler);
|
||||
} else {
|
||||
|
@ -691,7 +686,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
handleIncomingIntent();
|
||||
updateLockIcon();
|
||||
doShortcutActions();
|
||||
updateErrorBar();
|
||||
updateErrorCard();
|
||||
}
|
||||
|
||||
private void deleteEntries(List<VaultEntry> entries) {
|
||||
|
@ -851,49 +846,49 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
}
|
||||
}
|
||||
|
||||
private void updateErrorBar() {
|
||||
private void updateErrorCard() {
|
||||
ErrorCardInfo info = null;
|
||||
|
||||
Preferences.BackupResult backupRes = _prefs.getErroredBackupResult();
|
||||
if (backupRes != null) {
|
||||
_textErrorBar.setText(R.string.backup_error_bar_message);
|
||||
_btnErrorBar.setOnClickListener(view -> {
|
||||
info = new ErrorCardInfo(getString(R.string.backup_error_bar_message), view -> {
|
||||
Dialogs.showBackupErrorDialog(this, backupRes, (dialog, which) -> {
|
||||
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
||||
});
|
||||
});
|
||||
_btnErrorBar.setVisibility(View.VISIBLE);
|
||||
} else if (_prefs.isBackupsReminderNeeded() && _prefs.isBackupReminderEnabled()) {
|
||||
String text;
|
||||
Date date = _prefs.getLatestBackupOrExportTime();
|
||||
if (date != null) {
|
||||
_textErrorBar.setText(getString(R.string.backup_reminder_bar_message_with_latest, TimeUtils.getElapsedSince(this, date)));
|
||||
text = getString(R.string.backup_reminder_bar_message_with_latest, TimeUtils.getElapsedSince(this, date));
|
||||
} else {
|
||||
_textErrorBar.setText(R.string.backup_reminder_bar_message);
|
||||
text = getString(R.string.backup_reminder_bar_message);
|
||||
}
|
||||
_btnErrorBar.setOnClickListener(view -> {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||
info = new ErrorCardInfo(text, view -> {
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(R.string.backup_reminder_bar_dialog_title)
|
||||
.setMessage(R.string.backup_reminder_bar_dialog_summary)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(R.string.backup_reminder_bar_dialog_accept, (dialog, whichButton) -> {
|
||||
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create());
|
||||
});
|
||||
_btnErrorBar.setVisibility(View.VISIBLE);
|
||||
} else if (_prefs.isPlaintextBackupWarningNeeded()) {
|
||||
_textErrorBar.setText(R.string.backup_plaintext_export_warning);
|
||||
_btnErrorBar.setOnClickListener(view -> showPlaintextExportWarningOptions());
|
||||
_btnErrorBar.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
_btnErrorBar.setVisibility(View.GONE);
|
||||
info = new ErrorCardInfo(getString(R.string.backup_plaintext_export_warning), view -> showPlaintextExportWarningOptions());
|
||||
}
|
||||
|
||||
_entryListView.setErrorCardInfo(info);
|
||||
}
|
||||
|
||||
private void showPlaintextExportWarningOptions() {
|
||||
View view = LayoutInflater.from(this).inflate(R.layout.dialog_plaintext_warning, null);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.backup_plaintext_export_warning)
|
||||
.setView(view)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
|
@ -910,7 +905,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
_prefs.setIsPlaintextBackupWarningDisabled(checkBox.isChecked());
|
||||
_prefs.setIsPlaintextBackupWarningNeeded(false);
|
||||
|
||||
updateErrorBar();
|
||||
updateErrorCard();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -926,8 +921,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
setFavoriteMenuItemVisiblity();
|
||||
setIsMultipleSelected(_selectedEntries.size() > 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -957,14 +950,14 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
|
||||
if (_selectedEntries.size() == 1){
|
||||
if (_selectedEntries.get(0).isFavorite()) {
|
||||
toggleFavoriteMenuItem.setIcon(R.drawable.ic_set_favorite);
|
||||
toggleFavoriteMenuItem.setIcon(R.drawable.ic_filled_star_24);
|
||||
toggleFavoriteMenuItem.setTitle(R.string.unfavorite);
|
||||
} else {
|
||||
toggleFavoriteMenuItem.setIcon(R.drawable.ic_unset_favorite);
|
||||
toggleFavoriteMenuItem.setIcon(R.drawable.ic_outline_star_24);
|
||||
toggleFavoriteMenuItem.setTitle(R.string.favorite);
|
||||
}
|
||||
} else {
|
||||
toggleFavoriteMenuItem.setIcon(R.drawable.ic_unset_favorite);
|
||||
toggleFavoriteMenuItem.setIcon(R.drawable.ic_outline_star_24);
|
||||
toggleFavoriteMenuItem.setTitle(String.format("%s / %s", getString(R.string.favorite), getString(R.string.unfavorite)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment;
|
|||
public class PreferencesActivity extends AegisActivity implements
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
private Fragment _fragment;
|
||||
private CharSequence _prefTitle;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -48,6 +49,10 @@ public class PreferencesActivity extends AegisActivity implements
|
|||
}
|
||||
} else {
|
||||
_fragment = getSupportFragmentManager().findFragmentById(R.id.content);
|
||||
_prefTitle = savedInstanceState.getCharSequence("prefTitle");
|
||||
if (_prefTitle != null) {
|
||||
setTitle(_prefTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +74,7 @@ public class PreferencesActivity extends AegisActivity implements
|
|||
// this is done so we don't lose anything if the fragment calls recreate on this activity
|
||||
outState.putParcelable("result", ((PreferencesFragment) _fragment).getResult());
|
||||
}
|
||||
outState.putCharSequence("prefTitle", _prefTitle);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
|
@ -90,7 +96,8 @@ public class PreferencesActivity extends AegisActivity implements
|
|||
_fragment.setTargetFragment(caller, 0);
|
||||
showFragment(_fragment);
|
||||
|
||||
setTitle(pref.getTitle());
|
||||
_prefTitle = pref.getTitle();
|
||||
setTitle(_prefTitle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,11 @@ public class ScannerActivity extends AegisActivity implements QrCodeAnalyzer.Lis
|
|||
}, ContextCompat.getMainExecutor(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetTheme() {
|
||||
setTheme(ThemeMap.FULLSCREEN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (_executor != null) {
|
||||
|
@ -95,11 +100,6 @@ public class ScannerActivity extends AegisActivity implements QrCodeAnalyzer.Lis
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetTheme() {
|
||||
setTheme(ThemeMap.FULLSCREEN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
_menu = menu;
|
||||
|
@ -142,10 +142,10 @@ public class ScannerActivity extends AegisActivity implements QrCodeAnalyzer.Lis
|
|||
if (dual) {
|
||||
switch (_currentLens) {
|
||||
case CameraSelector.LENS_FACING_BACK:
|
||||
item.setIcon(R.drawable.ic_camera_front_24dp);
|
||||
item.setIcon(R.drawable.ic_outline_camera_front_24);
|
||||
break;
|
||||
case CameraSelector.LENS_FACING_FRONT:
|
||||
item.setIcon(R.drawable.ic_camera_rear_24dp);
|
||||
item.setIcon(R.drawable.ic_outline_camera_rear_24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import com.beemdevelopment.aegis.vault.VaultEntry;
|
|||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.vault.slots.Slot;
|
||||
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.nulabinc.zxcvbn.Strength;
|
||||
|
@ -87,9 +88,10 @@ public class Dialogs {
|
|||
}
|
||||
textMessage.setText(message);
|
||||
|
||||
showSecureDialog(new AlertDialog.Builder(context)
|
||||
showSecureDialog(new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(title)
|
||||
.setView(view)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.yes, onDelete)
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.create());
|
||||
|
@ -108,9 +110,10 @@ public class Dialogs {
|
|||
}
|
||||
|
||||
public static void showDiscardDialog(Context context, DialogInterface.OnClickListener onSave, DialogInterface.OnClickListener onDiscard) {
|
||||
showSecureDialog(new AlertDialog.Builder(context)
|
||||
showSecureDialog(new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(context.getString(R.string.discard_changes))
|
||||
.setMessage(context.getString(R.string.discard_changes_description))
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(R.string.save, onSave)
|
||||
.setNegativeButton(R.string.discard, onDiscard)
|
||||
.create());
|
||||
|
@ -138,7 +141,7 @@ public class Dialogs {
|
|||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.set_password)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
|
@ -209,7 +212,7 @@ public class Dialogs {
|
|||
}
|
||||
inputLayout.setHint(hintId);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(titleId)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, null);
|
||||
|
@ -272,7 +275,7 @@ public class Dialogs {
|
|||
CheckBox checkBox = view.findViewById(R.id.checkbox);
|
||||
checkBox.setText(checkboxMessageId);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(titleId)
|
||||
.setView(view)
|
||||
.setNegativeButton(R.string.no, (dialog1, which) ->
|
||||
|
@ -306,7 +309,7 @@ public class Dialogs {
|
|||
numberPicker.setValue(currentValue);
|
||||
numberPicker.setWrapSelectorWheel(true);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.set_number)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which) ->
|
||||
|
@ -331,7 +334,7 @@ public class Dialogs {
|
|||
numberPicker.setValue(currentVersionCount / 5 - 1);
|
||||
numberPicker.setWrapSelectorWheel(false);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.set_number)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which) ->
|
||||
|
@ -372,10 +375,11 @@ public class Dialogs {
|
|||
TextView textMessage = view.findViewById(R.id.error_message);
|
||||
textMessage.setText(message);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(R.string.error_occurred)
|
||||
.setView(view)
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which) -> {
|
||||
if (listener != null) {
|
||||
listener.onClick(dialog1, which);
|
||||
|
@ -412,34 +416,35 @@ public class Dialogs {
|
|||
Dialogs.showErrorDialog(context, message, backupRes.getError(), listener);
|
||||
}
|
||||
|
||||
public static void showMultiMessageDialog(
|
||||
public static void showMultiErrorDialog(
|
||||
Context context, @StringRes int title, String message, List<CharSequence> messages, DialogInterface.OnClickListener listener) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(context)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
if (listener != null) {
|
||||
listener.onClick(dialog, which);
|
||||
}
|
||||
})
|
||||
.setNeutralButton(context.getString(R.string.details), (dialog, which) -> {
|
||||
showDetailedMultiMessageDialog(context, title, messages, listener);
|
||||
showDetailedMultiErrorDialog(context, title, messages, listener);
|
||||
})
|
||||
.create());
|
||||
}
|
||||
|
||||
public static <T extends Throwable> void showMultiErrorDialog(
|
||||
public static <T extends Throwable> void showMultiExceptionDialog(
|
||||
Context context, @StringRes int title, String message, List<T> errors, DialogInterface.OnClickListener listener) {
|
||||
List<CharSequence> messages = new ArrayList<>();
|
||||
for (Throwable e : errors) {
|
||||
messages.add(e.toString());
|
||||
}
|
||||
|
||||
showMultiMessageDialog(context, title, message, messages, listener);
|
||||
showMultiErrorDialog(context, title, message, messages, listener);
|
||||
}
|
||||
|
||||
private static void showDetailedMultiMessageDialog(
|
||||
private static void showDetailedMultiErrorDialog(
|
||||
Context context, @StringRes int title, List<CharSequence> messages, DialogInterface.OnClickListener listener) {
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
for (CharSequence message : messages) {
|
||||
|
@ -447,10 +452,11 @@ public class Dialogs {
|
|||
builder.append("\n\n");
|
||||
}
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(title)
|
||||
.setMessage(builder)
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which) -> {
|
||||
if (listener != null) {
|
||||
listener.onClick(dialog1, which);
|
||||
|
@ -477,10 +483,11 @@ public class Dialogs {
|
|||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_time_sync, null);
|
||||
CheckBox checkBox = view.findViewById(R.id.check_warning_disable);
|
||||
|
||||
showSecureDialog(new AlertDialog.Builder(context)
|
||||
showSecureDialog(new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.time_sync_warning_title)
|
||||
.setView(view)
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
if (checkBox.isChecked()) {
|
||||
prefs.setIsTimeSyncWarningEnabled(false);
|
||||
|
@ -515,7 +522,7 @@ public class Dialogs {
|
|||
setImporterHelpText(helpText, importers.get(position), isDirect);
|
||||
});
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(context)
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.choose_application)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which) -> {
|
||||
|
@ -536,11 +543,12 @@ public class Dialogs {
|
|||
errorDetails.append("\n\n");
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.partial_google_auth_import)
|
||||
.setMessage(context.getString(R.string.partial_google_auth_import_warning, missingIndexesAsString))
|
||||
.setView(view)
|
||||
.setCancelable(false)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(context.getString(R.string.import_partial_export_anyway, entries), (dialog, which) -> {
|
||||
dismissHandler.onClick(dialog, which);
|
||||
})
|
||||
|
|
|
@ -18,6 +18,7 @@ import androidx.fragment.app.DialogFragment;
|
|||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.Theme;
|
||||
import com.beemdevelopment.aegis.helpers.ThemeHelper;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.common.io.CharStreams;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -44,14 +45,14 @@ public abstract class SimpleWebViewDialog extends DialogFragment {
|
|||
view = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_web_view, null);
|
||||
} catch (InflateException e) {
|
||||
e.printStackTrace();
|
||||
return new AlertDialog.Builder(requireContext())
|
||||
return new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(android.R.string.dialog_alert_title)
|
||||
.setMessage(getString(R.string.webview_error))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(requireContext())
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(_title)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
|
@ -69,12 +70,11 @@ public abstract class SimpleWebViewDialog extends DialogFragment {
|
|||
}
|
||||
|
||||
protected String getBackgroundColor() {
|
||||
int backgroundColorResource = _theme == Theme.AMOLED ? R.attr.cardBackgroundFocused : R.attr.cardBackground;
|
||||
return colorToCSS(ThemeHelper.getThemeColor(backgroundColorResource, requireContext().getTheme()));
|
||||
return colorToCSS(ThemeHelper.getThemeColor(com.google.android.material.R.attr.colorSurfaceContainerHigh, requireContext().getTheme()));
|
||||
}
|
||||
|
||||
protected String getTextColor() {
|
||||
return colorToCSS(0xFFFFFF & ThemeHelper.getThemeColor(R.attr.primaryText, requireContext().getTheme()));
|
||||
return colorToCSS(0xFFFFFF & ThemeHelper.getThemeColor(com.google.android.material.R.attr.colorOnSurface, requireContext().getTheme()));
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
|
|
|
@ -8,11 +8,17 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.preference.Preference;
|
||||
|
||||
import com.beemdevelopment.aegis.AccountNamePosition;
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.Theme;
|
||||
import com.beemdevelopment.aegis.ViewMode;
|
||||
import com.beemdevelopment.aegis.ui.GroupManagerActivity;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.google.android.material.color.DynamicColors;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class AppearancePreferencesFragment extends PreferencesFragment {
|
||||
private Preference _groupsPreference;
|
||||
|
@ -33,7 +39,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
|
||||
_resetUsageCountPreference = requirePreference("pref_reset_usage_count");
|
||||
_resetUsageCountPreference.setOnPreferenceClickListener(preference -> {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.preference_reset_usage_count)
|
||||
.setMessage(R.string.preference_reset_usage_count_dialog)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> _prefs.clearUsageCount())
|
||||
|
@ -48,7 +54,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
darkModePreference.setOnPreferenceClickListener(preference -> {
|
||||
int currentTheme1 = _prefs.getCurrentTheme().ordinal();
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.choose_theme)
|
||||
.setSingleChoiceItems(R.array.theme_titles, currentTheme1, (dialog, which) -> {
|
||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
|
@ -65,13 +71,38 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
return true;
|
||||
});
|
||||
|
||||
Preference langPreference = requirePreference("pref_lang");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
langPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Preference dynamicColorsPreference = requirePreference("pref_dynamic_colors");
|
||||
dynamicColorsPreference.setEnabled(DynamicColors.isDynamicColorAvailable());
|
||||
dynamicColorsPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
getResult().putExtra("needsRecreate", true);
|
||||
requireActivity().recreate();
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference langPreference = requirePreference("pref_lang");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
String[] langs = getResources().getStringArray(R.array.pref_lang_values);
|
||||
String[] langNames = getResources().getStringArray(R.array.pref_lang_entries);
|
||||
List<String> langList = Arrays.asList(langs);
|
||||
int curLangIndex = langList.contains(_prefs.getLanguage()) ? langList.indexOf(_prefs.getLanguage()) : 0;
|
||||
langPreference.setSummary(langNames[curLangIndex]);
|
||||
langPreference.setOnPreferenceClickListener(preference -> {
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.pref_lang_title)
|
||||
.setSingleChoiceItems(langNames, curLangIndex, (dialog, which) -> {
|
||||
int newLangIndex = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
_prefs.setLanguage(langs[newLangIndex]);
|
||||
langPreference.setSummary(langNames[newLangIndex]);
|
||||
|
||||
dialog.dismiss();
|
||||
|
||||
getResult().putExtra("needsRecreate", true);
|
||||
requireActivity().recreate();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create());
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
// Setting locale doesn't work on Marshmallow or below
|
||||
langPreference.setVisible(false);
|
||||
|
@ -83,7 +114,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
viewModePreference.setOnPreferenceClickListener(preference -> {
|
||||
int currentViewMode1 = _prefs.getCurrentViewMode().ordinal();
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.choose_view_mode)
|
||||
.setSingleChoiceItems(R.array.view_mode_titles, currentViewMode1, (dialog, which) -> {
|
||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
|
@ -99,9 +130,22 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
return true;
|
||||
});
|
||||
|
||||
String[] codeGroupings = getResources().getStringArray(R.array.pref_code_groupings_values);
|
||||
String[] codeGroupingNames = getResources().getStringArray(R.array.pref_code_groupings);
|
||||
int currentCodeGroupingIndex = Arrays.asList(codeGroupings).indexOf(_prefs.getCodeGroupSize().name());
|
||||
Preference codeDigitGroupingPreference = requirePreference("pref_code_group_size_string");
|
||||
codeDigitGroupingPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
codeDigitGroupingPreference.setOnPreferenceClickListener(preference -> {
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.pref_code_group_size_title)
|
||||
.setSingleChoiceItems(codeGroupingNames, currentCodeGroupingIndex, (dialog, which) -> {
|
||||
int newCodeGroupingIndex = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
_prefs.setCodeGroupSize(Preferences.CodeGrouping.valueOf(codeGroupings[newCodeGroupingIndex]));
|
||||
|
||||
dialog.dismiss();
|
||||
getResult().putExtra("needsRefresh", true);
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create());
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -117,7 +161,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
_currentAccountNamePositionPreference.setOnPreferenceClickListener(preference -> {
|
||||
int currentAccountNamePosition1 = _prefs.getAccountNamePosition().ordinal();
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.choose_account_name_position))
|
||||
.setSingleChoiceItems(R.array.account_name_position_titles, currentAccountNamePosition1, (dialog, which) -> {
|
||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
|
|
|
@ -19,6 +19,7 @@ import androidx.preference.SwitchPreferenceCompat;
|
|||
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.helpers.ThemeHelper;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
||||
|
||||
|
@ -195,9 +196,9 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
|||
|
||||
// TODO: Find out why setting the tint of the icon doesn't work
|
||||
if (backupFailed) {
|
||||
pref.setIcon(R.drawable.ic_info_outline_black_24dp);
|
||||
pref.setIcon(R.drawable.ic_outline_error_24);
|
||||
} else if (res != null) {
|
||||
pref.setIcon(R.drawable.ic_check_black_24dp);
|
||||
pref.setIcon(R.drawable.ic_outline_check_24);
|
||||
} else {
|
||||
pref.setIcon(null);
|
||||
}
|
||||
|
@ -205,21 +206,20 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
|||
|
||||
private CharSequence getBackupStatusMessage(@Nullable Preferences.BackupResult res) {
|
||||
String message;
|
||||
int color = R.color.warning_color;
|
||||
int colorAttr = com.google.android.material.R.attr.colorError;
|
||||
if (res == null) {
|
||||
message = getString(R.string.backup_status_none);
|
||||
} else if (res.isSuccessful()) {
|
||||
color = R.color.success_color;
|
||||
colorAttr = R.attr.colorSuccess;
|
||||
message = getString(R.string.backup_status_success, res.getElapsedSince(requireContext()));
|
||||
} else {
|
||||
message = getString(R.string.backup_status_failed, res.getElapsedSince(requireContext()));
|
||||
}
|
||||
|
||||
int color = ThemeHelper.getThemeColor(colorAttr, requireContext().getTheme());
|
||||
Spannable spannable = new SpannableString(message);
|
||||
spannable.setSpan(new ForegroundColorSpan(getResources().getColor(color)), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
if (color == R.color.warning_color) {
|
||||
spannable.setSpan(new ForegroundColorSpan(color), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
return spannable;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.preference.Preference;
|
|||
import com.beemdevelopment.aegis.CopyBehavior;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
public class BehaviorPreferencesFragment extends PreferencesFragment {
|
||||
private Preference _entryPausePreference;
|
||||
|
@ -23,7 +24,7 @@ public class BehaviorPreferencesFragment extends PreferencesFragment {
|
|||
copyBehaviorPreference.setOnPreferenceClickListener(preference -> {
|
||||
int currentCopyBehavior1 = _prefs.getCopyBehavior().ordinal();
|
||||
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.choose_copy_behavior))
|
||||
.setSingleChoiceItems(R.array.copy_behavior_titles, currentCopyBehavior1, (dialog, which) -> {
|
||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
|
|
|
@ -14,7 +14,6 @@ import androidx.activity.result.ActivityResultLauncher;
|
|||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -30,6 +29,7 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
|||
import com.beemdevelopment.aegis.ui.tasks.ImportIconPackTask;
|
||||
import com.beemdevelopment.aegis.ui.views.IconPackAdapter;
|
||||
import com.beemdevelopment.aegis.vault.VaultManager;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -102,9 +102,10 @@ public class IconPacksManagerFragment extends Fragment implements IconPackAdapte
|
|||
|
||||
@Override
|
||||
public void onRemoveIconPack(IconPack pack) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.remove_icon_pack)
|
||||
.setMessage(R.string.remove_icon_pack_description)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
|
||||
try {
|
||||
_iconPackManager.removeIconPack(pack);
|
||||
|
@ -124,9 +125,10 @@ public class IconPacksManagerFragment extends Fragment implements IconPackAdapte
|
|||
ImportIconPackTask task = new ImportIconPackTask(requireContext(), result -> {
|
||||
Exception e = result.getException();
|
||||
if (e instanceof IconPackExistsException) {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(R.string.error_occurred)
|
||||
.setMessage(R.string.icon_pack_import_exists_error)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
if (removeIconPack(((IconPackExistsException) e).getIconPack())) {
|
||||
importIconPack(uri);
|
||||
|
|
|
@ -45,6 +45,7 @@ import com.beemdevelopment.aegis.vault.VaultRepository;
|
|||
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -202,7 +203,7 @@ public class ImportExportPreferencesFragment extends PreferencesFragment {
|
|||
groupsSelection.addItems(groupsArray, false);
|
||||
}
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(requireContext())
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.pref_export_summary)
|
||||
.setView(view)
|
||||
.setNeutralButton(R.string.share, null)
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
|||
import com.beemdevelopment.aegis.vault.slots.Slot;
|
||||
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
||||
import com.beemdevelopment.aegis.vault.slots.SlotList;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -91,9 +92,10 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
|
|||
if (!_vaultManager.getVault().isEncryptionEnabled()) {
|
||||
Dialogs.showSetPasswordDialog(requireActivity(), new EnableEncryptionListener());
|
||||
} else {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
|
||||
.setTitle(R.string.disable_encryption)
|
||||
.setMessage(getText(R.string.disable_encryption_description))
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||
try {
|
||||
_vaultManager.disableEncryption();
|
||||
|
@ -169,9 +171,10 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
|
|||
task.execute(getLifecycle(), params);
|
||||
} else {
|
||||
_pinKeyboardPreference.setChecked(false);
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(R.string.pin_keyboard_error)
|
||||
.setMessage(R.string.pin_keyboard_error_description)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create());
|
||||
|
@ -192,7 +195,7 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
|
|||
checkedItems[i] = _prefs.isAutoLockTypeEnabled(items[i]);
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext())
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.pref_auto_lock_prompt)
|
||||
.setMultiChoiceItems(textItems, checkedItems, (dialog, index, isChecked) -> checkedItems[index] = isChecked)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
|
@ -221,7 +224,7 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
|
|||
.map(f -> getString(f.getStringRes()))
|
||||
.toArray(String[]::new);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext())
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.pref_password_reminder_title)
|
||||
.setSingleChoiceItems(textItems, currFreq.ordinal(), (dialog, which) -> {
|
||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
|
@ -459,9 +462,10 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
|
|||
if (result != null) {
|
||||
_pinKeyboardPreference.setChecked(true);
|
||||
} else {
|
||||
Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext())
|
||||
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Aegis_AlertDialog_Error)
|
||||
.setTitle(R.string.pin_keyboard_error)
|
||||
.setMessage(R.string.invalid_password)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create());
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.beemdevelopment.aegis.ui.intro;
|
|||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -16,6 +15,7 @@ import androidx.viewpager2.widget.ViewPager2;
|
|||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.helpers.AnimationsHelper;
|
||||
import com.beemdevelopment.aegis.ui.AegisActivity;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
@ -28,8 +28,8 @@ public abstract class IntroBaseActivity extends AegisActivity implements IntroAc
|
|||
private List<Class<? extends SlideFragment>> _slides;
|
||||
private WeakReference<SlideFragment> _currentSlide;
|
||||
|
||||
private ImageButton _btnPrevious;
|
||||
private ImageButton _btnNext;
|
||||
private MaterialButton _btnPrevious;
|
||||
private MaterialButton _btnNext;
|
||||
private SlideIndicator _slideIndicator;
|
||||
|
||||
@Override
|
||||
|
@ -158,7 +158,7 @@ public abstract class IntroBaseActivity extends AegisActivity implements IntroAc
|
|||
? View.VISIBLE
|
||||
: View.INVISIBLE);
|
||||
if (pos == _slides.size() - 1) {
|
||||
_btnNext.setImageResource(R.drawable.circular_button_done);
|
||||
_btnNext.setIconResource(R.drawable.ic_outline_check_24);
|
||||
}
|
||||
_slideIndicator.setSlideCount(_slides.size());
|
||||
_slideIndicator.setCurrentSlide(pos);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.beemdevelopment.aegis.ui.models;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public class ErrorCardInfo {
|
||||
private final String _message;
|
||||
private final View.OnClickListener _listener;
|
||||
|
||||
public ErrorCardInfo(String message, View.OnClickListener listener) {
|
||||
_message = message;
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return _message;
|
||||
}
|
||||
|
||||
public View.OnClickListener getListener() {
|
||||
return _listener;
|
||||
}
|
||||
}
|
|
@ -1,26 +1,38 @@
|
|||
package com.beemdevelopment.aegis.ui.tasks;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Process;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
public abstract class ProgressDialogTask<Params, Result> extends AsyncTask<Params, String, Result> {
|
||||
private ProgressDialog _dialog;
|
||||
private final AlertDialog _dialog;
|
||||
private final TextView _textProgress;
|
||||
|
||||
public ProgressDialogTask(Context context, String message) {
|
||||
_dialog = new ProgressDialog(context);
|
||||
_dialog.setCancelable(false);
|
||||
_dialog.setMessage(message);
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_progress, null);
|
||||
_textProgress = view.findViewById(R.id.text_progress);
|
||||
_textProgress.setText(message);
|
||||
|
||||
_dialog = new MaterialAlertDialogBuilder(context)
|
||||
.setView(view)
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
|
||||
Dialogs.secureDialog(_dialog);
|
||||
}
|
||||
|
||||
|
@ -41,7 +53,7 @@ public abstract class ProgressDialogTask<Params, Result> extends AsyncTask<Param
|
|||
@Override
|
||||
protected void onProgressUpdate(String... values) {
|
||||
if (values.length == 1) {
|
||||
_dialog.setMessage(values[0]);
|
||||
_textProgress.setText(values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +61,7 @@ public abstract class ProgressDialogTask<Params, Result> extends AsyncTask<Param
|
|||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
|
||||
}
|
||||
|
||||
protected final ProgressDialog getDialog() {
|
||||
protected final AlertDialog getDialog() {
|
||||
return _dialog;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public class AssignIconHolder extends RecyclerView.ViewHolder implements AssignI
|
|||
if (_entry.getNewIcon() != null) {
|
||||
GlideHelper.loadIcon(Glide.with(_view.getContext()), _entry.getNewIcon(), _newIcon);
|
||||
} else {
|
||||
GlideHelper.loadResource(Glide.with(_view.getContext()), R.drawable.ic_icon_unselected, _newIcon);
|
||||
GlideHelper.loadResource(Glide.with(_view.getContext()), R.drawable.ic_unselected, _newIcon);
|
||||
}
|
||||
|
||||
_btnReset.setVisibility(_entry.getNewIcon() != null ? View.VISIBLE : View.INVISIBLE);
|
||||
|
|
|
@ -17,10 +17,10 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.beemdevelopment.aegis.CopyBehavior;
|
||||
import com.beemdevelopment.aegis.AccountNamePosition;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.CopyBehavior;
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.SortCategory;
|
||||
import com.beemdevelopment.aegis.ViewMode;
|
||||
import com.beemdevelopment.aegis.helpers.ItemTouchHelperAdapter;
|
||||
|
@ -29,6 +29,7 @@ import com.beemdevelopment.aegis.otp.HotpInfo;
|
|||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
||||
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
||||
import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||
import com.beemdevelopment.aegis.ui.models.ErrorCardInfo;
|
||||
import com.beemdevelopment.aegis.util.CollectionUtils;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
|
||||
|
@ -70,6 +71,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
private Handler _dimHandler;
|
||||
private Handler _doubleTapHandler;
|
||||
private boolean _pauseFocused;
|
||||
private ErrorCardInfo _errorCardInfo;
|
||||
|
||||
// keeps track of the EntryHolders that are currently bound
|
||||
private List<EntryHolder> _holders;
|
||||
|
@ -130,8 +132,21 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
_pauseFocused = pauseFocused;
|
||||
}
|
||||
|
||||
public VaultEntry getEntryAt(int position) {
|
||||
return _shownEntries.get(position);
|
||||
public void setErrorCardInfo(ErrorCardInfo info) {
|
||||
ErrorCardInfo oldInfo = _errorCardInfo;
|
||||
_errorCardInfo = info;
|
||||
|
||||
if (oldInfo == null && info != null) {
|
||||
notifyItemInserted(0);
|
||||
} else if (oldInfo != null && info == null) {
|
||||
notifyItemRemoved(0);
|
||||
} else {
|
||||
notifyItemChanged(0);
|
||||
}
|
||||
}
|
||||
|
||||
public VaultEntry getEntryAtPos(int position) {
|
||||
return _shownEntries.get(translateEntryPosToIndex(position));
|
||||
}
|
||||
|
||||
public int addEntry(VaultEntry entry) {
|
||||
|
@ -148,8 +163,8 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
for (int i = getShownFavoritesCount(); i < _shownEntries.size(); i++) {
|
||||
if (comparator.compare(_shownEntries.get(i), entry) > 0) {
|
||||
_shownEntries.add(i, entry);
|
||||
notifyItemInserted(i);
|
||||
position = i;
|
||||
position = translateEntryIndexToPos(i);
|
||||
notifyItemInserted(position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +173,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
if (position < 0) {
|
||||
_shownEntries.add(entry);
|
||||
|
||||
position = getItemCount() - 1;
|
||||
position = translateEntryIndexToPos(getShownEntriesCount() - 1);
|
||||
if (position == 0) {
|
||||
notifyDataSetChanged();
|
||||
} else {
|
||||
|
@ -186,9 +201,12 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
_entries.remove(entry);
|
||||
|
||||
if (_shownEntries.contains(entry)) {
|
||||
int position = _shownEntries.indexOf(entry);
|
||||
_shownEntries.remove(position);
|
||||
int index = _shownEntries.indexOf(entry);
|
||||
_shownEntries.remove(index);
|
||||
|
||||
int position = translateEntryIndexToPos(index);
|
||||
notifyItemRemoved(position);
|
||||
|
||||
updateFooter();
|
||||
}
|
||||
|
||||
|
@ -213,26 +231,32 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
_entries.set(_entries.indexOf(oldEntry), newEntry);
|
||||
|
||||
if (_shownEntries.contains(oldEntry)) {
|
||||
int position = _shownEntries.indexOf(oldEntry);
|
||||
int index = _shownEntries.indexOf(oldEntry);
|
||||
int position = translateEntryIndexToPos(index);
|
||||
if (isEntryFiltered(newEntry)) {
|
||||
_shownEntries.remove(position);
|
||||
_shownEntries.remove(index);
|
||||
notifyItemRemoved(position);
|
||||
} else {
|
||||
_shownEntries.set(position, newEntry);
|
||||
_shownEntries.set(index, newEntry);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
sortShownEntries();
|
||||
int newPosition = _shownEntries.indexOf(newEntry);
|
||||
int newIndex = _shownEntries.indexOf(newEntry);
|
||||
int newPosition = translateEntryIndexToPos(newIndex);
|
||||
if (newPosition != NO_POSITION && position != newPosition) {
|
||||
notifyItemMoved(position, newPosition);
|
||||
}
|
||||
} else if (!isEntryFiltered(newEntry)) {
|
||||
// NOTE: This logic is wrong, because sorting is not taken into account. This code
|
||||
// path is currently never hit though, because it is not possible to edit an entry
|
||||
// that is not shown.
|
||||
_shownEntries.add(newEntry);
|
||||
|
||||
int position = getItemCount() - 1;
|
||||
notifyItemInserted(position);
|
||||
}
|
||||
|
||||
checkPeriodUniformity();
|
||||
updateFooter();
|
||||
}
|
||||
|
@ -247,6 +271,36 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private int translateEntryIndexToPos(int index) {
|
||||
if (index == NO_POSITION) {
|
||||
return NO_POSITION;
|
||||
}
|
||||
|
||||
if (isErrorCardShown()) {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private boolean isEntryFiltered(VaultEntry entry) {
|
||||
Set<UUID> groups = entry.getGroups();
|
||||
String issuer = entry.getIssuer().toLowerCase();
|
||||
|
@ -366,33 +420,42 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
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() || isPositionFooter(position)) {
|
||||
if (!_groupFilter.isEmpty() || isPositionFooter(position) || isPositionErrorCard(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_view.onEntryDrop(_shownEntries.get(position));
|
||||
int index = translateEntryPosToIndex(position);
|
||||
_view.onEntryDrop(_shownEntries.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemMove(int firstPosition, int secondPosition) {
|
||||
// moving entries is not allowed when a filter is applied
|
||||
// footer cant be moved, nor can items be moved below it
|
||||
if (!_groupFilter.isEmpty() || isPositionFooter(firstPosition) || isPositionFooter(secondPosition)) {
|
||||
if (!_groupFilter.isEmpty()
|
||||
|| isPositionFooter(firstPosition) || isPositionFooter(secondPosition)
|
||||
|| isPositionErrorCard(firstPosition) || isPositionErrorCard(secondPosition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// notify the vault first
|
||||
_view.onEntryMove(_entries.get(firstPosition), _entries.get(secondPosition));
|
||||
int firstIndex = translateEntryPosToIndex(firstPosition);
|
||||
int secondIndex = translateEntryPosToIndex(secondPosition);
|
||||
_view.onEntryMove(_entries.get(firstIndex), _entries.get(secondIndex));
|
||||
|
||||
// then update our end
|
||||
CollectionUtils.move(_entries, firstPosition, secondPosition);
|
||||
CollectionUtils.move(_shownEntries, firstPosition, secondPosition);
|
||||
CollectionUtils.move(_entries, firstIndex, secondIndex);
|
||||
CollectionUtils.move(_shownEntries, firstIndex, secondIndex);
|
||||
|
||||
notifyItemMoved(firstPosition, secondPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (isPositionErrorCard(position)) {
|
||||
return R.layout.card_error;
|
||||
}
|
||||
|
||||
if (isPositionFooter(position)) {
|
||||
return R.layout.card_footer;
|
||||
}
|
||||
|
@ -406,7 +469,15 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
RecyclerView.ViewHolder holder;
|
||||
View view = inflater.inflate(viewType, parent, false);
|
||||
holder = viewType == R.layout.card_footer ? new FooterView(view) : new EntryHolder(view);
|
||||
|
||||
if (viewType == R.layout.card_error) {
|
||||
holder = new ErrorCardHolder(view, _errorCardInfo);
|
||||
} else if (viewType == R.layout.card_footer) {
|
||||
holder = new FooterView(view);
|
||||
} else {
|
||||
holder = new EntryHolder(view);
|
||||
}
|
||||
|
||||
if (_showIcon && holder instanceof EntryHolder) {
|
||||
_view.setPreloadView(((EntryHolder) holder).getIconView());
|
||||
}
|
||||
|
@ -426,7 +497,8 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
|
||||
if (holder instanceof EntryHolder) {
|
||||
EntryHolder entryHolder = (EntryHolder) holder;
|
||||
VaultEntry entry = _shownEntries.get(position);
|
||||
int index = translateEntryPosToIndex(position);
|
||||
VaultEntry entry = _shownEntries.get(index);
|
||||
|
||||
boolean hidden = _tapToReveal && entry != _focusedEntry;
|
||||
boolean paused = _pauseFocused && entry == _focusedEntry;
|
||||
|
@ -508,12 +580,13 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
entryHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
int position = holder.getAdapterPosition();
|
||||
int position = holder.getBindingAdapterPosition();
|
||||
if (_selectedEntries.isEmpty()) {
|
||||
entryHolder.setFocusedAndAnimate(true);
|
||||
}
|
||||
|
||||
boolean returnVal = _view.onLongEntryClick(_shownEntries.get(position));
|
||||
int index = translateEntryPosToIndex(position);
|
||||
boolean returnVal = _view.onLongEntryClick(_shownEntries.get(index));
|
||||
if (_selectedEntries.size() == 0 || isEntryDraggable(entry)) {
|
||||
_view.startDrag(entryHolder);
|
||||
}
|
||||
|
@ -748,15 +821,30 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return getEntriesCount() + 1;
|
||||
// Always at least one item because of the footer
|
||||
// Two in case there's also an error card
|
||||
int baseCount = 1;
|
||||
if (isErrorCardShown()) {
|
||||
baseCount++;
|
||||
}
|
||||
|
||||
public int getEntriesCount() {
|
||||
return baseCount + getShownEntriesCount();
|
||||
}
|
||||
|
||||
public int getShownEntriesCount() {
|
||||
return _shownEntries.size();
|
||||
}
|
||||
|
||||
public boolean isPositionFooter(int position) {
|
||||
return position == getEntriesCount();
|
||||
return position == (getItemCount() - 1);
|
||||
}
|
||||
|
||||
public boolean isPositionErrorCard(int position) {
|
||||
return isErrorCardShown() && position == 0;
|
||||
}
|
||||
|
||||
public boolean isErrorCardShown() {
|
||||
return _errorCardInfo != null;
|
||||
}
|
||||
|
||||
private void updateFooter() {
|
||||
|
@ -772,7 +860,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
}
|
||||
|
||||
public void refresh() {
|
||||
int entriesShown = getEntriesCount();
|
||||
int entriesShown = getShownEntriesCount();
|
||||
SpannableString entriesShownSpannable = new SpannableString(_footerView.getResources().getQuantityString(R.plurals.entries_shown, entriesShown, entriesShown));
|
||||
|
||||
String entriesShownString = String.format("%d", entriesShown);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.beemdevelopment.aegis.ui.views;
|
||||
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
|
@ -17,7 +16,6 @@ import com.beemdevelopment.aegis.R;
|
|||
import com.beemdevelopment.aegis.ViewMode;
|
||||
import com.beemdevelopment.aegis.helpers.AnimationsHelper;
|
||||
import com.beemdevelopment.aegis.helpers.SimpleAnimationEndListener;
|
||||
import com.beemdevelopment.aegis.helpers.ThemeHelper;
|
||||
import com.beemdevelopment.aegis.helpers.UiRefresher;
|
||||
import com.beemdevelopment.aegis.otp.HotpInfo;
|
||||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
||||
|
@ -28,6 +26,7 @@ import com.beemdevelopment.aegis.otp.YandexInfo;
|
|||
import com.beemdevelopment.aegis.ui.glide.GlideHelper;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
public class EntryHolder extends RecyclerView.ViewHolder {
|
||||
private static final float DEFAULT_ALPHA = 1.0f;
|
||||
|
@ -56,7 +55,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
private boolean _paused;
|
||||
|
||||
private TotpProgressBar _progressBar;
|
||||
private View _view;
|
||||
private MaterialCardView _view;
|
||||
|
||||
private UiRefresher _refresher;
|
||||
private Handler _animationHandler;
|
||||
|
@ -67,8 +66,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
public EntryHolder(final View view) {
|
||||
super(view);
|
||||
|
||||
_view = view.findViewById(R.id.rlCardEntry);
|
||||
|
||||
_view = (MaterialCardView) view;
|
||||
_profileName = view.findViewById(R.id.profile_account_name);
|
||||
_profileCode = view.findViewById(R.id.profile_code);
|
||||
_profileIssuer = view.findViewById(R.id.profile_issuer);
|
||||
|
@ -84,9 +82,6 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
_animationHandler = new Handler();
|
||||
|
||||
_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));
|
||||
|
||||
_scaleIn = AnimationsHelper.loadScaledAnimation(view.getContext(), R.anim.item_scale_in);
|
||||
_scaleOut = AnimationsHelper.loadScaledAnimation(view.getContext(), R.anim.item_scale_out);
|
||||
|
@ -229,11 +224,8 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
public void setFocused(boolean focused) {
|
||||
if (focused) {
|
||||
_selected.setVisibility(View.VISIBLE);
|
||||
_view.setBackgroundColor(ThemeHelper.getThemeColor(R.attr.cardBackgroundFocused, _view.getContext().getTheme()));
|
||||
} else {
|
||||
_view.setBackgroundColor(ThemeHelper.getThemeColor(R.attr.cardBackground, _view.getContext().getTheme()));
|
||||
}
|
||||
_view.setSelected(focused);
|
||||
_view.setChecked(focused);
|
||||
}
|
||||
|
||||
public void setFocusedAndAnimate(boolean focused) {
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.beemdevelopment.aegis.helpers.UiRefresher;
|
|||
import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.beemdevelopment.aegis.ui.glide.GlideHelper;
|
||||
import com.beemdevelopment.aegis.ui.models.ErrorCardInfo;
|
||||
import com.beemdevelopment.aegis.ui.models.VaultGroupModel;
|
||||
import com.beemdevelopment.aegis.util.UUIDMap;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
|
@ -131,7 +132,9 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||
@Override
|
||||
public int getSpanSize(int position) {
|
||||
if (_viewMode == ViewMode.TILES && position == _adapter.getEntriesCount()) {
|
||||
if (_viewMode == ViewMode.TILES
|
||||
&& (_adapter.isPositionFooter(position)
|
||||
|| _adapter.isPositionErrorCard(position))) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -376,6 +379,10 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
_adapter.setTapToRevealTime(number);
|
||||
}
|
||||
|
||||
public void setErrorCardInfo(ErrorCardInfo info) {
|
||||
_adapter.setErrorCardInfo(info);
|
||||
}
|
||||
|
||||
public void addEntry(VaultEntry entry) {
|
||||
addEntry(entry, false);
|
||||
}
|
||||
|
@ -472,7 +479,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
}
|
||||
|
||||
private void addChipTo(ChipGroup chipGroup, VaultGroupModel group) {
|
||||
Chip chip = (Chip) getLayoutInflater().inflate(R.layout.chip_material, null, false);
|
||||
Chip chip = (Chip) getLayoutInflater().inflate(R.layout.chip_group_filter, null, false);
|
||||
chip.setText(group.getName());
|
||||
chip.setCheckable(true);
|
||||
chip.setChecked(_groupFilter != null && _groupFilter.contains(group.getUUID()));
|
||||
|
@ -600,7 +607,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
}
|
||||
|
||||
private void updateEmptyState() {
|
||||
if (_adapter.getEntriesCount() > 0) {
|
||||
if (_adapter.getShownEntriesCount() > 0) {
|
||||
_recyclerView.setVisibility(View.VISIBLE);
|
||||
_emptyStateView.setVisibility(View.GONE);
|
||||
} else {
|
||||
|
@ -636,6 +643,11 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
|
||||
@Override
|
||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
if (_adapter.isPositionErrorCard(parent.getChildAdapterPosition(view))) {
|
||||
outRect.top = MetricsHelper.convertDpToPixels(requireContext(), 4);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_adapter.isPositionFooter(parent.getChildAdapterPosition(view))) {
|
||||
int pixels = MetricsHelper.convertDpToPixels(requireContext(), 20);
|
||||
outRect.top = pixels;
|
||||
|
@ -662,41 +674,43 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
return;
|
||||
}
|
||||
|
||||
// The footer always has a top and bottom margin
|
||||
if (_adapter.isPositionFooter(adapterPosition)) {
|
||||
// The error card and the footer always have a top and bottom margin
|
||||
if (_adapter.isPositionErrorCard(adapterPosition)
|
||||
|| _adapter.isPositionFooter(adapterPosition)) {
|
||||
outRect.top = _height;
|
||||
outRect.bottom = _height;
|
||||
return;
|
||||
}
|
||||
|
||||
// The first entry should have a top margin, but only if the group chip is not shown
|
||||
if (adapterPosition == 0 && (_groups == null || _groups.isEmpty())) {
|
||||
int entryIndex = _adapter.translateEntryPosToIndex(adapterPosition);
|
||||
// The first entry should have a top margin, but only if the group chip is not shown and the error card is not shown
|
||||
if (entryIndex == 0 && (_groups == null || _groups.isEmpty()) && !_adapter.isErrorCardShown()) {
|
||||
outRect.top = _height;
|
||||
}
|
||||
|
||||
// Only non-favorite entries have a bottom margin, except for the final favorite entry
|
||||
int totalFavorites = _adapter.getShownFavoritesCount();
|
||||
if (totalFavorites == 0
|
||||
|| (adapterPosition < _adapter.getEntriesCount() && !_adapter.getEntryAt(adapterPosition).isFavorite())
|
||||
|| totalFavorites == adapterPosition + 1) {
|
||||
|| (entryIndex < _adapter.getShownEntriesCount() && !_adapter.getEntryAtPos(adapterPosition).isFavorite())
|
||||
|| totalFavorites == entryIndex + 1) {
|
||||
outRect.bottom = _height;
|
||||
}
|
||||
|
||||
if (totalFavorites > 0) {
|
||||
// If this entry is the last favorite entry in the list, it should always have
|
||||
// a bottom margin, regardless of the view mode
|
||||
if (adapterPosition == totalFavorites - 1) {
|
||||
if (entryIndex == totalFavorites - 1) {
|
||||
outRect.bottom = _height;
|
||||
}
|
||||
|
||||
// If this is the first non-favorite entry, it should have a top margin
|
||||
if (adapterPosition == totalFavorites) {
|
||||
if (entryIndex == totalFavorites) {
|
||||
outRect.top = _height;
|
||||
}
|
||||
}
|
||||
|
||||
// The last entry should never have a bottom margin
|
||||
if (_adapter.getEntriesCount() == adapterPosition + 1) {
|
||||
if (_adapter.getShownEntriesCount() == entryIndex + 1) {
|
||||
outRect.bottom = 0;
|
||||
}
|
||||
}
|
||||
|
@ -734,7 +748,11 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
VaultEntry entry = _adapter.getEntryAt(position);
|
||||
if (_adapter.getItemViewType(position) == R.layout.card_error) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
VaultEntry entry = _adapter.getEntryAtPos(position);
|
||||
if (!entry.hasIcon()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package com.beemdevelopment.aegis.ui.views;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.ui.models.ErrorCardInfo;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
public class ErrorCardHolder extends RecyclerView.ViewHolder {
|
||||
public ErrorCardHolder(@NonNull View itemView, ErrorCardInfo info) {
|
||||
super(itemView);
|
||||
|
||||
TextView errorTextView = itemView.findViewById(R.id.text_error_bar);
|
||||
errorTextView.setText(info.getMessage());
|
||||
|
||||
MaterialCardView errorCard = itemView.findViewById(R.id.card_error);
|
||||
errorCard.setOnClickListener(info.getListener());
|
||||
}
|
||||
}
|
|
@ -39,8 +39,8 @@ public class IconHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
public void loadIcon(Context context) {
|
||||
if (_isCustom) {
|
||||
int tint = ThemeHelper.getThemeColor(R.attr.iconColorPrimary, context.getTheme());
|
||||
GlideHelper.loadResource(Glide.with(context), R.drawable.ic_plus_black_24dp, tint, _imageView);
|
||||
int tint = ThemeHelper.getThemeColor(com.google.android.material.R.attr.colorOnSurfaceVariant, context.getTheme());
|
||||
GlideHelper.loadResource(Glide.with(context), R.drawable.ic_outline_add_24, tint, _imageView);
|
||||
} else {
|
||||
GlideHelper.loadIconFile(Glide.with(context), _iconFile, _iconType, _imageView);
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#D7E3EF" android:state_checked="true" />
|
||||
<item android:color="@color/background" />
|
||||
</selector>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/colorPrimary" android:state_checked="true" />
|
||||
<item android:color="@color/primary_text" />
|
||||
</selector>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/colorSecondary" android:state_enabled="true"/>
|
||||
<item android:alpha="0.38" android:color="@color/colorSecondary"/>
|
||||
<item android:color="?attr/colorSecondary" android:state_enabled="true"/>
|
||||
<item android:alpha="0.38" android:color="?attr/colorSecondary"/>
|
||||
</selector>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_enabled="false"
|
||||
android:color="#78efefef"
|
||||
/>
|
||||
<item
|
||||
android:state_enabled="true"
|
||||
android:color="#efefef"
|
||||
/>
|
||||
</selector>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?attr/iconColorPrimary" android:state_focused="true"/>
|
||||
<item android:color="?attr/iconColorPrimary" android:state_activated="true"/>
|
||||
<item android:color="?attr/iconColorPrimary"/>
|
||||
</selector>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#fff" android:state_focused="true"/>
|
||||
<item android:color="#fff" android:state_hovered="true"/>
|
||||
<item android:color="#fff"/>
|
||||
</selector>
|
|
@ -1,10 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
|
||||
</vector>
|
|
@ -1,15 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<group android:scaleX="1.1111112"
|
||||
android:scaleY="1.1111112"
|
||||
android:translateX="-1.3333334"
|
||||
android:translateY="-1.3333334">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -1,15 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<group android:scaleX="1.1111112"
|
||||
android:scaleY="1.1111112"
|
||||
android:translateX="-1.3333334"
|
||||
android:translateY="-1.3333334">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||
</group>
|
||||
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 125 B |
Binary file not shown.
Before Width: | Height: | Size: 98 B |
|
@ -1,26 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="137.93103"
|
||||
android:viewportHeight="137.93103">
|
||||
<group android:translateX="-11.034483"
|
||||
android:translateY="-11.034483">
|
||||
<path
|
||||
android:pathData="M55.78,0h48.44C120.28,0 128.31,0 137,2.73A34,34 0,0 1,157.27 23C160,31.69 160,39.72 160,55.78v48.44c0,16.06 0,24.09 -2.73,32.74A34,34 0,0 1,137 157.27C128.31,160 120.28,160 104.22,160H55.78c-16.06,0 -24.09,0 -32.74,-2.73A34,34 0,0 1,2.73 137C0,128.31 0,120.28 0,104.22V55.78C0,39.72 0,31.69 2.73,23A34,34 0,0 1,23 2.73C31.69,0 39.72,0 55.78,0h0">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="28.48"
|
||||
android:startX="51.92"
|
||||
android:endY="189.51"
|
||||
android:endX="139.67"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FFFFFFFF"/>
|
||||
<item android:offset="0.37" android:color="#FFF5FAFC"/>
|
||||
<item android:offset="1" android:color="#FFDBEBF5"/>
|
||||
<item android:offset="1" android:color="#FFDBEBF5"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</group>
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@android:color/white"/>
|
||||
<corners android:topLeftRadius="16dp"
|
||||
android:topRightRadius="16dp"/>
|
||||
|
||||
</shape>
|
Binary file not shown.
Before Width: | Height: | Size: 114 B |
Binary file not shown.
Before Width: | Height: | Size: 132 B |
|
@ -1,5 +1,11 @@
|
|||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#000000" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M10,17l5,-5 -5,-5v10z"/>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,17l5,-5 -5,-5v10z" />
|
||||
</vector>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#59000000" />
|
||||
<size
|
||||
android:width="50dp"
|
||||
android:height="50dp" />
|
||||
</shape>
|
|
@ -1,9 +0,0 @@
|
|||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/circular_button_background" />
|
||||
<item
|
||||
android:drawable="@drawable/ic_check_black_24dp"
|
||||
android:bottom="16dp"
|
||||
android:top="16dp"
|
||||
android:left="16dp"
|
||||
android:right="16dp" />
|
||||
</layer-list>
|
|
@ -1,9 +0,0 @@
|
|||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/circular_button_background" />
|
||||
<item
|
||||
android:drawable="@drawable/ic_arrow_right_black_24dp"
|
||||
android:bottom="16dp"
|
||||
android:top="16dp"
|
||||
android:left="16dp"
|
||||
android:right="16dp" />
|
||||
</layer-list>
|
|
@ -1,9 +0,0 @@
|
|||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/circular_button_background" />
|
||||
<item
|
||||
android:drawable="@drawable/ic_arrow_left_black_24dp"
|
||||
android:bottom="16dp"
|
||||
android:top="16dp"
|
||||
android:left="16dp"
|
||||
android:right="16dp" />
|
||||
</layer-list>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/divider2"/>
|
||||
<size android:height=".1dp"/>
|
||||
|
||||
<padding android:left="1dp"
|
||||
android:top="1dp"
|
||||
android:right="1dp"
|
||||
android:bottom="1dp" />
|
||||
|
||||
<corners android:radius="7dp" />
|
||||
</shape>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#B2000000"/>
|
||||
<padding
|
||||
android:left="16dp"
|
||||
android:top="4dp"
|
||||
android:right="16dp"
|
||||
android:bottom="4dp"/>
|
||||
<corners
|
||||
android:radius="2dp"/>
|
||||
</shape>
|
|
@ -2,9 +2,8 @@
|
|||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/auth_button"/>
|
||||
<stroke android:color="@color/auth_button" android:width="1dp" />
|
||||
<!--corners allow us to make the rounded corners button-->
|
||||
<solid />
|
||||
<stroke android:width="1dp" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
||||
</item>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,7v2.99s-1.99,0.01 -2,0L17,7h-3s0.01,-1.99 0,-2h3L17,2h2v3h3v2h-3zM16,11L16,8h-3L13,5L5,5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-8h-3zM5,19l3,-4 2,3 3,-4 4,5L5,19z"/>
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z" />
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M16.61 15.15C16.15 15.15 15.77 14.78 15.77 14.32S16.15 13.5 16.61 13.5H16.61C17.07 13.5 17.45 13.86 17.45 14.32C17.45 14.78 17.07 15.15 16.61 15.15M7.41 15.15C6.95 15.15 6.57 14.78 6.57 14.32C6.57 13.86 6.95 13.5 7.41 13.5H7.41C7.87 13.5 8.24 13.86 8.24 14.32C8.24 14.78 7.87 15.15 7.41 15.15M16.91 10.14L18.58 7.26C18.67 7.09 18.61 6.88 18.45 6.79C18.28 6.69 18.07 6.75 18 6.92L16.29 9.83C14.95 9.22 13.5 8.9 12 8.91C10.47 8.91 9 9.24 7.73 9.82L6.04 6.91C5.95 6.74 5.74 6.68 5.57 6.78C5.4 6.87 5.35 7.08 5.44 7.25L7.1 10.13C4.25 11.69 2.29 14.58 2 18H22C21.72 14.59 19.77 11.7 16.91 10.14H16.91Z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<!-- drawable/ic_arrow_left_black_24dp.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:autoMirrored="true">
|
||||
<path android:fillColor="#000" android:pathData="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<!-- drawable/ic_arrow_right_black_24dp.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:autoMirrored="true">
|
||||
<path android:fillColor="#000" android:pathData="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M5.5,10.5h2v1h-2zM20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM9,11.5c0,0.85 -0.65,1.5 -1.5,1.5h-2v2L4,15L4,9h3.5c0.85,0 1.5,0.65 1.5,1.5v1zM12.5,15L11,15L11,9h1.5v6zM20,15h-1.2l-2.55,-3.5L16.25,15L15,15L15,9h1.25l2.5,3.5L18.75,9L20,9v6z"/>
|
||||
</vector>
|
|
@ -1,10 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
|
||||
|
||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||
<vector android:height="32dp" android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
|
||||
</vector>
|
|
@ -1,10 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M3,18h12v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h18v-2L3,11v2z"/>
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<!-- drawable/brush.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M20.71,4.63L19.37,3.29C19,2.9 18.35,2.9 17.96,3.29L9,12.25L11.75,15L20.71,6.04C21.1,5.65 21.1,5 20.71,4.63M7,14A3,3 0 0,0 4,17C4,18.31 2.84,19 2,19C2.92,20.22 4.5,21 6,21A4,4 0 0,0 10,17A3,3 0 0,0 7,14Z" />
|
||||
</vector>
|
|
@ -1,7 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M7,2H17V12.5C17,10.83 13.67,10 12,10C10.33,10 7,10.83 7,12.5M17,0H7A2,2 0 0,0 5,2V16A2,2 0 0,0 7,18H17A2,2 0 0,0 19,16V2A2,2 0 0,0 17,0M12,8A2,2 0 0,0 14,6A2,2 0 0,0 12,4A2,2 0 0,0 10,6A2,2 0 0,0 12,8M14,20V22H19V20M10,20H5V22H10V24L13,21L10,18V20Z" />
|
||||
</vector>
|
|
@ -1,7 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M12,6C10.89,6 10,5.1 10,4A2,2 0 0,1 12,2C13.09,2 14,2.9 14,4A2,2 0 0,1 12,6M17,0H7A2,2 0 0,0 5,2V16A2,2 0 0,0 7,18H17A2,2 0 0,0 19,16V2A2,2 0 0,0 17,0M14,20V22H19V20M10,20H5V22H10V24L13,21L10,18V20Z" />
|
||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||
<vector android:height="24dp" android:tint="#F7F7F7"
|
||||
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="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||
</vector>
|
|
@ -1,7 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
|
||||
</vector>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
|
||||
<path
|
||||
android:pathData="M0 0h24v24H0z" />
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<!-- drawable/cloud_upload_outline.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4C9.11,4 6.6,5.64 5.35,8.04C2.34,8.36 0,10.91 0,14A6,6 0 0,0 6,20H19A5,5 0 0,0 24,15C24,12.36 21.95,10.22 19.35,10.04M19,18H6A4,4 0 0,1 2,14C2,11.95 3.53,10.24 5.56,10.03L6.63,9.92L7.13,8.97C8.08,7.14 9.94,6 12,6C14.62,6 16.88,7.86 17.39,10.43L17.69,11.93L19.22,12.04C20.78,12.14 22,13.45 22,15A3,3 0 0,1 19,18M8,13H10.55V16H13.45V13H16L12,9L8,13Z" />
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" />
|
||||
</vector>
|
|
@ -2,6 +2,7 @@
|
|||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path android:fillColor="#000" android:pathData="M4,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M4,6V18H11V6H4M20,18V6H18.76C19,6.54 18.95,7.07 18.95,7.13C18.88,7.8 18.41,8.5 18.24,8.75L15.91,11.3L19.23,11.28L19.24,12.5L14.04,12.47L14,11.47C14,11.47 17.05,8.24 17.2,7.95C17.34,7.67 17.91,6 16.5,6C15.27,6.05 15.41,7.3 15.41,7.3L13.87,7.31C13.87,7.31 13.88,6.65 14.25,6H13V18H15.58L15.57,17.14L16.54,17.13C16.54,17.13 17.45,16.97 17.46,16.08C17.5,15.08 16.65,15.08 16.5,15.08C16.37,15.08 15.43,15.13 15.43,15.95H13.91C13.91,15.95 13.95,13.89 16.5,13.89C19.1,13.89 18.96,15.91 18.96,15.91C18.96,15.91 19,17.16 17.85,17.63L18.37,18H20M8.92,16H7.42V10.2L5.62,10.76V9.53L8.76,8.41H8.92V16Z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<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>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<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>
|
|
@ -1,5 +0,0 @@
|
|||
<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>
|
|
@ -1,5 +0,0 @@
|
|||
<vector android:height="24dp" android:tint="#F7F7F7"
|
||||
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="M18,7l-1.41,-1.41 -6.34,6.34 1.41,1.41L18,7zM22.24,5.59L11.66,16.17 7.48,12l-1.41,1.41L11.66,19l12,-12 -1.42,-1.41zM0.41,13.41L6,19l1.41,-1.41L1.83,12 0.41,13.41z"/>
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<!-- drawable/dots_vertical.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z" />
|
||||
</vector>
|
8
app/src/main/res/drawable/ic_filled_star_24.xml
Normal file
8
app/src/main/res/drawable/ic_filled_star_24.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M233,840L298,559L80,370L368,345L480,80L592,345L880,370L662,559L727,840L480,691L233,840Z"/>
|
||||
</vector>
|
|
@ -1,7 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M11.83,1.73C8.43,1.79 6.23,3.32 6.23,3.32C5.95,3.5 5.88,3.91 6.07,4.19C6.27,4.5 6.66,4.55 6.96,4.34C6.96,4.34 11.27,1.15 17.46,4.38C17.75,4.55 18.14,4.45 18.31,4.15C18.5,3.85 18.37,3.47 18.03,3.28C16.36,2.4 14.78,1.96 13.36,1.8C12.83,1.74 12.32,1.72 11.83,1.73M12.22,4.34C6.26,4.26 3.41,9.05 3.41,9.05C3.22,9.34 3.3,9.72 3.58,9.91C3.87,10.1 4.26,10 4.5,9.68C4.5,9.68 6.92,5.5 12.2,5.59C17.5,5.66 19.82,9.65 19.82,9.65C20,9.94 20.38,10.04 20.68,9.87C21,9.69 21.07,9.31 20.9,9C20.9,9 18.15,4.42 12.22,4.34M11.5,6.82C9.82,6.94 8.21,7.55 7,8.56C4.62,10.53 3.1,14.14 4.77,19C4.88,19.33 5.24,19.5 5.57,19.39C5.89,19.28 6.07,18.92 5.95,18.6V18.6C4.41,14.13 5.78,11.2 7.8,9.5C9.77,7.89 13.25,7.5 15.84,9.1C17.11,9.9 18.1,11.28 18.6,12.64C19.11,14 19.08,15.32 18.67,15.94C18.25,16.59 17.4,16.83 16.65,16.64C15.9,16.45 15.29,15.91 15.26,14.77C15.23,13.06 13.89,12 12.5,11.84C11.16,11.68 9.61,12.4 9.21,14C8.45,16.92 10.36,21.07 14.78,22.45C15.11,22.55 15.46,22.37 15.57,22.04C15.67,21.71 15.5,21.35 15.15,21.25C11.32,20.06 9.87,16.43 10.42,14.29C10.66,13.33 11.5,13 12.38,13.08C13.25,13.18 14,13.7 14,14.79C14.05,16.43 15.12,17.54 16.34,17.85C17.56,18.16 18.97,17.77 19.72,16.62C20.5,15.45 20.37,13.8 19.78,12.21C19.18,10.61 18.07,9.03 16.5,8.04C14.96,7.08 13.19,6.7 11.5,6.82M11.86,9.25V9.26C10.08,9.32 8.3,10.24 7.28,12.18C5.96,14.67 6.56,17.21 7.44,19.04C8.33,20.88 9.54,22.1 9.54,22.1C9.78,22.35 10.17,22.35 10.42,22.11C10.67,21.87 10.67,21.5 10.43,21.23C10.43,21.23 9.36,20.13 8.57,18.5C7.78,16.87 7.3,14.81 8.38,12.77C9.5,10.67 11.5,10.16 13.26,10.67C15.04,11.19 16.53,12.74 16.5,15.03C16.46,15.38 16.71,15.68 17.06,15.7C17.4,15.73 17.7,15.47 17.73,15.06C17.79,12.2 15.87,10.13 13.61,9.47C13.04,9.31 12.45,9.23 11.86,9.25M12.08,14.25C11.73,14.26 11.46,14.55 11.47,14.89C11.47,14.89 11.5,16.37 12.31,17.8C13.15,19.23 14.93,20.59 18.03,20.3C18.37,20.28 18.64,20 18.62,19.64C18.6,19.29 18.3,19.03 17.91,19.06C15.19,19.31 14.04,18.28 13.39,17.17C12.74,16.07 12.72,14.88 12.72,14.88C12.72,14.53 12.44,14.25 12.08,14.25Z" />
|
||||
</vector>
|
|
@ -1,8 +0,0 @@
|
|||
<!-- drawable/gesture_tap.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M10,9A1,1 0 0,1 11,8A1,1 0 0,1 12,9V13.47L13.21,13.6L18.15,15.79C18.68,16.03 19,16.56 19,17.14V21.5C18.97,22.32 18.32,22.97 17.5,23H11C10.62,23 10.26,22.85 10,22.57L5.1,18.37L5.84,17.6C6.03,17.39 6.3,17.28 6.58,17.28H6.8L10,19V9M11,5A4,4 0 0,1 15,9C15,10.5 14.2,11.77 13,12.46V11.24C13.61,10.69 14,9.89 14,9A3,3 0 0,0 11,6A3,3 0 0,0 8,9C8,9.89 8.39,10.69 9,11.24V12.46C7.8,11.77 7,10.5 7,9A4,4 0 0,1 11,5Z" />
|
||||
</vector>
|
File diff suppressed because one or more lines are too long
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M0 0h24v24H0z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/>
|
||||
</vector>
|
|
@ -1,34 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11.99,18.54l-7.37,-5.73L3,14.07l9,7 9,-7 -1.63,-1.27 -7.38,5.74zM12,16l7.36,-5.73L21,9l-9,-7 -9,7 1.63,1.27L12,16z"/>
|
||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||
<!-- licensed under CC BY-SA 3.0 by WPZOOM (http://www.wpzoom.com/) -->
|
||||
<vector android:height="24dp" android:viewportHeight="500.0"
|
||||
android:viewportWidth="500.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M131.9,150.1v63.6h-27.3c-20.1,0 -36.3,16.3 -36.3,36.3v181.7c0,20.1 16.3,36.3 36.3,36.3h290.7c20.1,0 36.3,-16.3 36.3,-36.3V250c0,-20.1 -16.3,-36.3 -36.3,-36.3h-27.3v-63.6c0,-65.2 -52.9,-118.1 -118.1,-118.1S131.9,84.8 131.9,150.1zM177.3,213.7v-63.6c0,-40.2 32.5,-72.7 72.7,-72.7c40.2,0 72.7,32.5 72.7,72.7v63.6H177.3zM213.7,313.6c0,-20.1 16.3,-36.3 36.3,-36.3s36.3,16.3 36.3,36.3c0,12.8 -6.6,24.1 -16.6,30.5c0,0 3.5,21.4 7.5,46.7c0,7.5 -6.1,13.6 -13.6,13.6h-27.3c-7.5,0 -13.6,-6.1 -13.6,-13.6l7.5,-46.7C220.3,337.7 213.7,326.4 213.7,313.6z"/>
|
||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||
<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>
|
10
app/src/main/res/drawable/ic_outline_add_24.xml
Normal file
10
app/src/main/res/drawable/ic_outline_add_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M440,520L200,520L200,440L440,440L440,200L520,200L520,440L760,440L760,520L520,520L520,760L440,760L440,520Z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L560,120L560,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L760,760Q760,760 760,760Q760,760 760,760L760,400L840,400L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM680,360L680,280L600,280L600,200L680,200L680,120L760,120L760,200L840,200L840,280L760,280L760,360L680,360ZM240,680L720,680L570,480L450,640L360,520L240,680ZM200,200L200,320L200,320L200,400L200,400L200,760Q200,760 200,760Q200,760 200,760L200,760Q200,760 200,760Q200,760 200,760L200,200Q200,200 200,200Q200,200 200,200L200,200Z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_outline_android_24.xml
Normal file
10
app/src/main/res/drawable/ic_outline_android_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M40,720Q49,613 105.5,523Q162,433 256,380L182,252Q176,243 179,233Q182,223 192,218Q200,213 210,216Q220,219 226,228L300,356Q386,320 480,320Q574,320 660,356L734,228Q740,219 750,216Q760,213 768,218Q778,223 781,233Q784,243 778,252L704,380Q798,433 854.5,523Q911,613 920,720L40,720ZM280,610Q301,610 315.5,595.5Q330,581 330,560Q330,539 315.5,524.5Q301,510 280,510Q259,510 244.5,524.5Q230,539 230,560Q230,581 244.5,595.5Q259,610 280,610ZM680,610Q701,610 715.5,595.5Q730,581 730,560Q730,539 715.5,524.5Q701,510 680,510Q659,510 644.5,524.5Q630,539 630,560Q630,581 644.5,595.5Q659,610 680,610Z" />
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_outline_arrow_left_alt_24.xml
Normal file
11
app/src/main/res/drawable/ic_outline_arrow_left_alt_24.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M400,720L160,480L400,240L456,298L314,440L800,440L800,520L314,520L456,662L400,720Z" />
|
||||
</vector>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue