diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 02151d2..ee7629a 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,17 +1,17 @@ - + - + - - + + - - + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3cce64f..b9a64be 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,15 +35,15 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' + implementation 'androidx.lifecycle:lifecycle-livedata:2.4.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel:2.4.1' implementation 'androidx.navigation:navigation-fragment:2.5.3' implementation 'androidx.navigation:navigation-ui:2.5.3' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' implementation "androidx.biometric:biometric:1.1.0" - implementation 'com.cringe_studios:CringeAuthenticatorLibrary:1.0' + implementation 'com.cringe_studios:CringeAuthenticatorLibrary:1.2' implementation 'com.google.mlkit:barcode-scanning:17.1.0' implementation 'com.google.code.gson:gson:2.8.9' diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java index ae559cb..bc899c3 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/IntroActivity.java @@ -6,6 +6,7 @@ import android.content.SharedPreferences; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.ViewGroup; import android.widget.Toast; @@ -24,6 +25,8 @@ public class IntroActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Log.i("AMOGUS", "CREATE"); + if (!SettingsUtil.isIntroVideoEnabled(this)) { openMainActivity(); return; @@ -61,11 +64,16 @@ public class IntroActivity extends AppCompatActivity { @Override public void onDestroy() { super.onDestroy(); - // When the Activity is destroyed, release our MediaPlayer and set it to null. if(mMediaPlayer != null) mMediaPlayer.release(); mMediaPlayer = null; } + @Override + protected void onResume() { + super.onResume(); + binding.videoView.start(); + } + private void setDimension() { float videoProportion = (float) mMediaPlayer.getVideoHeight() / mMediaPlayer.getVideoWidth(); int screenWidth = getResources().getDisplayMetrics().widthPixels; diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java index 25188c7..0cda957 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/MainActivity.java @@ -23,6 +23,7 @@ import androidx.navigation.ui.NavigationUI; import com.cringe_studios.cringe_authenticator.databinding.ActivityMainBinding; import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeChoiceBinding; +import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeHotpBinding; import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeTotpBinding; import com.cringe_studios.cringe_authenticator.fragment.DynamicFragment; import com.cringe_studios.cringe_authenticator.fragment.HomeFragment; @@ -185,7 +186,6 @@ public class MainActivity extends AppCompatActivity { } private void showTOTPDialog() { - // TODO: checksum option DialogInputCodeTotpBinding binding = DialogInputCodeTotpBinding.inflate(getLayoutInflater()); binding.inputAlgorithm.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, OTPAlgorithm.values())); binding.inputDigits.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new Integer[]{6, 7, 8, 9, 10, 11, 12})); @@ -199,9 +199,9 @@ public class MainActivity extends AppCompatActivity { OTPAlgorithm algorithm = (OTPAlgorithm) binding.inputAlgorithm.getSelectedItem(); int digits = (int) binding.inputDigits.getSelectedItem(); int period = Integer.parseInt(binding.inputPeriod.getText().toString()); + boolean checksum = binding.inputChecksum.isChecked(); - // TODO: checksum - OTPData data = new OTPData(name, OTPType.TOTP, secret, algorithm, digits, period, 0, false); + OTPData data = new OTPData(name, OTPType.TOTP, secret, algorithm, digits, period, 0, checksum); String errorMessage = data.validate(); if(errorMessage != null) { @@ -219,8 +219,36 @@ public class MainActivity extends AppCompatActivity { } private void showHOTPDialog() { - DialogInputCodeTotpBinding binding = DialogInputCodeTotpBinding.inflate(getLayoutInflater()); - showCodeDialog(binding.getRoot(), () -> true); + DialogInputCodeHotpBinding binding = DialogInputCodeHotpBinding.inflate(getLayoutInflater()); + binding.inputAlgorithm.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, OTPAlgorithm.values())); + binding.inputDigits.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new Integer[]{6, 7, 8, 9, 10, 11, 12})); + showCodeDialog(binding.getRoot(), () -> { + Fragment fragment = NavigationUtil.getCurrentFragment(this); + if(!(fragment instanceof DynamicFragment)) return true; + + try { + String name = binding.inputName.getText().toString(); + String secret = binding.inputSecret.getText().toString(); + OTPAlgorithm algorithm = (OTPAlgorithm) binding.inputAlgorithm.getSelectedItem(); + int digits = (int) binding.inputDigits.getSelectedItem(); + int counter = Integer.parseInt(binding.inputCounter.getText().toString()); + boolean checksum = binding.inputChecksum.isChecked(); + + OTPData data = new OTPData(name, OTPType.TOTP, secret, algorithm, digits, 0, counter, checksum); + + String errorMessage = data.validate(); + if(errorMessage != null) { + showErrorDialog(errorMessage); + return false; + } + + ((DynamicFragment) fragment).addOTP(data); + return true; + }catch(NumberFormatException e) { + showErrorDialog("Invalid number entered"); + return false; + } + }); } private void showCodeDialog(View view, DialogCallback ok) { @@ -254,7 +282,17 @@ public class MainActivity extends AppCompatActivity { new AlertDialog.Builder(this) .setTitle("New Group") .setView(t) - .setPositiveButton("Add", (view, which) -> {}) + .setPositiveButton("Add", (view, which) -> { + if(t.getText().length() == 0) { + showErrorDialog("You need to input a name"); + return; + } + + Fragment frag = NavigationUtil.getCurrentFragment(this); + if(frag instanceof MenuFragment) { + ((MenuFragment) frag).addGroup(t.getText().toString()); + } + }) .setNegativeButton("Cancel", (view, which) -> {}) .show(); } diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/DynamicFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/DynamicFragment.java index be2fdbc..4ae1d46 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/DynamicFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/DynamicFragment.java @@ -22,7 +22,7 @@ import com.cringe_studios.cringe_authenticator.util.SettingsUtil; import java.util.List; -public class DynamicFragment extends Fragment { +public class DynamicFragment extends NamedFragment { public static final String BUNDLE_GROUP = "group"; @@ -36,6 +36,11 @@ public class DynamicFragment extends Fragment { private OTPListAdapter otpListAdapter; + @Override + public String getName() { + return groupName; + } + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -72,8 +77,7 @@ public class DynamicFragment extends Fragment { } private void loadOTPs() { - SharedPreferences prefs = requireActivity().getSharedPreferences(SettingsUtil.GROUPS_PREFS_NAME, Context.MODE_PRIVATE); - List data = SettingsUtil.getOTPs(prefs, groupName); + List data = SettingsUtil.getOTPs(requireContext(), groupName); for(OTPData otp : data) { otpListAdapter.add(otp); @@ -81,8 +85,7 @@ public class DynamicFragment extends Fragment { } public void addOTP(OTPData data) { - SharedPreferences prefs = requireActivity().getSharedPreferences(SettingsUtil.GROUPS_PREFS_NAME, Context.MODE_PRIVATE); - SettingsUtil.addOTP(prefs, groupName, data); + SettingsUtil.addOTP(requireContext(), groupName, data); otpListAdapter.add(data); } diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/HomeFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/HomeFragment.java index 7f1ae15..16b267d 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/HomeFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/HomeFragment.java @@ -11,10 +11,15 @@ import androidx.fragment.app.Fragment; import com.cringe_studios.cringe_authenticator.databinding.FragmentHomeBinding; import com.cringe_studios.cringe_authenticator.util.FabUtil; -public class HomeFragment extends Fragment { +public class HomeFragment extends NamedFragment { private FragmentHomeBinding binding; + @Override + public String getName() { + return "Home"; + } + @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentHomeBinding.inflate(inflater, container, false); diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java index 65a34af..5f639b8 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/MenuFragment.java @@ -3,6 +3,7 @@ package com.cringe_studios.cringe_authenticator.fragment; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -12,55 +13,71 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import com.cringe_studios.cringe_authenticator.OTPData; import com.cringe_studios.cringe_authenticator.databinding.FragmentMenuBinding; import com.cringe_studios.cringe_authenticator.databinding.MenuItemBinding; +import com.cringe_studios.cringe_authenticator.grouplist.GroupListAdapter; +import com.cringe_studios.cringe_authenticator.grouplist.GroupListItem; import com.cringe_studios.cringe_authenticator.util.FabUtil; import com.cringe_studios.cringe_authenticator.util.NavigationUtil; +import com.cringe_studios.cringe_authenticator.util.SettingsUtil; -public class MenuFragment extends Fragment { +import java.util.List; + +public class MenuFragment extends NamedFragment { private FragmentMenuBinding binding; + private GroupListAdapter groupListAdapter; + + @Override + public String getName() { + return "Menu"; + } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentMenuBinding.inflate(inflater); - SharedPreferences pr = requireContext().getSharedPreferences("menu", Context.MODE_PRIVATE); + groupListAdapter = new GroupListAdapter(requireContext(), group -> { + Bundle bundle = new Bundle(); + bundle.putString(DynamicFragment.BUNDLE_GROUP, group); + NavigationUtil.navigate(this, DynamicFragment.class, bundle); + }, this::removeGroup); - String[] items = {"a", "b"}; + binding.menuItems.setAdapter(groupListAdapter); - for(String item : items) { - MenuItemBinding itemBinding = MenuItemBinding.inflate(inflater, binding.menuItems, false); - itemBinding.button.setText(item); - itemBinding.button.setOnClickListener(view -> { - Bundle bundle = new Bundle(); - bundle.putString(DynamicFragment.BUNDLE_GROUP, item); - NavigationUtil.navigate(this, DynamicFragment.class, bundle); - }); - itemBinding.button.setOnLongClickListener(view -> { - new AlertDialog.Builder(requireContext()) - .setTitle("Delete?") - .setMessage("Delete this?") - .setPositiveButton("Yes", (dialog, which) -> itemBinding.button.setVisibility(View.GONE)) - .setNegativeButton("No", (dialog, which) -> {}) - .show(); - // TODO: better method? - // TODO: actually delete - return true; - }); - binding.menuItems.addView(itemBinding.getRoot()); - } + loadGroups(); - binding.editSwitch.setOnCheckedChangeListener((view, checked) -> { + /*binding.editSwitch.setOnCheckedChangeListener((view, checked) -> { // TODO: edit mode - }); + });*/ FabUtil.hideFabs(requireActivity()); return binding.getRoot(); } + private void loadGroups() { + List items = SettingsUtil.getGroups(requireContext()); + Log.i("AMOGUS", "items: " + items); + + for(String item : items) { + groupListAdapter.add(item); + } + } + + public void addGroup(String group) { + SettingsUtil.addGroup(requireContext(), group); + groupListAdapter.add(group); + } + + public void removeGroup(String group) { + SettingsUtil.removeGroup(requireContext(), group); + groupListAdapter.remove(group); + } + @Override public void onDestroyView() { super.onDestroyView(); diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/NamedFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/NamedFragment.java new file mode 100644 index 0000000..9dddbf0 --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/NamedFragment.java @@ -0,0 +1,9 @@ +package com.cringe_studios.cringe_authenticator.fragment; + +import androidx.fragment.app.Fragment; + +public abstract class NamedFragment extends Fragment { + + public abstract String getName(); + +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java index f3d9843..9ec41dc 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/fragment/SettingsFragment.java @@ -27,10 +27,15 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -public class SettingsFragment extends Fragment { +public class SettingsFragment extends NamedFragment { private FragmentSettingsBinding binding; + @Override + public String getName() { + return "Settings"; + } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java new file mode 100644 index 0000000..d5771eb --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListAdapter.java @@ -0,0 +1,93 @@ +package com.cringe_studios.cringe_authenticator.grouplist; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.util.Consumer; +import androidx.recyclerview.widget.RecyclerView; + +import com.cringe_studios.cringe_authenticator.OTPData; +import com.cringe_studios.cringe_authenticator.databinding.MenuItemBinding; +import com.cringe_studios.cringe_authenticator.fragment.DynamicFragment; +import com.cringe_studios.cringe_authenticator.util.NavigationUtil; +import com.cringe_studios.cringe_authenticator.util.SettingsUtil; + +import java.util.ArrayList; +import java.util.List; + +public class GroupListAdapter extends RecyclerView.Adapter { + + private Context context; + + private LayoutInflater inflater; + + private List items; + + private Handler handler; + + private Consumer navigateToGroup; + + private Consumer removeGroup; + + public GroupListAdapter(Context context, Consumer navigateToGroup, Consumer removeGroup) { + this.context = context; + this.navigateToGroup = navigateToGroup; + this.removeGroup = removeGroup; + this.inflater = LayoutInflater.from(context); + this.items = new ArrayList<>(); + this.handler = new Handler(Looper.getMainLooper()); + } + + @NonNull + @Override + public GroupListItem onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + MenuItemBinding binding = MenuItemBinding.inflate(inflater, parent, false); + return new GroupListItem(binding); + } + + @Override + public void onBindViewHolder(@NonNull GroupListItem holder, int position) { + String group = items.get(position); + + holder.getBinding().button.setText(group); + + holder.getBinding().button.setOnClickListener(view -> navigateToGroup.accept(group)); + holder.getBinding().button.setOnLongClickListener(view -> { + new AlertDialog.Builder(context) + .setTitle("Delete?") + .setMessage("Delete this?") + .setPositiveButton("Yes", (dialog, which) -> removeGroup.accept(group)) + .setNegativeButton("No", (dialog, which) -> {}) + .show(); + // TODO: better method? + // TODO: actually delete + return true; + }); + } + + @Override + public int getItemCount() { + return items.size(); + } + + public void add(String group) { + items.add(group); + notifyItemInserted(items.size() - 1); + } + + public void remove(String group) { + int index = items.indexOf(group); + if(index == -1) return; + items.remove(group); + notifyItemRemoved(index); + } + +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListItem.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListItem.java new file mode 100644 index 0000000..3e44f33 --- /dev/null +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/grouplist/GroupListItem.java @@ -0,0 +1,23 @@ +package com.cringe_studios.cringe_authenticator.grouplist; + +import android.view.MenuItem; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.cringe_studios.cringe_authenticator.databinding.MenuItemBinding; + +public class GroupListItem extends RecyclerView.ViewHolder { + + private MenuItemBinding binding; + + public GroupListItem(@NonNull MenuItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + + public MenuItemBinding getBinding() { + return binding; + } +} diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java index ee769a0..f446448 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/otplist/OTPListAdapter.java @@ -68,6 +68,7 @@ public class OTPListAdapter extends RecyclerView.Adapter { public void remove(OTPData data) { int index = items.indexOf(data); + if(index == -1) return; items.remove(data); notifyItemRemoved(index); } diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java index c53cbe4..555ef70 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/NavigationUtil.java @@ -3,28 +3,44 @@ package com.cringe_studios.cringe_authenticator.util; import android.content.Context; import android.os.Bundle; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import com.cringe_studios.cringe_authenticator.R; +import com.cringe_studios.cringe_authenticator.fragment.NamedFragment; + +import kotlin.Suppress; public class NavigationUtil { - public static void navigate(AppCompatActivity activity, Class fragmentClass, Bundle args) { - activity.getSupportActionBar().setTitle(fragmentClass.getSimpleName()); - navigate(activity.getSupportFragmentManager().getPrimaryNavigationFragment().getChildFragmentManager(), fragmentClass, args); + public static void navigate(AppCompatActivity activity, Class fragmentClass, Bundle args) { + FragmentManager manager = activity.getSupportFragmentManager().getPrimaryNavigationFragment().getChildFragmentManager(); + NamedFragment fragment = instantiateFragment(manager, fragmentClass, args); + + ActionBar bar = activity.getSupportActionBar(); + navigate(manager, fragment, () -> { + if(bar != null) bar.setTitle(fragment.getName()); + }); } - public static void navigate(Fragment currentFragment, Class fragmentClass, Bundle args) { - ((AppCompatActivity) currentFragment.getActivity()).getSupportActionBar().setTitle(fragmentClass.getSimpleName()); - navigate(currentFragment.getParentFragment().getChildFragmentManager(), fragmentClass, args); + public static void navigate(Fragment currentFragment, Class fragmentClass, Bundle args) { + navigate((AppCompatActivity) currentFragment.requireActivity(), fragmentClass, args); } - private static void navigate(FragmentManager manager, Class fragmentClass, Bundle args) { + @SuppressWarnings("unchecked") + private static T instantiateFragment(FragmentManager manager, Class fragmentClass, Bundle args) { + T fragment = (T) manager.getFragmentFactory().instantiate(ClassLoader.getSystemClassLoader(), fragmentClass.getName()); + if(args != null) fragment.setArguments(args); + return fragment; + } + + private static void navigate(FragmentManager manager, Fragment fragment, Runnable onCommit) { manager.beginTransaction() .setReorderingAllowed(true) - .replace(R.id.nav_host_fragment_content_main, fragmentClass, args) + .replace(R.id.nav_host_fragment_content_main, fragment) + .runOnCommit(onCommit) .commit(); } diff --git a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/SettingsUtil.java b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/SettingsUtil.java index 8e81b7f..2c4f3e4 100644 --- a/app/src/main/java/com/cringe_studios/cringe_authenticator/util/SettingsUtil.java +++ b/app/src/main/java/com/cringe_studios/cringe_authenticator/util/SettingsUtil.java @@ -41,21 +41,49 @@ public class SettingsUtil { private static final Gson GSON = new Gson(); - // TODO: refactor - public static List getOTPs(SharedPreferences prefs, String group) { - String currentOTPs = prefs.getString("group." + group, "[]"); + public static List getGroups(Context ctx) { + SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE); + return Arrays.asList(GSON.fromJson(prefs.getString("groups", "[]"), String[].class)); + } + + public static void addGroup(Context ctx, String group) { + List groups = new ArrayList<>(getGroups(ctx)); + groups.add(group); + + SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE); + prefs.edit().putString("groups", GSON.toJson(groups)).apply(); + } + + public static void removeGroup(Context ctx, String group) { + List groups = new ArrayList<>(getGroups(ctx)); + groups.remove(group); + + SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE); + prefs.edit().putString("groups", GSON.toJson(groups)).apply(); + + deleteOTPs(ctx, group); + } + + public static List getOTPs(Context ctx, String group) { + String currentOTPs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).getString("group." + group, "[]"); return Arrays.asList(GSON.fromJson(currentOTPs, OTPData[].class)); } - public static void addOTP(SharedPreferences prefs, String group, @NonNull OTPData data) { - List otps = new ArrayList<>(getOTPs(prefs, group)); + public static void addOTP(Context ctx, String group, @NonNull OTPData data) { + List otps = new ArrayList<>(getOTPs(ctx, group)); otps.add(data); - prefs.edit() + ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit() .putString("group." + group, GSON.toJson(otps.toArray(new OTPData[0]))) .apply(); } + private static void deleteOTPs(Context ctx, String group) { + ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit() + .remove("group." + group) + .apply(); + } + public static void setEnableIntroVideo(Context ctx, boolean enableIntroVideo) { SharedPreferences prefs = ctx.getSharedPreferences(GENERAL_PREFS_NAME, Context.MODE_PRIVATE); prefs.edit().putBoolean("enableIntroVideo", enableIntroVideo).apply(); diff --git a/app/src/main/res/layout/dialog_input_code_hotp.xml b/app/src/main/res/layout/dialog_input_code_hotp.xml new file mode 100644 index 0000000..fc45af5 --- /dev/null +++ b/app/src/main/res/layout/dialog_input_code_hotp.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_input_code_totp.xml b/app/src/main/res/layout/dialog_input_code_totp.xml index eccbf65..806c3d0 100644 --- a/app/src/main/res/layout/dialog_input_code_totp.xml +++ b/app/src/main/res/layout/dialog_input_code_totp.xml @@ -11,7 +11,8 @@ android:layout_height="wrap_content" android:ems="10" android:inputType="text" - android:hint="Name" /> + android:hint="Name" + android:autofillHints="" /> + android:hint="Secret" + android:autofillHints="" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_menu.xml b/app/src/main/res/layout/fragment_menu.xml index e001a15..98e5064 100644 --- a/app/src/main/res/layout/fragment_menu.xml +++ b/app/src/main/res/layout/fragment_menu.xml @@ -11,7 +11,7 @@ android:layout_height="match_parent" android:padding="16dp"> - - + --> + + \ No newline at end of file diff --git a/app/src/main/res/layout/menu_item.xml b/app/src/main/res/layout/menu_item.xml index a8f5d5c..57f7894 100644 --- a/app/src/main/res/layout/menu_item.xml +++ b/app/src/main/res/layout/menu_item.xml @@ -11,6 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button" - android:background="@drawable/button_themed" /> + android:background="@drawable/button_themed" + android:textAllCaps="false" /> \ No newline at end of file