mirror of
https://github.com/wismna/DoNext.git
synced 2025-10-03 15:40:14 -04:00
Replace AsyncTasks with TaskRunner
Some refactoring
This commit is contained in:
@@ -2,7 +2,6 @@ package com.wismna.geoffroy.donext.fragments;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@@ -21,9 +20,10 @@ import com.wismna.geoffroy.donext.adapters.TaskListRecyclerViewAdapter;
|
|||||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||||
import com.wismna.geoffroy.donext.database.TaskListDataAccess;
|
import com.wismna.geoffroy.donext.database.TaskListDataAccess;
|
||||||
import com.wismna.geoffroy.donext.helpers.TaskListTouchHelper;
|
import com.wismna.geoffroy.donext.helpers.TaskListTouchHelper;
|
||||||
|
import com.wismna.geoffroy.donext.utils.TaskRunner;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fragment representing a list of Items.
|
* A fragment representing a list of Items.
|
||||||
@@ -64,7 +64,24 @@ public class TaskListsDialogFragment extends DynamicDialogFragment implements
|
|||||||
mContentLayoutId = R.layout.content_tasklists;
|
mContentLayoutId = R.layout.content_tasklists;
|
||||||
|
|
||||||
taskListDataAccess = new TaskListDataAccess(getContext(), TaskListDataAccess.MODE.WRITE);
|
taskListDataAccess = new TaskListDataAccess(getContext(), TaskListDataAccess.MODE.WRITE);
|
||||||
new GetTaskListsTask(this).execute(taskListDataAccess);
|
|
||||||
|
Context context = getContext();
|
||||||
|
TaskRunner taskRunner = new TaskRunner();
|
||||||
|
taskRunner.executeAsync(new GetTaskLists(context), (taskLists) -> {
|
||||||
|
taskListRecyclerViewAdapter = new TaskListRecyclerViewAdapter(taskLists, this);
|
||||||
|
|
||||||
|
// Set the adapter
|
||||||
|
RecyclerView recyclerView = findViewById(R.id.task_lists_view);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
recyclerView.setAdapter(taskListRecyclerViewAdapter);
|
||||||
|
|
||||||
|
// Set the Touch Helper
|
||||||
|
ItemTouchHelper.Callback callback = new TaskListTouchHelper(taskListRecyclerViewAdapter);
|
||||||
|
mItemTouchHelper = new ItemTouchHelper(callback);
|
||||||
|
mItemTouchHelper.attachToRecyclerView(recyclerView);
|
||||||
|
|
||||||
|
toggleVisibleCreateNewTaskListLayout();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -122,7 +139,7 @@ public class TaskListsDialogFragment extends DynamicDialogFragment implements
|
|||||||
private void toggleVisibleCreateNewTaskListLayout() {
|
private void toggleVisibleCreateNewTaskListLayout() {
|
||||||
LinearLayout layout = findViewById(R.id.new_task_list_layout);
|
LinearLayout layout = findViewById(R.id.new_task_list_layout);
|
||||||
int taskListCount = taskListRecyclerViewAdapter.getItemCount();
|
int taskListCount = taskListRecyclerViewAdapter.getItemCount();
|
||||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
String maxTaskListsString = sharedPref.getString("pref_conf_max_lists", "5");
|
String maxTaskListsString = sharedPref.getString("pref_conf_max_lists", "5");
|
||||||
int maxTaskLists = Integer.parseInt(maxTaskListsString);
|
int maxTaskLists = Integer.parseInt(maxTaskListsString);
|
||||||
if (taskListCount >= maxTaskLists) layout.setVisibility(View.GONE);
|
if (taskListCount >= maxTaskLists) layout.setVisibility(View.GONE);
|
||||||
@@ -137,7 +154,7 @@ public class TaskListsDialogFragment extends DynamicDialogFragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClickDeleteButton(int position, long id) {
|
public void onClickDeleteButton(int position, long id) {
|
||||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
|
|
||||||
if(sharedPref.getBoolean("pref_conf_tasklist_del", true)) {
|
if(sharedPref.getBoolean("pref_conf_tasklist_del", true)) {
|
||||||
String title = getResources().getString(R.string.task_list_confirmation_delete);
|
String title = getResources().getString(R.string.task_list_confirmation_delete);
|
||||||
@@ -160,7 +177,7 @@ public class TaskListsDialogFragment extends DynamicDialogFragment implements
|
|||||||
CheckBox neverAskAgainCheckBox = dialog.getDialog().findViewById(R.id.task_confirmation_never);
|
CheckBox neverAskAgainCheckBox = dialog.getDialog().findViewById(R.id.task_confirmation_never);
|
||||||
if (neverAskAgainCheckBox.isChecked()) {
|
if (neverAskAgainCheckBox.isChecked()) {
|
||||||
|
|
||||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
SharedPreferences.Editor editor = sharedPref.edit();
|
SharedPreferences.Editor editor = sharedPref.edit();
|
||||||
|
|
||||||
editor.putBoolean("pref_conf_tasklist_del", false);
|
editor.putBoolean("pref_conf_tasklist_del", false);
|
||||||
@@ -192,39 +209,18 @@ public class TaskListsDialogFragment extends DynamicDialogFragment implements
|
|||||||
toggleVisibleCreateNewTaskListLayout();
|
toggleVisibleCreateNewTaskListLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GetTaskListsTask extends AsyncTask<TaskListDataAccess, Void, List<TaskList>> {
|
static class GetTaskLists implements Callable<List<TaskList>> {
|
||||||
private final WeakReference<TaskListsDialogFragment> fragmentReference;
|
private final Context context;
|
||||||
|
|
||||||
GetTaskListsTask(TaskListsDialogFragment context) {
|
public GetTaskLists(Context context) {
|
||||||
fragmentReference = new WeakReference<>(context);
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<TaskList> doInBackground(TaskListDataAccess... params) {
|
public List<TaskList> call() {
|
||||||
TaskListDataAccess taskListDataAccess = params[0];
|
try(TaskListDataAccess taskListDataAccess = new TaskListDataAccess(context)) {
|
||||||
return taskListDataAccess.getTaskLists(false);
|
return taskListDataAccess.getTaskLists(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(List<TaskList> taskLists) {
|
|
||||||
super.onPostExecute(taskLists);
|
|
||||||
TaskListsDialogFragment fragment = fragmentReference.get();
|
|
||||||
if (fragment == null) return;
|
|
||||||
fragment.taskListRecyclerViewAdapter =
|
|
||||||
new TaskListRecyclerViewAdapter(taskLists, fragment);
|
|
||||||
|
|
||||||
// Set the adapter
|
|
||||||
Context context = fragment.getContext();
|
|
||||||
RecyclerView recyclerView = fragment.findViewById(R.id.task_lists_view);
|
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
|
||||||
recyclerView.setAdapter(fragment.taskListRecyclerViewAdapter);
|
|
||||||
|
|
||||||
// Set the Touch Helper
|
|
||||||
ItemTouchHelper.Callback callback = new TaskListTouchHelper(fragment.taskListRecyclerViewAdapter);
|
|
||||||
fragment.mItemTouchHelper = new ItemTouchHelper(callback);
|
|
||||||
fragment.mItemTouchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
|
|
||||||
fragment.toggleVisibleCreateNewTaskListLayout();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,26 @@
|
|||||||
package com.wismna.geoffroy.donext.fragments;
|
package com.wismna.geoffroy.donext.fragments;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.wismna.geoffroy.donext.R;
|
import com.wismna.geoffroy.donext.R;
|
||||||
import com.wismna.geoffroy.donext.adapters.TodayArrayAdapter;
|
import com.wismna.geoffroy.donext.adapters.TodayArrayAdapter;
|
||||||
import com.wismna.geoffroy.donext.dao.Task;
|
import com.wismna.geoffroy.donext.dao.Task;
|
||||||
import com.wismna.geoffroy.donext.database.TaskDataAccess;
|
import com.wismna.geoffroy.donext.database.TaskDataAccess;
|
||||||
|
import com.wismna.geoffroy.donext.utils.TaskRunner;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by bg45 on 2017-03-21.
|
* Created by bg45 on 2017-03-21.
|
||||||
@@ -53,7 +54,9 @@ public class TodayFormDialogFragment extends DynamicDialogFragment {
|
|||||||
mNegativeButtonString = getString(R.string.new_task_cancel);
|
mNegativeButtonString = getString(R.string.new_task_cancel);
|
||||||
mContentLayoutId = R.layout.content_today_form;
|
mContentLayoutId = R.layout.content_today_form;
|
||||||
// Load the tasks asynchronously
|
// Load the tasks asynchronously
|
||||||
new LoadTasks(this).execute(getActivity());
|
//new LoadTasks(this).execute(getActivity());
|
||||||
|
TaskRunner taskRunner = new TaskRunner();
|
||||||
|
taskRunner.executeAsync(new LoadTasks(getContext()), this::setLayoutValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setLayoutValues(List<Task> tasks) {
|
private void setLayoutValues(List<Task> tasks) {
|
||||||
@@ -94,7 +97,8 @@ public class TodayFormDialogFragment extends DynamicDialogFragment {
|
|||||||
protected void onPositiveButtonClick(View view) {
|
protected void onPositiveButtonClick(View view) {
|
||||||
mListener.onTodayTaskDialogPositiveClick(view);
|
mListener.onTodayTaskDialogPositiveClick(view);
|
||||||
// Only commit the updated tasks to DB
|
// Only commit the updated tasks to DB
|
||||||
new UpdateTasks(this).execute(mUpdatedTasks.toArray(new Task[0]));
|
TaskRunner taskRunner = new TaskRunner();
|
||||||
|
taskRunner.executeAsync(new UpdateTasks(getContext(), mUpdatedTasks.toArray(new Task[0])), (position) -> mListener.onTodayTasksUpdated());
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,50 +112,40 @@ public class TodayFormDialogFragment extends DynamicDialogFragment {
|
|||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class LoadTasks extends AsyncTask<Context, Void, List<Task>> {
|
static class LoadTasks implements Callable<List<Task>> {
|
||||||
private final WeakReference<TodayFormDialogFragment> fragmentReference;
|
private final Context context;
|
||||||
|
|
||||||
LoadTasks(TodayFormDialogFragment context) {
|
public LoadTasks(Context context) {
|
||||||
fragmentReference = new WeakReference<>(context);
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Task> doInBackground(Context... params) {
|
public List<Task> call() {
|
||||||
try(TaskDataAccess taskDataAccess = new TaskDataAccess(params[0])) {
|
try(TaskDataAccess taskDataAccess = new TaskDataAccess(context)) {
|
||||||
return taskDataAccess.getAllTasks();
|
return taskDataAccess.getAllTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(List<Task> tasks) {
|
|
||||||
super.onPostExecute(tasks);
|
|
||||||
fragmentReference.get().setLayoutValues(tasks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class UpdateTasks extends AsyncTask<Task, Void, Integer> {
|
static class UpdateTasks implements Callable<Integer> {
|
||||||
private final WeakReference<TodayFormDialogFragment> fragmentReference;
|
private final Context context;
|
||||||
|
private final Task[] tasks;
|
||||||
|
|
||||||
UpdateTasks(TodayFormDialogFragment context) {
|
public UpdateTasks(Context context, Task[] tasks) {
|
||||||
fragmentReference = new WeakReference<>(context);
|
this.context = context;
|
||||||
|
this.tasks = tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Integer doInBackground(Task... params) {
|
public Integer call() {
|
||||||
int position;
|
int position;
|
||||||
try (TaskDataAccess taskDataAccess = new TaskDataAccess(fragmentReference.get().getActivity(), TaskDataAccess.MODE.WRITE)) {
|
try (TaskDataAccess taskDataAccess = new TaskDataAccess(context, TaskDataAccess.MODE.WRITE)) {
|
||||||
for (position = 0; position < params.length; position ++) {
|
for (position = 0; position < tasks.length; position ++) {
|
||||||
Task task = params[position];
|
Task task = tasks[position];
|
||||||
taskDataAccess.updateTodayTasks(task.getId(), task.isToday(), position);
|
taskDataAccess.updateTodayTasks(task.getId(), task.isToday(), position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Integer integer) {
|
|
||||||
super.onPostExecute(integer);
|
|
||||||
fragmentReference.get().mListener.onTodayTasksUpdated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,14 +4,15 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.StaticLayout;
|
import android.text.StaticLayout;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.wismna.geoffroy.donext.R;
|
import com.wismna.geoffroy.donext.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,8 +25,8 @@ public class TaskTouchHelper extends ItemTouchHelper.SimpleCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final TaskTouchHelperAdapter mAdapter;
|
private final TaskTouchHelperAdapter mAdapter;
|
||||||
private int colorRight;
|
private final int colorRight;
|
||||||
private int colorLeft;
|
private final int colorLeft;
|
||||||
|
|
||||||
public TaskTouchHelper(TaskTouchHelperAdapter adapter, int colorRight, int colorLeft){
|
public TaskTouchHelper(TaskTouchHelperAdapter adapter, int colorRight, int colorLeft){
|
||||||
// No drag moves, no swipes (except for 1st element, see getSwipeDirs method)
|
// No drag moves, no swipes (except for 1st element, see getSwipeDirs method)
|
||||||
@@ -37,8 +38,8 @@ public class TaskTouchHelper extends ItemTouchHelper.SimpleCallback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSwipeDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
public int getSwipeDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||||
// Allow both directions swiping on first item, only left on the others
|
// Allow both directions swiping on first item, none on the others
|
||||||
if (viewHolder.getAdapterPosition() == 0)
|
if (viewHolder.getAbsoluteAdapterPosition() == 0)
|
||||||
return ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
return ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
||||||
else return super.getSwipeDirs(recyclerView, viewHolder);
|
else return super.getSwipeDirs(recyclerView, viewHolder);
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ public class TaskTouchHelper extends ItemTouchHelper.SimpleCallback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||||
mAdapter.onItemSwiped(viewHolder.getAdapterPosition(), direction);
|
mAdapter.onItemSwiped(viewHolder.getAbsoluteAdapterPosition(), direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -1,68 +0,0 @@
|
|||||||
package com.wismna.geoffroy.donext.repositories;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
|
|
||||||
import com.wismna.geoffroy.donext.data.AppDatabase;
|
|
||||||
import com.wismna.geoffroy.donext.data.Task;
|
|
||||||
import com.wismna.geoffroy.donext.data.TaskDao;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
|
|
||||||
public class TaskRepository {
|
|
||||||
private TaskDao mTaskDao;
|
|
||||||
|
|
||||||
TaskRepository(Application application) {
|
|
||||||
AppDatabase db = AppDatabase.getDatabase(application);
|
|
||||||
mTaskDao = db.taskDao();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insert(Task task) {
|
|
||||||
new insertAsyncTask(mTaskDao).execute(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(Task task) {
|
|
||||||
new updateAsyncTask(mTaskDao).execute(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<Task>> getTasksInList(long taskId) {
|
|
||||||
return mTaskDao.getAllTasksFromList(taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<Task>> getTodayTasks() {
|
|
||||||
return mTaskDao.getTodayTasks();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Async tasks
|
|
||||||
private static class insertAsyncTask extends AsyncTask<Task, Void, Void> {
|
|
||||||
|
|
||||||
private TaskDao mAsyncTaskDao;
|
|
||||||
|
|
||||||
insertAsyncTask(TaskDao dao) {
|
|
||||||
mAsyncTaskDao = dao;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(final Task... params) {
|
|
||||||
mAsyncTaskDao.createTask(params[0]);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class updateAsyncTask extends AsyncTask<Task, Void, Void> {
|
|
||||||
|
|
||||||
private TaskDao mAsyncTaskDao;
|
|
||||||
|
|
||||||
updateAsyncTask(TaskDao dao) {
|
|
||||||
mAsyncTaskDao = dao;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(final Task... params) {
|
|
||||||
mAsyncTaskDao.updateTask(params[0]);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,29 @@
|
|||||||
|
package com.wismna.geoffroy.donext.utils;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class TaskRunner {
|
||||||
|
private final Executor executor = Executors.newSingleThreadExecutor();
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
public interface Callback<R> {
|
||||||
|
void onComplete(R result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <R> void executeAsync(Callable<R> callable, Callback<R> callback) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
final R result;
|
||||||
|
try {
|
||||||
|
result = callable.call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
handler.post(() -> callback.onComplete(result));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user