Add group rename, OTP delete

This commit is contained in:
MrLetsplay 2023-07-03 20:26:55 +02:00
parent 7a82b98169
commit aa03844f3c
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
19 changed files with 163 additions and 81 deletions

View File

@ -48,7 +48,7 @@ dependencies {
implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.code.gson:gson:2.8.9'
def camerax_version = "1.2.2" def camerax_version = "1.2.3"
implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}" implementation "androidx.camera:camera-lifecycle:${camerax_version}"

View File

@ -10,7 +10,6 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Toast; import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.ActivityResultLauncher;
@ -237,23 +236,12 @@ public class MainActivity extends AppCompatActivity {
} }
public void addGroup(MenuItem item) { public void addGroup(MenuItem item) {
EditText t = new EditText(this); DialogUtil.showCreateGroupDialog(getLayoutInflater(), null, group -> {
new StyledDialogBuilder(this) Fragment frag = NavigationUtil.getCurrentFragment(this);
.setTitle(R.string.action_new_group) if(frag instanceof MenuFragment) {
.setView(t) ((MenuFragment) frag).addGroup(group);
.setPositiveButton(R.string.add, (view, which) -> { }
if(t.getText().length() == 0) { });
DialogUtil.showErrorDialog(this, getString(R.string.new_group_missing_title));
return;
}
Fragment frag = NavigationUtil.getCurrentFragment(this);
if(frag instanceof MenuFragment) {
((MenuFragment) frag).addGroup(t.getText().toString());
}
})
.setNegativeButton(R.string.cancel, (view, which) -> {})
.show();
} }
@Override @Override

View File

@ -10,9 +10,9 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.R; import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.databinding.FragmentGroupBinding; import com.cringe_studios.cringe_authenticator.databinding.FragmentGroupBinding;
import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.cringe_studios.cringe_authenticator.otplist.OTPListAdapter; import com.cringe_studios.cringe_authenticator.otplist.OTPListAdapter;
import com.cringe_studios.cringe_authenticator.otplist.OTPListItem; import com.cringe_studios.cringe_authenticator.otplist.OTPListItem;
import com.cringe_studios.cringe_authenticator.util.DialogUtil; import com.cringe_studios.cringe_authenticator.util.DialogUtil;
@ -28,7 +28,7 @@ public class GroupFragment extends NamedFragment {
public static final String BUNDLE_GROUP = "group"; public static final String BUNDLE_GROUP = "group";
private String groupName; private String groupID;
private FragmentGroupBinding binding; private FragmentGroupBinding binding;
@ -40,7 +40,7 @@ public class GroupFragment extends NamedFragment {
@Override @Override
public String getName() { public String getName() {
return groupName; return SettingsUtil.getGroupName(requireContext(), groupID);
} }
@Override @Override
@ -53,7 +53,7 @@ public class GroupFragment extends NamedFragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentGroupBinding.inflate(inflater, container, false); binding = FragmentGroupBinding.inflate(inflater, container, false);
groupName = requireArguments().getString(GroupFragment.BUNDLE_GROUP); groupID = requireArguments().getString(GroupFragment.BUNDLE_GROUP);
FabUtil.showFabs(requireActivity()); FabUtil.showFabs(requireActivity());
@ -90,8 +90,8 @@ public class GroupFragment extends NamedFragment {
break; break;
case 2: case 2:
new StyledDialogBuilder(requireContext()) new StyledDialogBuilder(requireContext())
.setTitle("Delete?") .setTitle(R.string.otp_delete_title)
.setMessage("Delete this?") .setMessage(R.string.otp_delete_message)
.setPositiveButton(R.string.yes, (d, w) -> { .setPositiveButton(R.string.yes, (d, w) -> {
otpListAdapter.remove(data); otpListAdapter.remove(data);
saveOTPs(); saveOTPs();
@ -103,30 +103,15 @@ public class GroupFragment extends NamedFragment {
}) })
.setNegativeButton(R.string.cancel, (dialog, which) -> {}) .setNegativeButton(R.string.cancel, (dialog, which) -> {})
.show(); .show();
/*switch(data.getType()) {
case HOTP:
DialogUtil.showHOTPDialog(getLayoutInflater(), data, newData -> {
otpListAdapter.replace(data, newData);
saveOTPs();
});
break;
case TOTP:
DialogUtil.showTOTPDialog(getLayoutInflater(), data, newData -> {
otpListAdapter.replace(data, newData);
saveOTPs();
});
break;
}*/
} }
private void saveOTPs() { private void saveOTPs() {
SettingsUtil.updateOTPs(requireContext(), groupName, otpListAdapter.getItems()); SettingsUtil.updateOTPs(requireContext(), groupID, otpListAdapter.getItems());
refreshCodes(); refreshCodes();
} }
private void loadOTPs() { private void loadOTPs() {
List<OTPData> data = SettingsUtil.getOTPs(requireContext(), groupName); List<OTPData> data = SettingsUtil.getOTPs(requireContext(), groupID);
for(OTPData otp : data) { for(OTPData otp : data) {
otpListAdapter.add(otp); otpListAdapter.add(otp);
@ -134,7 +119,7 @@ public class GroupFragment extends NamedFragment {
} }
public void addOTP(OTPData data) { public void addOTP(OTPData data) {
SettingsUtil.addOTP(requireContext(), groupName, data); SettingsUtil.addOTP(requireContext(), groupID, data);
otpListAdapter.add(data); otpListAdapter.add(data);
} }

View File

@ -8,13 +8,17 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.databinding.FragmentMenuBinding; import com.cringe_studios.cringe_authenticator.databinding.FragmentMenuBinding;
import com.cringe_studios.cringe_authenticator.grouplist.GroupListAdapter; import com.cringe_studios.cringe_authenticator.grouplist.GroupListAdapter;
import com.cringe_studios.cringe_authenticator.util.DialogUtil;
import com.cringe_studios.cringe_authenticator.util.FabUtil; import com.cringe_studios.cringe_authenticator.util.FabUtil;
import com.cringe_studios.cringe_authenticator.util.NavigationUtil; import com.cringe_studios.cringe_authenticator.util.NavigationUtil;
import com.cringe_studios.cringe_authenticator.util.SettingsUtil; import com.cringe_studios.cringe_authenticator.util.SettingsUtil;
import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder;
import java.util.List; import java.util.List;
import java.util.UUID;
public class MenuFragment extends NamedFragment { public class MenuFragment extends NamedFragment {
@ -36,21 +40,42 @@ public class MenuFragment extends NamedFragment {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(GroupFragment.BUNDLE_GROUP, group); bundle.putString(GroupFragment.BUNDLE_GROUP, group);
NavigationUtil.navigate(this, GroupFragment.class, bundle); NavigationUtil.navigate(this, GroupFragment.class, bundle);
}, this::removeGroup); }, this::showGroupDialog);
binding.menuItems.setAdapter(groupListAdapter); binding.menuItems.setAdapter(groupListAdapter);
loadGroups(); loadGroups();
/*binding.editSwitch.setOnCheckedChangeListener((view, checked) -> {
// TODO: edit mode
});*/
FabUtil.hideFabs(requireActivity()); FabUtil.hideFabs(requireActivity());
return binding.getRoot(); return binding.getRoot();
} }
private void showGroupDialog(String group) {
new StyledDialogBuilder(requireContext())
.setTitle(R.string.edit_group_title)
.setItems(R.array.rename_delete, (dialog, which) -> {
switch(which) {
case 0:
DialogUtil.showCreateGroupDialog(getLayoutInflater(), SettingsUtil.getGroupName(requireContext(), group), newName -> {
renameGroup(group, newName);
});
break;
case 1:
new StyledDialogBuilder(requireContext())
.setTitle(R.string.group_delete_title)
.setMessage(R.string.group_delete_message)
.setPositiveButton(R.string.yes, (d, w) -> removeGroup(group))
.setNegativeButton(R.string.no, (d, w) -> {})
.show();
break;
}
})
.setNegativeButton(R.string.cancel, (dialog, which) -> {})
.show();
}
private void loadGroups() { private void loadGroups() {
List<String> items = SettingsUtil.getGroups(requireContext()); List<String> items = SettingsUtil.getGroups(requireContext());
@ -59,9 +84,10 @@ public class MenuFragment extends NamedFragment {
} }
} }
public void addGroup(String group) { public void addGroup(String groupName) {
SettingsUtil.addGroup(requireContext(), group); String id = UUID.randomUUID().toString();
groupListAdapter.add(group); SettingsUtil.addGroup(requireContext(), id, groupName);
groupListAdapter.add(id);
} }
public void removeGroup(String group) { public void removeGroup(String group) {
@ -69,6 +95,11 @@ public class MenuFragment extends NamedFragment {
groupListAdapter.remove(group); groupListAdapter.remove(group);
} }
public void renameGroup(String group, String newName) {
SettingsUtil.setGroupName(requireContext(), group, newName);
groupListAdapter.update(group);
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
super.onDestroyView(); super.onDestroyView();

View File

@ -10,9 +10,8 @@ import androidx.annotation.NonNull;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.databinding.MenuItemBinding; import com.cringe_studios.cringe_authenticator.databinding.MenuItemBinding;
import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder; import com.cringe_studios.cringe_authenticator.util.SettingsUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -29,12 +28,12 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
private Consumer<String> navigateToGroup; private Consumer<String> navigateToGroup;
private Consumer<String> removeGroup; private Consumer<String> showMenuCallback;
public GroupListAdapter(Context context, Consumer<String> navigateToGroup, Consumer<String> removeGroup) { public GroupListAdapter(Context context, Consumer<String> navigateToGroup, Consumer<String> showMenuCallback) {
this.context = context; this.context = context;
this.navigateToGroup = navigateToGroup; this.navigateToGroup = navigateToGroup;
this.removeGroup = removeGroup; this.showMenuCallback = showMenuCallback;
this.inflater = LayoutInflater.from(context); this.inflater = LayoutInflater.from(context);
this.items = new ArrayList<>(); this.items = new ArrayList<>();
this.handler = new Handler(Looper.getMainLooper()); this.handler = new Handler(Looper.getMainLooper());
@ -51,17 +50,11 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
public void onBindViewHolder(@NonNull GroupListItem holder, int position) { public void onBindViewHolder(@NonNull GroupListItem holder, int position) {
String group = items.get(position); String group = items.get(position);
holder.getBinding().button.setText(group); holder.getBinding().button.setText(SettingsUtil.getGroupName(context, group));
holder.getBinding().button.setOnClickListener(view -> navigateToGroup.accept(group)); holder.getBinding().button.setOnClickListener(view -> navigateToGroup.accept(group));
holder.getBinding().button.setOnLongClickListener(view -> { holder.getBinding().button.setOnLongClickListener(view -> {
new StyledDialogBuilder(context) showMenuCallback.accept(group);
.setTitle(R.string.group_delete_title)
.setMessage(R.string.group_delete_message)
.setPositiveButton(R.string.yes, (dialog, which) -> removeGroup.accept(group))
.setNegativeButton(R.string.no, (dialog, which) -> {})
.show();
// TODO: better method?
return true; return true;
}); });
} }
@ -83,4 +76,10 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
notifyItemRemoved(index); notifyItemRemoved(index);
} }
public void update(String group) {
int index = items.indexOf(group);
if(index == -1) return;
notifyItemChanged(index);
}
} }

View File

@ -1,4 +1,4 @@
package com.cringe_studios.cringe_authenticator; package com.cringe_studios.cringe_authenticator.model;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;

View File

@ -12,9 +12,9 @@ import androidx.annotation.NonNull;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.R; import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.databinding.OtpCodeBinding; import com.cringe_studios.cringe_authenticator.databinding.OtpCodeBinding;
import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.cringe_studios.cringe_authenticator_library.OTPException; import com.cringe_studios.cringe_authenticator_library.OTPException;
import com.cringe_studios.cringe_authenticator_library.OTPType; import com.cringe_studios.cringe_authenticator_library.OTPType;

View File

@ -3,8 +3,8 @@ package com.cringe_studios.cringe_authenticator.otplist;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.databinding.OtpCodeBinding; import com.cringe_studios.cringe_authenticator.databinding.OtpCodeBinding;
import com.cringe_studios.cringe_authenticator.model.OTPData;
public class OTPListItem extends RecyclerView.ViewHolder { public class OTPListItem extends RecyclerView.ViewHolder {

View File

@ -27,8 +27,8 @@ import androidx.camera.core.SurfaceOrientedMeteringPointFactory;
import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.databinding.ActivityQrScannerBinding; import com.cringe_studios.cringe_authenticator.databinding.ActivityQrScannerBinding;
import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.cringe_studios.cringe_authenticator.util.OTPParser; import com.cringe_studios.cringe_authenticator.util.OTPParser;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.vision.barcode.BarcodeScanner; import com.google.mlkit.vision.barcode.BarcodeScanner;

View File

@ -8,7 +8,7 @@ import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.cringe_studios.cringe_authenticator.OTPData; import com.cringe_studios.cringe_authenticator.model.OTPData;
public class QRScannerContract extends ActivityResultContract<Void, ScannerResult> { public class QRScannerContract extends ActivityResultContract<Void, ScannerResult> {

View File

@ -3,7 +3,7 @@ package com.cringe_studios.cringe_authenticator.scanner;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.cringe_studios.cringe_authenticator.OTPData; import com.cringe_studios.cringe_authenticator.model.OTPData;
public class ScannerResult { public class ScannerResult {

View File

@ -8,8 +8,8 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.R; import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.cringe_studios.cringe_authenticator.util.OTPParser; import com.cringe_studios.cringe_authenticator.util.OTPParser;
import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder; import com.cringe_studios.cringe_authenticator.util.StyledDialogBuilder;

View File

@ -0,0 +1,7 @@
package com.cringe_studios.cringe_authenticator.util;
public interface BiConsumer<T, U> {
public void accept(T t, U u);
}

View File

@ -10,10 +10,11 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.R; import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.databinding.DialogCreateGroupBinding;
import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeHotpBinding; import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeHotpBinding;
import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeTotpBinding; import com.cringe_studios.cringe_authenticator.databinding.DialogInputCodeTotpBinding;
import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm; import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
import com.cringe_studios.cringe_authenticator_library.OTPType; import com.cringe_studios.cringe_authenticator_library.OTPType;
@ -169,4 +170,34 @@ public class DialogUtil {
case TOTP: showTOTPDialog(inflater, initialData, callback, back, false); break; case TOTP: showTOTPDialog(inflater, initialData, callback, back, false); break;
} }
} }
public static void showCreateGroupDialog(LayoutInflater inflater, String initialName, Consumer<String> callback) {
Context context = inflater.getContext();
DialogCreateGroupBinding binding = DialogCreateGroupBinding.inflate(inflater);
binding.createGroupName.setText(initialName);
AlertDialog dialog = new StyledDialogBuilder(context)
.setTitle(R.string.action_new_group)
.setView(binding.getRoot())
.setPositiveButton(R.string.add, (view, which) -> {})
.setNegativeButton(R.string.cancel, (view, which) -> {})
.create();
dialog.setOnShowListener(d -> {
Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
okButton.setOnClickListener(v -> {
if(binding.createGroupName.getText().length() == 0) {
DialogUtil.showErrorDialog(context, context.getString(R.string.new_group_missing_title));
return;
}
dialog.dismiss();
callback.accept(binding.createGroupName.getText().toString());
});
});
dialog.show();
}
} }

View File

@ -2,7 +2,7 @@ package com.cringe_studios.cringe_authenticator.util;
import android.net.Uri; import android.net.Uri;
import com.cringe_studios.cringe_authenticator.OTPData; import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm; import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
import com.cringe_studios.cringe_authenticator_library.OTPType; import com.cringe_studios.cringe_authenticator_library.OTPType;

View File

@ -5,8 +5,8 @@ import android.content.SharedPreferences;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.cringe_studios.cringe_authenticator.OTPData;
import com.cringe_studios.cringe_authenticator.R; import com.cringe_studios.cringe_authenticator.R;
import com.cringe_studios.cringe_authenticator.model.OTPData;
import com.google.gson.Gson; import com.google.gson.Gson;
import java.util.ArrayList; import java.util.ArrayList;
@ -44,12 +44,14 @@ public class SettingsUtil {
return Arrays.asList(GSON.fromJson(prefs.getString("groups", "[]"), String[].class)); return Arrays.asList(GSON.fromJson(prefs.getString("groups", "[]"), String[].class));
} }
public static void addGroup(Context ctx, String group) { public static void addGroup(Context ctx, String group, String groupName) {
List<String> groups = new ArrayList<>(getGroups(ctx)); List<String> groups = new ArrayList<>(getGroups(ctx));
groups.add(group); groups.add(group);
SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE); SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE);
prefs.edit().putString("groups", GSON.toJson(groups)).apply(); prefs.edit().putString("groups", GSON.toJson(groups)).apply();
setGroupName(ctx, group, groupName);
} }
public static void removeGroup(Context ctx, String group) { public static void removeGroup(Context ctx, String group) {
@ -59,32 +61,45 @@ public class SettingsUtil {
SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE); SharedPreferences prefs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE);
prefs.edit().putString("groups", GSON.toJson(groups)).apply(); prefs.edit().putString("groups", GSON.toJson(groups)).apply();
deleteOTPs(ctx, group); deleteGroupData(ctx, group);
} }
public static List<OTPData> getOTPs(Context ctx, String group) { public static List<OTPData> getOTPs(Context ctx, String group) {
String currentOTPs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).getString("group." + group, "[]"); String currentOTPs = ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).getString("group." + group + ".otps", "[]");
return Arrays.asList(GSON.fromJson(currentOTPs, OTPData[].class)); return Arrays.asList(GSON.fromJson(currentOTPs, OTPData[].class));
} }
public static void addOTP(Context ctx, String group, @NonNull OTPData data) { public static void addOTP(Context ctx, String group, @NonNull OTPData data) {
// TODO: check for code with same name
List<OTPData> otps = new ArrayList<>(getOTPs(ctx, group)); List<OTPData> otps = new ArrayList<>(getOTPs(ctx, group));
otps.add(data); otps.add(data);
ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit() ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit()
.putString("group." + group, GSON.toJson(otps.toArray(new OTPData[0]))) .putString("group." + group + ".otps", GSON.toJson(otps.toArray(new OTPData[0])))
.apply(); .apply();
} }
public static void updateOTPs(Context ctx, String group, List<OTPData> otps) { public static void updateOTPs(Context ctx, String group, List<OTPData> otps) {
ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit() ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit()
.putString("group." + group, GSON.toJson(otps.toArray(new OTPData[0]))) .putString("group." + group + ".otps", GSON.toJson(otps.toArray(new OTPData[0])))
.apply(); .apply();
} }
private static void deleteOTPs(Context ctx, String group) { public static String getGroupName(Context ctx, String group) {
return ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).getString("group." + group + ".name", group);
}
public static void setGroupName(Context ctx, String group, String name) {
ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit() ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit()
.remove("group." + group) .putString("group." + group + ".name", name)
.apply();
}
private static void deleteGroupData(Context ctx, String group) {
ctx.getSharedPreferences(GROUPS_PREFS_NAME, Context.MODE_PRIVATE).edit()
.remove("group." + group + ".otps")
.remove("group." + group + ".name")
.apply(); .apply();
} }

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/create_group_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:ems="10"
android:inputType="text"
android:text="Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -31,6 +31,9 @@
<string name="failed_title">Aktion fehlgeschlagen</string> <string name="failed_title">Aktion fehlgeschlagen</string>
<string name="input_code_invalid_number">Ungültige Zahl</string> <string name="input_code_invalid_number">Ungültige Zahl</string>
<string name="back">Zurück</string> <string name="back">Zurück</string>
<string name="otp_delete_title">Löschen?</string>
<string name="otp_delete_message">OTP löschen?</string>
<string name="edit_group_title">Gruppe bearbeiten</string>
<string-array name="view_edit_delete"> <string-array name="view_edit_delete">
<item>Anzeigen</item> <item>Anzeigen</item>
<item>Bearbeiten</item> <item>Bearbeiten</item>

View File

@ -71,6 +71,9 @@
<string name="failed_title">Action failed</string> <string name="failed_title">Action failed</string>
<string name="input_code_invalid_number">Invalid number entered</string> <string name="input_code_invalid_number">Invalid number entered</string>
<string name="back">Back</string> <string name="back">Back</string>
<string name="otp_delete_title">Delete?</string>
<string name="otp_delete_message">Delete this?</string>
<string name="edit_group_title">Edit Group</string>
<string-array name="view_edit_delete"> <string-array name="view_edit_delete">
<item>View</item> <item>View</item>
<item>Edit</item> <item>Edit</item>