Rework OTP editing (WIP)
This commit is contained in:
parent
041513fb30
commit
82cc4760cf
@ -167,6 +167,13 @@ public class MainActivity extends BaseActivity {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(fragment instanceof GroupFragment) {
|
||||
GroupFragment frag = (GroupFragment) fragment;
|
||||
getMenuInflater().inflate(frag.isEditing() ? R.menu.menu_otps_edit : R.menu.menu_otps, menu);
|
||||
if(frag.isEditing() && frag.hasSelectedMultipleItems()) menu.removeItem(R.id.action_edit_group);
|
||||
return true;
|
||||
}
|
||||
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
return true;
|
||||
}
|
||||
@ -197,6 +204,14 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
if(fragment instanceof GroupFragment) {
|
||||
GroupFragment groupFragment = (GroupFragment) fragment;
|
||||
if(groupFragment.isEditing()) {
|
||||
groupFragment.finishEditing();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!(fragment instanceof HomeFragment)) {
|
||||
NavigationUtil.navigate(this, HomeFragment.class, null);
|
||||
}
|
||||
@ -256,7 +271,7 @@ public class MainActivity extends BaseActivity {
|
||||
if(!(fragment instanceof GroupFragment)) return;
|
||||
|
||||
((GroupFragment) fragment).addOTP(data);
|
||||
}, () -> inputCode(), false);
|
||||
}, false);
|
||||
}
|
||||
|
||||
private void showHOTPDialog() {
|
||||
@ -265,7 +280,7 @@ public class MainActivity extends BaseActivity {
|
||||
if(!(fragment instanceof GroupFragment)) return;
|
||||
|
||||
((GroupFragment) fragment).addOTP(data);
|
||||
}, () -> inputCode(), false);
|
||||
}, false);
|
||||
}
|
||||
|
||||
public void addGroup(MenuItem item) {
|
||||
@ -289,6 +304,41 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
public void addOTP(MenuItem item) {
|
||||
Fragment frag = NavigationUtil.getCurrentFragment(this);
|
||||
if(frag instanceof GroupFragment) {
|
||||
((GroupFragment) frag).addOTP();
|
||||
}
|
||||
}
|
||||
|
||||
public void viewOTP(MenuItem item) {
|
||||
Fragment frag = NavigationUtil.getCurrentFragment(this);
|
||||
if(frag instanceof GroupFragment) {
|
||||
((GroupFragment) frag).viewOTP();
|
||||
}
|
||||
}
|
||||
|
||||
public void editOTP(MenuItem item) {
|
||||
Fragment frag = NavigationUtil.getCurrentFragment(this);
|
||||
if(frag instanceof GroupFragment) {
|
||||
((GroupFragment) frag).editOTP();
|
||||
}
|
||||
}
|
||||
|
||||
public void moveOTP(MenuItem item) {
|
||||
Fragment frag = NavigationUtil.getCurrentFragment(this);
|
||||
if(frag instanceof GroupFragment) {
|
||||
((GroupFragment) frag).moveOTP();
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteOTP(MenuItem item) {
|
||||
Fragment frag = NavigationUtil.getCurrentFragment(this);
|
||||
if(frag instanceof GroupFragment) {
|
||||
((GroupFragment) frag).deleteOTP();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
@ -5,6 +5,7 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@ -16,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.cringe_studios.cringe_authenticator.R;
|
||||
import com.cringe_studios.cringe_authenticator.crypto.CryptoException;
|
||||
import com.cringe_studios.cringe_authenticator.databinding.FragmentGroupBinding;
|
||||
import com.cringe_studios.cringe_authenticator.grouplist.GroupListItem;
|
||||
import com.cringe_studios.cringe_authenticator.model.OTPData;
|
||||
import com.cringe_studios.cringe_authenticator.otplist.OTPListAdapter;
|
||||
import com.cringe_studios.cringe_authenticator.otplist.OTPListItem;
|
||||
@ -63,8 +65,7 @@ public class GroupFragment extends NamedFragment {
|
||||
|
||||
FabUtil.showFabs(requireActivity());
|
||||
|
||||
otpListAdapter = new OTPListAdapter(requireContext(), data -> showOTPDialog(data));
|
||||
|
||||
otpListAdapter = new OTPListAdapter(requireContext(), binding.itemList);
|
||||
binding.itemList.setAdapter(otpListAdapter);
|
||||
|
||||
loadOTPs();
|
||||
@ -80,52 +81,6 @@ public class GroupFragment extends NamedFragment {
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void showOTPDialog(OTPData data) {
|
||||
new StyledDialogBuilder(requireContext())
|
||||
.setTitle(R.string.edit_otp_title)
|
||||
.setItems(R.array.view_edit_move_delete, (dialog, which) -> {
|
||||
switch(which) {
|
||||
case 0:
|
||||
DialogUtil.showViewCodeDialog(getLayoutInflater(), data, () -> showOTPDialog(data));
|
||||
break;
|
||||
case 1:
|
||||
DialogUtil.showEditCodeDialog(getLayoutInflater(), data, newData -> {
|
||||
otpListAdapter.replace(data, newData);
|
||||
saveOTPs();
|
||||
}, () -> showOTPDialog(data));
|
||||
break;
|
||||
case 2:
|
||||
DialogUtil.showChooseGroupDialog(requireContext(), group -> {
|
||||
OTPDatabase.promptLoadDatabase(requireActivity(), () -> {
|
||||
try {
|
||||
OTPDatabase.getLoadedDatabase().addOTP(group, data);
|
||||
OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext()));
|
||||
otpListAdapter.remove(data);
|
||||
saveOTPs();
|
||||
} catch (OTPDatabaseException | CryptoException e) {
|
||||
DialogUtil.showErrorDialog(requireContext(), e.toString());
|
||||
}
|
||||
}, null);
|
||||
saveOTPs();
|
||||
}, null);
|
||||
break;
|
||||
case 3:
|
||||
new StyledDialogBuilder(requireContext())
|
||||
.setTitle(R.string.otp_delete_title)
|
||||
.setMessage(R.string.otp_delete_message)
|
||||
.setPositiveButton(R.string.yes, (d, w) -> {
|
||||
otpListAdapter.remove(data);
|
||||
saveOTPs();
|
||||
})
|
||||
.setNegativeButton(R.string.no, (d, w) -> {})
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (dialog, which) -> {})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void saveOTPs() {
|
||||
OTPDatabase.promptLoadDatabase(requireActivity(), () -> {
|
||||
try {
|
||||
@ -178,6 +133,89 @@ public class GroupFragment extends NamedFragment {
|
||||
}
|
||||
}
|
||||
|
||||
public void addOTP() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void viewOTP() {
|
||||
if(!otpListAdapter.isEditing()) return;
|
||||
|
||||
List<OTPListItem> items = otpListAdapter.getSelectedCodes();
|
||||
if(items.size() != 1) return;
|
||||
|
||||
OTPData data = items.get(0).getOTPData();
|
||||
DialogUtil.showViewCodeDialog(getLayoutInflater(), data);
|
||||
}
|
||||
|
||||
public void editOTP() {
|
||||
if(!otpListAdapter.isEditing()) return;
|
||||
|
||||
List<OTPListItem> items = otpListAdapter.getSelectedCodes();
|
||||
if(items.size() != 1) return;
|
||||
|
||||
OTPData data = items.get(0).getOTPData();
|
||||
DialogUtil.showEditCodeDialog(getLayoutInflater(), data, newData -> {
|
||||
otpListAdapter.replace(data, newData);
|
||||
saveOTPs();
|
||||
otpListAdapter.finishEditing();
|
||||
});
|
||||
}
|
||||
|
||||
public void moveOTP() {
|
||||
if(!otpListAdapter.isEditing()) return;
|
||||
|
||||
List<OTPListItem> items = otpListAdapter.getSelectedCodes();
|
||||
|
||||
DialogUtil.showChooseGroupDialog(requireContext(), group -> {
|
||||
OTPDatabase.promptLoadDatabase(requireActivity(), () -> {
|
||||
try {
|
||||
for(OTPListItem item : items) {
|
||||
OTPData data = item.getOTPData();
|
||||
OTPDatabase.getLoadedDatabase().addOTP(group, data);
|
||||
OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext()));
|
||||
otpListAdapter.remove(data);
|
||||
}
|
||||
|
||||
saveOTPs();
|
||||
} catch (OTPDatabaseException | CryptoException e) {
|
||||
DialogUtil.showErrorDialog(requireContext(), e.toString());
|
||||
}
|
||||
}, null);
|
||||
saveOTPs();
|
||||
}, null);
|
||||
}
|
||||
|
||||
public void deleteOTP() {
|
||||
if(!otpListAdapter.isEditing()) return;
|
||||
|
||||
List<OTPListItem> items = otpListAdapter.getSelectedCodes();
|
||||
|
||||
new StyledDialogBuilder(requireContext())
|
||||
.setTitle(R.string.otp_delete_title)
|
||||
.setMessage(R.string.otp_delete_message)
|
||||
.setPositiveButton(R.string.yes, (d, w) -> {
|
||||
for(OTPListItem item : items) {
|
||||
otpListAdapter.remove(item.getOTPData());
|
||||
}
|
||||
|
||||
saveOTPs();
|
||||
})
|
||||
.setNegativeButton(R.string.no, (d, w) -> {})
|
||||
.show();
|
||||
}
|
||||
|
||||
public boolean isEditing() {
|
||||
return otpListAdapter.isEditing();
|
||||
}
|
||||
|
||||
public void finishEditing() {
|
||||
otpListAdapter.finishEditing();
|
||||
}
|
||||
|
||||
public boolean hasSelectedMultipleItems() {
|
||||
return otpListAdapter.getSelectedCodes().size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
@ -54,31 +54,6 @@ public class MenuFragment extends NamedFragment {
|
||||
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);
|
||||
}, null);
|
||||
|
||||
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() {
|
||||
List<String> items = SettingsUtil.getGroups(requireContext());
|
||||
|
||||
@ -114,7 +89,7 @@ public class MenuFragment extends NamedFragment {
|
||||
|
||||
new StyledDialogBuilder(requireContext())
|
||||
.setTitle(R.string.group_delete_title)
|
||||
.setMessage("Delete selected groups?")
|
||||
.setMessage(R.string.group_delete_message)
|
||||
.setPositiveButton(R.string.yes, (d, w) -> {
|
||||
for(GroupListItem item : groupListAdapter.getSelectedGroups()) {
|
||||
removeGroup(item.getGroupId());
|
||||
|
@ -68,6 +68,7 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
|
||||
String group = items.get(position);
|
||||
|
||||
holder.setGroupId(group);
|
||||
holder.setSelected(false);
|
||||
|
||||
holder.getBinding().button.setText(SettingsUtil.getGroupName(context, group));
|
||||
|
||||
@ -80,10 +81,6 @@ public class GroupListAdapter extends RecyclerView.Adapter<GroupListItem> {
|
||||
((BaseActivity) context).invalidateMenu();
|
||||
}
|
||||
});
|
||||
/*holder.getBinding().button.setOnLongClickListener(view -> {
|
||||
showMenuCallback.accept(group);
|
||||
return true;
|
||||
});*/
|
||||
|
||||
holder.getBinding().button.setOnLongClickListener(view -> {
|
||||
if(editing) return true;
|
||||
|
@ -40,7 +40,7 @@ public class GroupListItem extends RecyclerView.ViewHolder {
|
||||
this.selected = selected;
|
||||
|
||||
if(selected) {
|
||||
binding.menuItemBackground.setBackground(new ColorDrawable(0xFFFF00FF));
|
||||
binding.menuItemBackground.setBackground(new ColorDrawable(binding.getRoot().getContext().getResources().getColor(R.color.selected_highlight)));
|
||||
}else {
|
||||
binding.menuItemBackground.setBackground(null);
|
||||
}
|
||||
|
@ -11,8 +11,10 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.BaseActivity;
|
||||
import com.cringe_studios.cringe_authenticator.R;
|
||||
import com.cringe_studios.cringe_authenticator.databinding.OtpCodeBinding;
|
||||
import com.cringe_studios.cringe_authenticator.model.OTPData;
|
||||
@ -21,26 +23,29 @@ import com.cringe_studios.cringe_authenticator_library.OTPException;
|
||||
import com.cringe_studios.cringe_authenticator_library.OTPType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class OTPListAdapter extends RecyclerView.Adapter<OTPListItem> {
|
||||
|
||||
private Context context;
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
private LayoutInflater inflater;
|
||||
|
||||
private List<OTPData> items;
|
||||
|
||||
private Handler handler;
|
||||
|
||||
private Consumer<OTPData> showMenuCallback;
|
||||
private boolean editing;
|
||||
|
||||
public OTPListAdapter(Context context, Consumer<OTPData> showMenuCallback) {
|
||||
public OTPListAdapter(Context context, RecyclerView recyclerView) {
|
||||
this.context = context;
|
||||
this.recyclerView = recyclerView;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.items = new ArrayList<>();
|
||||
this.handler = new Handler(Looper.getMainLooper());
|
||||
this.showMenuCallback = showMenuCallback;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -55,32 +60,44 @@ public class OTPListAdapter extends RecyclerView.Adapter<OTPListItem> {
|
||||
OTPData data = items.get(position);
|
||||
|
||||
holder.setOTPData(data);
|
||||
holder.setSelected(false);
|
||||
|
||||
holder.getBinding().label.setText(String.format("%s%s", data.getIssuer() == null || data.getIssuer().isEmpty() ? "" : data.getIssuer() + ": ", data.getName()));
|
||||
holder.getBinding().progress.setVisibility(data.getType() == OTPType.TOTP ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
holder.getBinding().getRoot().setOnClickListener(view -> {
|
||||
if(!view.isClickable()) return;
|
||||
if(!editing) {
|
||||
if (!view.isClickable()) return;
|
||||
|
||||
if(data.getType() != OTPType.HOTP) return;
|
||||
if (data.getType() != OTPType.HOTP) return;
|
||||
|
||||
// Click delay for HOTP
|
||||
view.setClickable(false);
|
||||
data.incrementCounter();
|
||||
// Click delay for HOTP
|
||||
view.setClickable(false);
|
||||
data.incrementCounter();
|
||||
|
||||
try {
|
||||
holder.getBinding().otpCode.setText(OTPListItem.formatCode(data.getPin()));
|
||||
}catch(OTPException e) {
|
||||
DialogUtil.showErrorDialog(context, context.getString(R.string.otp_add_error, e.getMessage() != null ? e.getMessage() : e.toString()));
|
||||
return;
|
||||
try {
|
||||
holder.getBinding().otpCode.setText(OTPListItem.formatCode(data.getPin()));
|
||||
} catch (OTPException e) {
|
||||
DialogUtil.showErrorDialog(context, context.getString(R.string.otp_add_error, e.getMessage() != null ? e.getMessage() : e.toString()));
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(view.getContext(), R.string.hotp_generated_new_code, Toast.LENGTH_SHORT).show();
|
||||
|
||||
handler.postDelayed(() -> view.setClickable(true), 5000);
|
||||
}else {
|
||||
holder.setSelected(!holder.isSelected());
|
||||
if(getSelectedCodes().isEmpty()) editing = false;
|
||||
((BaseActivity) context).invalidateMenu();
|
||||
}
|
||||
|
||||
Toast.makeText(view.getContext(), R.string.hotp_generated_new_code, Toast.LENGTH_SHORT).show();
|
||||
|
||||
handler.postDelayed(() -> view.setClickable(true), 5000);
|
||||
});
|
||||
|
||||
holder.getBinding().getRoot().setOnLongClickListener(view -> {
|
||||
showMenuCallback.accept(holder.getOTPData());
|
||||
if(editing) return true;
|
||||
|
||||
holder.setSelected(true);
|
||||
editing = true;
|
||||
((BaseActivity) context).invalidateMenu();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -113,4 +130,59 @@ public class OTPListAdapter extends RecyclerView.Adapter<OTPListItem> {
|
||||
notifyItemRemoved(index);
|
||||
}
|
||||
|
||||
public boolean isEditing() {
|
||||
return editing;
|
||||
}
|
||||
|
||||
public void finishEditing() {
|
||||
if(!editing) return;
|
||||
|
||||
editing = false;
|
||||
for(OTPListItem item : getSelectedCodes()) {
|
||||
item.setSelected(false);
|
||||
}
|
||||
|
||||
((BaseActivity) context).invalidateMenu();
|
||||
}
|
||||
|
||||
public List<OTPListItem> getSelectedCodes() {
|
||||
if(!editing) return Collections.emptyList();
|
||||
|
||||
List<OTPListItem> selected = new ArrayList<>();
|
||||
for(int i = 0; i < items.size(); i++) {
|
||||
OTPListItem vh = (OTPListItem) recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if(vh == null) continue;
|
||||
if(vh.isSelected()) selected.add(vh);
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
private void attachTouchHelper(RecyclerView view) {
|
||||
new ItemTouchHelper(new OTPListAdapter.TouchHelperCallback()).attachToRecyclerView(view);
|
||||
}
|
||||
|
||||
private class TouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
|
||||
Collections.swap(items, viewHolder.getAdapterPosition(), target.getAdapterPosition());
|
||||
notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
|
||||
//saveGroups.run();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return editing;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
package com.cringe_studios.cringe_authenticator.otplist;
|
||||
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cringe_studios.cringe_authenticator.R;
|
||||
import com.cringe_studios.cringe_authenticator.databinding.OtpCodeBinding;
|
||||
import com.cringe_studios.cringe_authenticator.model.OTPData;
|
||||
|
||||
@ -12,6 +15,8 @@ public class OTPListItem extends RecyclerView.ViewHolder {
|
||||
|
||||
private OTPData otpData;
|
||||
|
||||
private boolean selected;
|
||||
|
||||
public OTPListItem(OtpCodeBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
@ -43,4 +48,18 @@ public class OTPListItem extends RecyclerView.ViewHolder {
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
|
||||
if(selected) {
|
||||
binding.otpCodeBackground.setBackground(new ColorDrawable(binding.getRoot().getContext().getResources().getColor(R.color.selected_highlight)));
|
||||
}else {
|
||||
binding.otpCodeBackground.setBackground(null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,12 +28,11 @@ public class DialogUtil {
|
||||
|
||||
private static final Integer[] DIGITS = new Integer[]{6, 7, 8, 9, 10, 11, 12};
|
||||
|
||||
private static void showCodeDialog(Context context, View view, DialogCallback ok, Runnable back) {
|
||||
private static void showCodeDialog(Context context, View view, DialogCallback ok) {
|
||||
AlertDialog dialog = new StyledDialogBuilder(context)
|
||||
.setTitle(R.string.code_input_title)
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.ok, (btnView, which) -> {})
|
||||
.setNeutralButton(R.string.back, (btnView, which) -> back.run())
|
||||
.setNegativeButton(R.string.cancel, (btnView, which) -> {})
|
||||
.create();
|
||||
|
||||
@ -60,7 +59,7 @@ public class DialogUtil {
|
||||
showErrorDialog(context, errorMessage, null);
|
||||
}
|
||||
|
||||
public static void showTOTPDialog(LayoutInflater inflater, OTPData initialData, Consumer<OTPData> callback, Runnable back, boolean view) {
|
||||
public static void showTOTPDialog(LayoutInflater inflater, OTPData initialData, Consumer<OTPData> callback, boolean view) {
|
||||
Context context = inflater.getContext();
|
||||
DialogInputCodeTotpBinding binding = DialogInputCodeTotpBinding.inflate(inflater);
|
||||
|
||||
@ -122,10 +121,10 @@ public class DialogUtil {
|
||||
showErrorDialog(context, context.getString(R.string.input_code_invalid_number));
|
||||
return false;
|
||||
}
|
||||
}, back);
|
||||
});
|
||||
}
|
||||
|
||||
public static void showHOTPDialog(LayoutInflater inflater, OTPData initialData, Consumer<OTPData> callback, Runnable back, boolean view) {
|
||||
public static void showHOTPDialog(LayoutInflater inflater, OTPData initialData, Consumer<OTPData> callback, boolean view) {
|
||||
Context context = inflater.getContext();
|
||||
DialogInputCodeHotpBinding binding = DialogInputCodeHotpBinding.inflate(inflater);
|
||||
|
||||
@ -187,21 +186,21 @@ public class DialogUtil {
|
||||
showErrorDialog(context, context.getString(R.string.input_code_invalid_number));
|
||||
return false;
|
||||
}
|
||||
}, back);
|
||||
});
|
||||
}
|
||||
|
||||
public static void showViewCodeDialog(LayoutInflater inflater, @NonNull OTPData initialData, Runnable back) {
|
||||
public static void showViewCodeDialog(LayoutInflater inflater, @NonNull OTPData initialData) {
|
||||
// TODO: use better dialogs
|
||||
switch(initialData.getType()) {
|
||||
case HOTP: showHOTPDialog(inflater, initialData, d -> {}, back, true); break;
|
||||
case TOTP: showTOTPDialog(inflater, initialData, d -> {}, back, true); break;
|
||||
case HOTP: showHOTPDialog(inflater, initialData, d -> {}, true); break;
|
||||
case TOTP: showTOTPDialog(inflater, initialData, d -> {}, true); break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void showEditCodeDialog(LayoutInflater inflater, @NonNull OTPData initialData, Consumer<OTPData> callback, Runnable back) {
|
||||
public static void showEditCodeDialog(LayoutInflater inflater, @NonNull OTPData initialData, Consumer<OTPData> callback) {
|
||||
switch(initialData.getType()) {
|
||||
case HOTP: showHOTPDialog(inflater, initialData, callback, back, false); break;
|
||||
case TOTP: showTOTPDialog(inflater, initialData, callback, back, false); break;
|
||||
case HOTP: showHOTPDialog(inflater, initialData, callback, false); break;
|
||||
case TOTP: showTOTPDialog(inflater, initialData, callback, false); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
<vector android:height="24dp" android:tint="?android:attr/textColor"
|
||||
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,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h5v2h2L12,1h-2v2zM10,18L5,18l5,-6v6zM19,3h-5v2h5v13l-5,-6v9h5c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
|
||||
|
@ -8,8 +8,7 @@
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/itemList"
|
||||
@ -23,7 +22,7 @@
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="65dp"
|
||||
android:layout_height="76dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/itemList" />
|
||||
|
@ -35,5 +35,12 @@
|
||||
android:orientation="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="76dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/menu_items" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
@ -7,9 +7,7 @@
|
||||
android:orientation="vertical"
|
||||
android:padding="5dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true" >
|
||||
android:paddingEnd="16dp" >
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/button"
|
||||
|
@ -2,17 +2,21 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/otp_code_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:background="@drawable/button_themed"
|
||||
android:orientation="vertical"
|
||||
android:padding="5dp">
|
||||
android:padding="5dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:background="@drawable/button_themed">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView5"
|
||||
|
23
app/src/main/res/menu/menu_otps.xml
Normal file
23
app/src/main/res/menu/menu_otps.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_add_otp"
|
||||
android:orderInCategory="100"
|
||||
android:icon="@drawable/baseline_add_24"
|
||||
android:title="@string/action_new_group"
|
||||
android:onClick="addOTP"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="never"
|
||||
android:onClick="openSettings" />
|
||||
<item
|
||||
android:id="@+id/action_about"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_about"
|
||||
app:showAsAction="never"
|
||||
android:onClick="openAbout" />
|
||||
</menu>
|
44
app/src/main/res/menu/menu_otps_edit.xml
Normal file
44
app/src/main/res/menu/menu_otps_edit.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_view_otp"
|
||||
android:orderInCategory="100"
|
||||
android:icon="@drawable/baseline_compare_24"
|
||||
android:title="View OTP"
|
||||
android:onClick="viewOTP"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/action_edit_otp"
|
||||
android:orderInCategory="100"
|
||||
android:icon="@drawable/baseline_edit_24"
|
||||
android:title="Edit OTP"
|
||||
android:onClick="editOTP"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/action_move_otp"
|
||||
android:orderInCategory="100"
|
||||
android:icon="@drawable/baseline_qr_code_scanner_24"
|
||||
android:title="Move OTP"
|
||||
android:onClick="moveOTP"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/action_delete_otp"
|
||||
android:orderInCategory="100"
|
||||
android:icon="@drawable/baseline_delete_24"
|
||||
android:title="Delete OTP"
|
||||
android:onClick="deleteOTP"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="never"
|
||||
android:onClick="openSettings" />
|
||||
<item
|
||||
android:id="@+id/action_about"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_about"
|
||||
app:showAsAction="never"
|
||||
android:onClick="openAbout" />
|
||||
</menu>
|
@ -21,8 +21,8 @@
|
||||
<string name="qr_scanner_failed">Scannen fehlgeschlagen: %s</string>
|
||||
<string name="intro_video_failed">Abspielen des Videos fehlgeschlagen</string>
|
||||
<string name="edit_otp_title">OTP bearbeiten</string>
|
||||
<string name="group_delete_title">Gruppe(n) löschen</string>
|
||||
<string name="group_delete_message">Willst du die ausgewählte(n) Gruppe(n) löschen?\n\nHinweis: Dadurch werden alle darin enthaltenen OTPs gelöscht!</string>
|
||||
<string name="group_delete_title">Gruppen löschen</string>
|
||||
<string name="group_delete_message">Willst du die ausgewählten Gruppen löschen?\n\nHinweis: Dadurch werden alle darin enthaltenen OTPs gelöscht!</string>
|
||||
<string name="hotp_generated_new_code">Neuen Code generiert</string>
|
||||
<string name="uri_handler_failed_title">Hinzufügen des Codes fehlgeschlagen</string>
|
||||
<string name="code_input_title">Code eingeben</string>
|
||||
@ -30,7 +30,7 @@
|
||||
<string name="input_code_invalid_number">Ungültige Zahl</string>
|
||||
<string name="back">Zurück</string>
|
||||
<string name="otp_delete_title">OTP löschen</string>
|
||||
<string name="otp_delete_message">Willst du das OTP löschen?</string>
|
||||
<string name="otp_delete_message">Willst du die ausgewählten OTPs löschen?</string>
|
||||
<string name="edit_group_title">Gruppe bearbeiten</string>
|
||||
<string name="settings_enable_intro_video">Intro-Video zeigen</string>
|
||||
<string name="settings_biometric_lock">Biometrische Authentifizierung aktivieren</string>
|
||||
|
@ -16,4 +16,6 @@
|
||||
<color name="color_yellow">#FFE500</color>
|
||||
<color name="color_turquoise">#00FFF7</color>
|
||||
<color name="color_green">#00FF0A</color>
|
||||
|
||||
<color name="selected_highlight">#33008BFF</color>
|
||||
</resources>
|
@ -21,16 +21,16 @@
|
||||
<string name="qr_scanner_failed">Scan failed: %s</string>
|
||||
<string name="intro_video_failed">Failed to play video</string>
|
||||
<string name="edit_otp_title">Edit OTP</string>
|
||||
<string name="group_delete_title">Delete Group(s)</string>
|
||||
<string name="group_delete_message">Do you want to delete the group(s)?\n\nNote: This will delete all of the contained OTPs!</string>
|
||||
<string name="group_delete_title">Delete Groups</string>
|
||||
<string name="group_delete_message">Do you want to delete the groups?\n\nNote: This will delete all of the contained OTPs!</string>
|
||||
<string name="hotp_generated_new_code">Generated new code</string>
|
||||
<string name="uri_handler_failed_title">Failed to add code</string>
|
||||
<string name="code_input_title">Input Code</string>
|
||||
<string name="failed_title">Action failed</string>
|
||||
<string name="input_code_invalid_number">Invalid number entered</string>
|
||||
<string name="back">Back</string>
|
||||
<string name="otp_delete_title">Delete OTP</string>
|
||||
<string name="otp_delete_message">Do you want to delete the OTP?</string>
|
||||
<string name="otp_delete_title">Delete OTP(s)</string>
|
||||
<string name="otp_delete_message">Do you want to delete the selected OTP(s)?</string>
|
||||
<string name="edit_group_title">Edit Group</string>
|
||||
<string name="settings_enable_intro_video">Enable intro video</string>
|
||||
<string name="settings_biometric_lock">Require biometric unlock</string>
|
||||
|
Loading…
Reference in New Issue
Block a user