mirror of
https://github.com/android-password-store/Android-Password-Store
synced 2025-08-31 22:35:17 +00:00
Improve nullability coverage (#514)
* Switch to in-built RV divider * Switch getActivity calls to requireActivity This enforces non-null activity and throws a proper exception when it is null for some reason. Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com>
This commit is contained in:
@@ -1,52 +0,0 @@
|
|||||||
package com.zeapo.pwdstore;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.view.View;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|
||||||
|
|
||||||
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
|
|
||||||
|
|
||||||
private Drawable mDivider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default divider will be used
|
|
||||||
*/
|
|
||||||
public DividerItemDecoration(Context context) {
|
|
||||||
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
|
|
||||||
mDivider = styledAttributes.getDrawable(0);
|
|
||||||
styledAttributes.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom divider will be used
|
|
||||||
*/
|
|
||||||
DividerItemDecoration(Context context, int resId) {
|
|
||||||
mDivider = ContextCompat.getDrawable(context, resId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
|
||||||
int left = parent.getPaddingLeft();
|
|
||||||
int right = parent.getWidth() - parent.getPaddingRight();
|
|
||||||
|
|
||||||
int childCount = parent.getChildCount();
|
|
||||||
for (int i = 0; i < childCount; i++) {
|
|
||||||
View child = parent.getChildAt(i);
|
|
||||||
|
|
||||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
|
||||||
|
|
||||||
int top = child.getBottom() + params.bottomMargin;
|
|
||||||
int bottom = top + mDivider.getIntrinsicHeight();
|
|
||||||
|
|
||||||
mDivider.setBounds(left, top, right, bottom);
|
|
||||||
mDivider.draw(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -11,6 +11,7 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
@@ -51,12 +52,12 @@ public class PasswordFragment extends Fragment {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String path = getArguments().getString("Path");
|
String path = getArguments().getString("Path");
|
||||||
|
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
settings = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||||
passListStack = new Stack<>();
|
passListStack = new Stack<>();
|
||||||
scrollPosition = new Stack<>();
|
scrollPosition = new Stack<>();
|
||||||
pathStack = new Stack<>();
|
pathStack = new Stack<>();
|
||||||
recyclerAdapter = new PasswordRecyclerAdapter((PasswordStore) getActivity(), mListener,
|
recyclerAdapter = new PasswordRecyclerAdapter((PasswordStore) requireActivity(), mListener,
|
||||||
PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
|
PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(requireContext()), getSortOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,19 +66,19 @@ public class PasswordFragment extends Fragment {
|
|||||||
View view = inflater.inflate(R.layout.password_recycler_view, container, false);
|
View view = inflater.inflate(R.layout.password_recycler_view, container, false);
|
||||||
|
|
||||||
// use a linear layout manager
|
// use a linear layout manager
|
||||||
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
|
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(requireContext());
|
||||||
|
|
||||||
recyclerView = view.findViewById(R.id.pass_recycler);
|
recyclerView = view.findViewById(R.id.pass_recycler);
|
||||||
recyclerView.setLayoutManager(mLayoutManager);
|
recyclerView.setLayoutManager(mLayoutManager);
|
||||||
|
|
||||||
// use divider
|
// use divider
|
||||||
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider));
|
recyclerView.addItemDecoration(new DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL));
|
||||||
|
|
||||||
// Set the adapter
|
// Set the adapter
|
||||||
recyclerView.setAdapter(recyclerAdapter);
|
recyclerView.setAdapter(recyclerAdapter);
|
||||||
|
|
||||||
final FloatingActionButton fab = view.findViewById(R.id.fab);
|
final FloatingActionButton fab = view.findViewById(R.id.fab);
|
||||||
fab.setOnClickListener(v -> ((PasswordStore) getActivity()).createPassword());
|
fab.setOnClickListener(v -> ((PasswordStore) requireActivity()).createPassword());
|
||||||
|
|
||||||
registerForContextMenu(recyclerView);
|
registerForContextMenu(recyclerView);
|
||||||
return view;
|
return view;
|
||||||
@@ -101,18 +102,17 @@ public class PasswordFragment extends Fragment {
|
|||||||
recyclerAdapter.clear();
|
recyclerAdapter.clear();
|
||||||
recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
|
recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
|
||||||
|
|
||||||
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
if (getArguments().getBoolean("matchWith", false)) {
|
if (getArguments().getBoolean("matchWith", false)) {
|
||||||
((PasswordStore) getActivity()).matchPasswordWithApp(item);
|
((PasswordStore) requireActivity()).matchPasswordWithApp(item);
|
||||||
} else {
|
} else {
|
||||||
((PasswordStore) getActivity()).decryptPassword(item);
|
((PasswordStore) requireActivity()).decryptPassword(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
throw new ClassCastException(context.toString()
|
throw new ClassCastException(context + " must implement OnFragmentInteractionListener");
|
||||||
+ " must implement OnFragmentInteractionListener");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,9 +124,9 @@ public class PasswordFragment extends Fragment {
|
|||||||
pathStack.clear();
|
pathStack.clear();
|
||||||
scrollPosition.clear();
|
scrollPosition.clear();
|
||||||
recyclerAdapter.clear();
|
recyclerAdapter.clear();
|
||||||
recyclerAdapter.addAll(PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
|
recyclerAdapter.addAll(PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(requireContext()), getSortOrder()));
|
||||||
|
|
||||||
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,8 +135,8 @@ public class PasswordFragment extends Fragment {
|
|||||||
public void refreshAdapter() {
|
public void refreshAdapter() {
|
||||||
recyclerAdapter.clear();
|
recyclerAdapter.clear();
|
||||||
recyclerAdapter.addAll(pathStack.isEmpty() ?
|
recyclerAdapter.addAll(pathStack.isEmpty() ?
|
||||||
PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()) :
|
PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(requireContext()), getSortOrder()) :
|
||||||
PasswordRepository.getPasswords(pathStack.peek(), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
|
PasswordRepository.getPasswords(pathStack.peek(), PasswordRepository.getRepositoryDirectory(requireContext()), getSortOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,8 +163,8 @@ public class PasswordFragment extends Fragment {
|
|||||||
private void recursiveFilter(String filter, File dir) {
|
private void recursiveFilter(String filter, File dir) {
|
||||||
// on the root the pathStack is empty
|
// on the root the pathStack is empty
|
||||||
ArrayList<PasswordItem> passwordItems = dir == null ?
|
ArrayList<PasswordItem> passwordItems = dir == null ?
|
||||||
PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()) :
|
PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(requireContext()), getSortOrder()) :
|
||||||
PasswordRepository.getPasswords(dir, PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder());
|
PasswordRepository.getPasswords(dir, PasswordRepository.getRepositoryDirectory(requireContext()), getSortOrder());
|
||||||
|
|
||||||
boolean rec = settings.getBoolean("filter_recursively", true);
|
boolean rec = settings.getBoolean("filter_recursively", true);
|
||||||
for (PasswordItem item : passwordItems) {
|
for (PasswordItem item : passwordItems) {
|
||||||
@@ -201,7 +201,7 @@ public class PasswordFragment extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public File getCurrentDir() {
|
public File getCurrentDir() {
|
||||||
if (pathStack.isEmpty())
|
if (pathStack.isEmpty())
|
||||||
return PasswordRepository.getRepositoryDirectory(getActivity().getApplicationContext());
|
return PasswordRepository.getRepositoryDirectory(requireContext());
|
||||||
else
|
else
|
||||||
return pathStack.peek();
|
return pathStack.peek();
|
||||||
}
|
}
|
||||||
|
@@ -37,8 +37,8 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
|
|||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
|
||||||
final Activity callingActivity = getActivity();
|
final Activity callingActivity = requireActivity();
|
||||||
LayoutInflater inflater = callingActivity.getLayoutInflater();
|
LayoutInflater inflater = callingActivity.getLayoutInflater();
|
||||||
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.fragment_pwgen, null);
|
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.fragment_pwgen, null);
|
||||||
Typeface monoTypeface = Typeface.createFromAsset(callingActivity.getAssets(), "fonts/sourcecodepro.ttf");
|
Typeface monoTypeface = Typeface.createFromAsset(callingActivity.getAssets(), "fonts/sourcecodepro.ttf");
|
||||||
@@ -46,7 +46,7 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
|
|||||||
builder.setView(view);
|
builder.setView(view);
|
||||||
|
|
||||||
SharedPreferences prefs
|
SharedPreferences prefs
|
||||||
= getActivity().getApplicationContext().getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE);
|
= requireActivity().getApplicationContext().getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE);
|
||||||
|
|
||||||
CheckBox checkBox = view.findViewById(R.id.numerals);
|
CheckBox checkBox = view.findViewById(R.id.numerals);
|
||||||
checkBox.setChecked(!prefs.getBoolean("0", false));
|
checkBox.setChecked(!prefs.getBoolean("0", false));
|
||||||
@@ -87,9 +87,9 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
|
|||||||
ad.setOnShowListener(dialog -> {
|
ad.setOnShowListener(dialog -> {
|
||||||
setPreferences();
|
setPreferences();
|
||||||
try {
|
try {
|
||||||
passwordText.setText(PasswordGenerator.INSTANCE.generate(getActivity().getApplicationContext()).get(0));
|
passwordText.setText(PasswordGenerator.generate(requireActivity().getApplicationContext()).get(0));
|
||||||
} catch (PasswordGenerator.PasswordGeneratorExeption e) {
|
} catch (PasswordGenerator.PasswordGeneratorExeption e) {
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
passwordText.setText("");
|
passwordText.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,9 +97,9 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
|
|||||||
b.setOnClickListener(v -> {
|
b.setOnClickListener(v -> {
|
||||||
setPreferences();
|
setPreferences();
|
||||||
try {
|
try {
|
||||||
passwordText.setText(PasswordGenerator.INSTANCE.generate(callingActivity.getApplicationContext()).get(0));
|
passwordText.setText(PasswordGenerator.generate(callingActivity.getApplicationContext()).get(0));
|
||||||
} catch (PasswordGenerator.PasswordGeneratorExeption e) {
|
} catch (PasswordGenerator.PasswordGeneratorExeption e) {
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
passwordText.setText("");
|
passwordText.setText("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -131,9 +131,9 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
|
|||||||
EditText editText = getDialog().findViewById(R.id.lengthNumber);
|
EditText editText = getDialog().findViewById(R.id.lengthNumber);
|
||||||
try {
|
try {
|
||||||
int length = Integer.valueOf(editText.getText().toString());
|
int length = Integer.valueOf(editText.getText().toString());
|
||||||
PasswordGenerator.INSTANCE.setPrefs(getActivity().getApplicationContext(), preferences, length);
|
PasswordGenerator.setPrefs(requireActivity().getApplicationContext(), preferences, length);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
PasswordGenerator.INSTANCE.setPrefs(getActivity().getApplicationContext(), preferences);
|
PasswordGenerator.setPrefs(requireActivity().getApplicationContext(), preferences);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
@@ -46,8 +47,8 @@ public class SelectFolderFragment extends Fragment {
|
|||||||
String path = getArguments().getString("Path");
|
String path = getArguments().getString("Path");
|
||||||
|
|
||||||
pathStack = new Stack<>();
|
pathStack = new Stack<>();
|
||||||
recyclerAdapter = new FolderRecyclerAdapter((SelectFolderActivity) getActivity(), mListener,
|
recyclerAdapter = new FolderRecyclerAdapter((SelectFolderActivity) requireActivity(), mListener,
|
||||||
PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
|
PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(requireActivity()), getSortOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,10 +58,10 @@ public class SelectFolderFragment extends Fragment {
|
|||||||
|
|
||||||
// use a linear layout manager
|
// use a linear layout manager
|
||||||
recyclerView = view.findViewById(R.id.pass_recycler);
|
recyclerView = view.findViewById(R.id.pass_recycler);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||||
|
|
||||||
// use divider
|
// use divider
|
||||||
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider));
|
recyclerView.addItemDecoration(new DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL));
|
||||||
|
|
||||||
// Set the adapter
|
// Set the adapter
|
||||||
recyclerView.setAdapter(recyclerAdapter);
|
recyclerView.setAdapter(recyclerAdapter);
|
||||||
@@ -84,7 +85,7 @@ public class SelectFolderFragment extends Fragment {
|
|||||||
recyclerAdapter.clear();
|
recyclerAdapter.clear();
|
||||||
recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
|
recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
|
||||||
|
|
||||||
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
@@ -100,13 +101,13 @@ public class SelectFolderFragment extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public File getCurrentDir() {
|
public File getCurrentDir() {
|
||||||
if (pathStack.isEmpty())
|
if (pathStack.isEmpty())
|
||||||
return PasswordRepository.getRepositoryDirectory(getActivity().getApplicationContext());
|
return PasswordRepository.getRepositoryDirectory(requireContext());
|
||||||
else
|
else
|
||||||
return pathStack.peek();
|
return pathStack.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PasswordRepository.PasswordSortOrder getSortOrder() {
|
private PasswordRepository.PasswordSortOrder getSortOrder() {
|
||||||
return PasswordRepository.PasswordSortOrder.getSortOrder(PreferenceManager.getDefaultSharedPreferences(getActivity()));
|
return PasswordRepository.PasswordSortOrder.getSortOrder(PreferenceManager.getDefaultSharedPreferences(requireContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface OnFragmentInteractionListener {
|
public interface OnFragmentInteractionListener {
|
||||||
|
@@ -47,6 +47,7 @@ object PasswordGenerator {
|
|||||||
* @return `false` if a numerical options is invalid,
|
* @return `false` if a numerical options is invalid,
|
||||||
* `true` otherwise
|
* `true` otherwise
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
fun setPrefs(ctx: Context, argv: ArrayList<String>, vararg numArgv: Int): Boolean {
|
fun setPrefs(ctx: Context, argv: ArrayList<String>, vararg numArgv: Int): Boolean {
|
||||||
val prefs = ctx.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
|
val prefs = ctx.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
|
||||||
val editor = prefs.edit()
|
val editor = prefs.edit()
|
||||||
@@ -81,7 +82,7 @@ object PasswordGenerator {
|
|||||||
* preferences file 'PasswordGenerator'
|
* preferences file 'PasswordGenerator'
|
||||||
* @return list of generated passwords
|
* @return list of generated passwords
|
||||||
*/
|
*/
|
||||||
@Throws(PasswordGenerator.PasswordGeneratorExeption::class)
|
@JvmStatic @Throws(PasswordGenerator.PasswordGeneratorExeption::class)
|
||||||
fun generate(ctx: Context): ArrayList<String> {
|
fun generate(ctx: Context): ArrayList<String> {
|
||||||
val prefs = ctx.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
|
val prefs = ctx.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
@@ -140,6 +141,6 @@ object PasswordGenerator {
|
|||||||
return passwords
|
return passwords
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PasswordGeneratorExeption(string: String) : Exception(string)
|
class PasswordGeneratorExeption(string: String) : Exception(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user