mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-23 04:33:54 -04:00
Refactor LocalFileTransferActivity & async-tasks
- All communication with LocalFileTransferActivity is now through WifiDirectManager.Callbacks only - Modified async tasks to use instance of calling WifiDirectManager
This commit is contained in:
parent
d11af7ba65
commit
bfd24a42d5
@ -33,7 +33,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnItemClick;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
@ -89,11 +88,11 @@ public class LocalFileTransferActivity extends AppCompatActivity implements
|
||||
|
||||
public @NonNull WifiDirectManager wifiDirectManager = new WifiDirectManager(this);
|
||||
|
||||
private ArrayList<FileItem> filesToSend = new ArrayList<>();
|
||||
private ArrayList<FileItem> filesForTransfer = new ArrayList<>();
|
||||
private FileListAdapter fileListAdapter;
|
||||
|
||||
private List<WifiP2pDevice> peerDevices = new ArrayList<WifiP2pDevice>();
|
||||
private boolean fileTransferStarted = false;
|
||||
private List<WifiP2pDevice> availablePeerDevices = new ArrayList<WifiP2pDevice>();
|
||||
private boolean hasSenderStartedConnection = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@ -126,24 +125,24 @@ public class LocalFileTransferActivity extends AppCompatActivity implements
|
||||
}
|
||||
});
|
||||
|
||||
wifiDirectManager.createWifiDirectManager(sharedPreferenceUtil, alertDialogShower, fileUriArrayList);
|
||||
|
||||
listViewPeerDevices.setAdapter(
|
||||
new WifiPeerListAdapter(this, R.layout.row_peer_device, peerDevices));
|
||||
new WifiPeerListAdapter(this, R.layout.row_peer_device, availablePeerDevices));
|
||||
|
||||
if (isFileSender) {
|
||||
for (int i = 0; i < fileUriArrayList.size(); i++) {
|
||||
filesToSend.add(new FileItem(getFileName(fileUriArrayList.get(i)), TO_BE_SENT));
|
||||
filesForTransfer.add(new FileItem(getFileName(fileUriArrayList.get(i)), TO_BE_SENT));
|
||||
}
|
||||
|
||||
displayFileTransferProgress(filesToSend);
|
||||
displayFileTransferProgress(filesForTransfer);
|
||||
}
|
||||
|
||||
wifiDirectManager.createWifiDirectManager(sharedPreferenceUtil, alertDialogShower, fileUriArrayList, filesForTransfer);
|
||||
}
|
||||
|
||||
@OnItemClick(R.id.list_peer_devices)
|
||||
void onItemClick(int position) {
|
||||
/* Connection can only be initiated by user of the sender device, & only when transfer has not been started */
|
||||
if (!isFileSender || fileTransferStarted) {
|
||||
if (!isFileSender || hasSenderStartedConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -182,7 +181,7 @@ public class LocalFileTransferActivity extends AppCompatActivity implements
|
||||
return true;
|
||||
}
|
||||
|
||||
onInitiateDiscovery();
|
||||
showPeerDiscoveryProgressBar();
|
||||
wifiDirectManager.discoverPeerDevices();
|
||||
|
||||
return true;
|
||||
@ -192,52 +191,64 @@ public class LocalFileTransferActivity extends AppCompatActivity implements
|
||||
}
|
||||
|
||||
/* Helper methods used in the activity */
|
||||
public void updateUserDevice(@Nullable WifiP2pDevice userDevice) { // Update UI with user device's details
|
||||
wifiDirectManager.setUserDevice(userDevice);
|
||||
|
||||
@Override
|
||||
public void onUserDeviceDetailsAvailable(@Nullable WifiP2pDevice userDevice) { // Update UI with user device's details
|
||||
if (userDevice != null) {
|
||||
deviceName.setText(userDevice.deviceName);
|
||||
Log.d(TAG, getDeviceStatus(userDevice.status));
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPeers() {
|
||||
peerDevices.clear();
|
||||
@Override
|
||||
public void clearListOfAvailablePeers() {
|
||||
availablePeerDevices.clear();
|
||||
((WifiPeerListAdapter) listViewPeerDevices.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayFileTransferProgress(ArrayList<FileItem> filesToSend) {
|
||||
if(!isFileSender) {
|
||||
this.filesToSend = filesToSend;
|
||||
}
|
||||
private void displayFileTransferProgress(@NonNull ArrayList<FileItem> filesToSend) {
|
||||
fileListAdapter = new FileListAdapter(filesToSend);
|
||||
filesRecyclerView.setAdapter(fileListAdapter);
|
||||
filesRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
}
|
||||
|
||||
public void onInitiateDiscovery() { // Setup UI for searching peers
|
||||
@Override
|
||||
public void onFilesForTransferAvailable(@NonNull ArrayList<FileItem> filesForTransfer) {
|
||||
this.filesForTransfer = filesForTransfer;
|
||||
displayFileTransferProgress(filesForTransfer);
|
||||
}
|
||||
|
||||
private void showPeerDiscoveryProgressBar() { // Setup UI for searching peers
|
||||
searchingPeersProgressBar.setVisibility(View.VISIBLE);
|
||||
listViewPeerDevices.setVisibility(View.INVISIBLE);
|
||||
textViewPeerDevices.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
public void changeStatus(int itemIndex, @FileItem.FileStatus int status) {
|
||||
filesToSend.get(itemIndex).setFileStatus(status);
|
||||
@Override
|
||||
public void onSenderStartedConnection() {
|
||||
this.hasSenderStartedConnection = true;
|
||||
}
|
||||
|
||||
/*public void changeStatus(int itemIndex, @FileItem.FileStatus int status) {
|
||||
filesForTransfer.get(itemIndex).setFileStatus(status);
|
||||
fileListAdapter.notifyItemChanged(itemIndex);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void onFileStatusChanged(int itemIndex) {
|
||||
fileListAdapter.notifyItemChanged(itemIndex);
|
||||
}
|
||||
|
||||
/* From WifiDirectManager.Callbacks interface */
|
||||
@Override
|
||||
public void updatePeerDevicesList(@NonNull WifiP2pDeviceList peers) {
|
||||
public void updateListOfAvailablePeers(@NonNull WifiP2pDeviceList peers) {
|
||||
availablePeerDevices.clear();
|
||||
availablePeerDevices.addAll(peers.getDeviceList());
|
||||
|
||||
searchingPeersProgressBar.setVisibility(View.GONE);
|
||||
listViewPeerDevices.setVisibility(View.VISIBLE);
|
||||
|
||||
peerDevices.clear();
|
||||
peerDevices.addAll(peers.getDeviceList());
|
||||
((WifiPeerListAdapter) listViewPeerDevices.getAdapter()).notifyDataSetChanged();
|
||||
|
||||
if (peerDevices.size() == 0) {
|
||||
if (availablePeerDevices.size() == 0) {
|
||||
Log.d(LocalFileTransferActivity.TAG, "No devices found");
|
||||
}
|
||||
}
|
||||
|
@ -37,11 +37,13 @@ class ReceiverDeviceAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
private static final String TAG = "ReceiverDeviceAsyncTask";
|
||||
|
||||
private WeakReference<LocalFileTransferActivity> weakReferenceToActivity;
|
||||
private WifiDirectManager wifiDirectManager;
|
||||
private int fileItemIndex;
|
||||
private String incomingFileName;
|
||||
|
||||
public ReceiverDeviceAsyncTask(LocalFileTransferActivity localFileTransferActivity) {
|
||||
public ReceiverDeviceAsyncTask(WifiDirectManager wifiDirectManager, LocalFileTransferActivity localFileTransferActivity) {
|
||||
this.weakReferenceToActivity = new WeakReference<>(localFileTransferActivity);
|
||||
this.wifiDirectManager = wifiDirectManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -49,16 +51,15 @@ class ReceiverDeviceAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
try (ServerSocket serverSocket = new ServerSocket(FILE_TRANSFER_PORT)) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Server: Socket opened at " + FILE_TRANSFER_PORT);
|
||||
|
||||
final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get();
|
||||
final String KIWIX_ROOT = localFileTransferActivity.wifiDirectManager.getZimStorageRootPath();
|
||||
int totalFileCount = localFileTransferActivity.wifiDirectManager.getTotalFilesForTransfer();
|
||||
final String KIWIX_ROOT = wifiDirectManager.getZimStorageRootPath();
|
||||
int totalFileCount = wifiDirectManager.getTotalFilesForTransfer();
|
||||
boolean result = true;
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Expecting "+totalFileCount+" files");
|
||||
|
||||
for (int currentFile = 1; currentFile <= totalFileCount && !isCancelled(); currentFile++) {
|
||||
fileItemIndex = currentFile - 1;
|
||||
ArrayList<FileItem> fileItems = localFileTransferActivity.wifiDirectManager.getFileItems();
|
||||
ArrayList<FileItem> fileItems = wifiDirectManager.getFileItems();
|
||||
incomingFileName = fileItems.get(fileItemIndex).getFileName();
|
||||
|
||||
try (Socket client = serverSocket.accept()) {
|
||||
@ -85,7 +86,7 @@ class ReceiverDeviceAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
publishProgress(fileItemIndex, ERROR);
|
||||
}
|
||||
|
||||
localFileTransferActivity.wifiDirectManager.incrementTotalFilesSent();
|
||||
wifiDirectManager.incrementTotalFilesSent();
|
||||
}
|
||||
|
||||
return (!isCancelled() && result);
|
||||
@ -100,9 +101,9 @@ class ReceiverDeviceAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
int fileIndex = values[0];
|
||||
int fileStatus = values[1];
|
||||
final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get();
|
||||
localFileTransferActivity.changeStatus(fileIndex, fileStatus);
|
||||
wifiDirectManager.changeStatus(fileIndex, fileStatus);
|
||||
|
||||
final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get();
|
||||
if(fileStatus == ERROR) {
|
||||
showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, incomingFileName), Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
@ -39,10 +39,12 @@ class SenderDeviceAsyncTask extends AsyncTask<Uri, Integer, Boolean> {
|
||||
private static final String TAG = "SenderDeviceAsyncTask";
|
||||
|
||||
private WeakReference<LocalFileTransferActivity> weakReferenceToActivity;
|
||||
private WifiDirectManager wifiDirectManager;
|
||||
private int fileItemIndex = -1;
|
||||
|
||||
public SenderDeviceAsyncTask(LocalFileTransferActivity localFileTransferActivity) {
|
||||
public SenderDeviceAsyncTask(WifiDirectManager wifiDirectManager, LocalFileTransferActivity localFileTransferActivity) {
|
||||
this.weakReferenceToActivity = new WeakReference<>(localFileTransferActivity);
|
||||
this.wifiDirectManager = wifiDirectManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,7 +76,7 @@ class SenderDeviceAsyncTask extends AsyncTask<Uri, Integer, Boolean> {
|
||||
}
|
||||
socket.bind(null);
|
||||
|
||||
String hostAddress = localFileTransferActivity.wifiDirectManager.getFileReceiverDeviceAddress().getHostAddress();
|
||||
String hostAddress = wifiDirectManager.getFileReceiverDeviceAddress().getHostAddress();
|
||||
socket.connect((new InetSocketAddress(hostAddress, FILE_TRANSFER_PORT)), 15000);
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Sender socket - " + socket.isConnected());
|
||||
@ -94,7 +96,7 @@ class SenderDeviceAsyncTask extends AsyncTask<Uri, Integer, Boolean> {
|
||||
publishProgress(fileItemIndex, ERROR);
|
||||
}
|
||||
|
||||
localFileTransferActivity.wifiDirectManager.incrementTotalFilesSent();
|
||||
wifiDirectManager.incrementTotalFilesSent();
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -105,10 +107,10 @@ class SenderDeviceAsyncTask extends AsyncTask<Uri, Integer, Boolean> {
|
||||
int fileIndex = values[0];
|
||||
int fileStatus = values[1];
|
||||
final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get();
|
||||
localFileTransferActivity.changeStatus(fileIndex, fileStatus);
|
||||
wifiDirectManager.changeStatus(fileIndex, fileStatus);
|
||||
|
||||
if(fileStatus == ERROR) {
|
||||
showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, getFileName(localFileTransferActivity.wifiDirectManager.getFileUriArrayList().get(fileItemIndex))), Toast.LENGTH_SHORT);
|
||||
showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, getFileName(wifiDirectManager.getFileUriArrayList().get(fileItemIndex))), Toast.LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +122,7 @@ class SenderDeviceAsyncTask extends AsyncTask<Uri, Integer, Boolean> {
|
||||
protected void onPostExecute(Boolean fileSendSuccessful) {
|
||||
final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get();
|
||||
|
||||
if (localFileTransferActivity.wifiDirectManager.allFilesSent()) {
|
||||
if (wifiDirectManager.allFilesSent()) {
|
||||
showToast(localFileTransferActivity, R.string.file_transfer_complete,
|
||||
Toast.LENGTH_SHORT);
|
||||
localFileTransferActivity.finish();
|
||||
|
@ -72,7 +72,7 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
|
||||
private int totalFilesForTransfer = -1;
|
||||
private int filesSent = 0; // Count of number of files transferred until now
|
||||
private ArrayList<FileItem> filesToSend = new ArrayList<>();
|
||||
private ArrayList<FileItem> filesForTransfer = new ArrayList<>();
|
||||
|
||||
private ArrayList<Uri> fileUriArrayList; // For sender device, stores uris of the files
|
||||
public boolean isFileSender = false; // Whether the device is the file sender or not
|
||||
@ -83,17 +83,19 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
|
||||
/* Initialisations for using the WiFi P2P API */
|
||||
public void createWifiDirectManager(@NonNull SharedPreferenceUtil sharedPreferenceUtil,
|
||||
@NonNull AlertDialogShower alertDialogShower, @Nullable ArrayList<Uri> fileUriArrayList) {
|
||||
@NonNull AlertDialogShower alertDialogShower, @Nullable ArrayList<Uri> fileUriArrayList,
|
||||
@Nullable ArrayList<FileItem> filesForTransfer) {
|
||||
this.sharedPreferenceUtil = sharedPreferenceUtil;
|
||||
this.alertDialogShower = alertDialogShower;
|
||||
this.fileUriArrayList = fileUriArrayList;
|
||||
this.filesForTransfer = filesForTransfer;
|
||||
this.isFileSender = (fileUriArrayList != null && fileUriArrayList.size() > 0);
|
||||
|
||||
if(isFileSender) {
|
||||
this.totalFilesForTransfer = fileUriArrayList.size();
|
||||
for (int i = 0; i < fileUriArrayList.size(); i++) {
|
||||
filesToSend.add(new FileItem(getFileName(fileUriArrayList.get(i)), TO_BE_SENT));
|
||||
}
|
||||
/*for (int i = 0; i < fileUriArrayList.size(); i++) {
|
||||
filesForTransfer.add(new FileItem(getFileName(fileUriArrayList.get(i)), TO_BE_SENT));
|
||||
}*/
|
||||
}
|
||||
|
||||
manager = (WifiP2pManager) activity.getSystemService(Context.WIFI_P2P_SERVICE);
|
||||
@ -142,19 +144,22 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
|
||||
if(wifiP2pEnabled == false) {
|
||||
showToast(activity, R.string.discovery_needs_wifi, Toast.LENGTH_SHORT);
|
||||
activity.clearPeers();
|
||||
((Callbacks) activity).clearListOfAvailablePeers();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
activity.clearPeers();
|
||||
((Callbacks) activity).clearListOfAvailablePeers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceChanged(@Nullable WifiP2pDevice userDevice) {
|
||||
// Update UI with wifi-direct details about the user device
|
||||
activity.updateUserDevice(userDevice);
|
||||
if(userDevice != null) {
|
||||
setUserDevice(userDevice);
|
||||
}
|
||||
((Callbacks) activity).onUserDeviceDetailsAvailable(userDevice);
|
||||
}
|
||||
|
||||
public boolean isWifiP2pEnabled() {
|
||||
@ -167,7 +172,7 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
// Upon disconnection, retry one more time
|
||||
if (manager != null && !retryChannel) {
|
||||
Log.d(TAG, "Channel lost, trying again");
|
||||
activity.clearPeers();
|
||||
((Callbacks) activity).clearListOfAvailablePeers();
|
||||
retryChannel = true;
|
||||
manager.initialize(activity, getMainLooper(), this);
|
||||
} else {
|
||||
@ -178,7 +183,7 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
/* From WifiP2pManager.PeerListListener callback-interface */
|
||||
@Override
|
||||
public void onPeersAvailable(@NonNull WifiP2pDeviceList peers) {
|
||||
((Callbacks) activity).updatePeerDevicesList(peers);
|
||||
((Callbacks) activity).updateListOfAvailablePeers(peers);
|
||||
}
|
||||
|
||||
/* From WifiP2pManager.ConnectionInfoListener callback-interface */
|
||||
@ -189,7 +194,7 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
performHandshakeWithSelectedPeerDevice();
|
||||
}
|
||||
|
||||
public void setUserDevice(@NonNull WifiP2pDevice userDevice) {
|
||||
private void setUserDevice(@NonNull WifiP2pDevice userDevice) {
|
||||
this.userDevice = userDevice;
|
||||
}
|
||||
|
||||
@ -212,6 +217,7 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
new KiwixDialog.FileTransferConfirmation(senderSelectedPeerDevice.deviceName),
|
||||
new Function0<Unit>() {
|
||||
@Override public Unit invoke() {
|
||||
((Callbacks) activity).onSenderStartedConnection();
|
||||
connect();
|
||||
showToast(activity, R.string.performing_handshake, Toast.LENGTH_LONG);
|
||||
return Unit.INSTANCE;
|
||||
@ -269,11 +275,11 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
}
|
||||
|
||||
public @NonNull ArrayList<FileItem> getFileItems() {
|
||||
return filesToSend;
|
||||
return filesForTransfer;
|
||||
}
|
||||
|
||||
public void setFileItems(@NonNull ArrayList<FileItem> fileItems) {
|
||||
this.filesToSend = fileItems;
|
||||
this.filesForTransfer = fileItems;
|
||||
}
|
||||
|
||||
public void incrementTotalFilesSent() {
|
||||
@ -325,9 +331,9 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
isFileTransferInProgress = true;
|
||||
|
||||
if (isGroupFormed() && !isFileSender) {
|
||||
((Callbacks) activity).displayFileTransferProgress(filesToSend);
|
||||
((Callbacks) activity).onFilesForTransferAvailable(filesForTransfer);
|
||||
|
||||
receiverDeviceAsyncTask = new ReceiverDeviceAsyncTask(activity);
|
||||
receiverDeviceAsyncTask = new ReceiverDeviceAsyncTask(this, activity);
|
||||
receiverDeviceAsyncTask.execute();
|
||||
} else if (isGroupFormed()) { // && isFileSender
|
||||
{
|
||||
@ -341,13 +347,18 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
showToast(activity, R.string.preparing_files, Toast.LENGTH_LONG);
|
||||
//for (int i = 0; i < 20000000; i++) ;
|
||||
|
||||
senderDeviceAsyncTaskArray = new SenderDeviceAsyncTask(activity);
|
||||
senderDeviceAsyncTaskArray = new SenderDeviceAsyncTask(this, activity);
|
||||
senderDeviceAsyncTaskArray.execute(fileUriArrayList.toArray(new Uri[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cancelAsyncTasks() {
|
||||
public void changeStatus(int itemIndex, @FileItem.FileStatus int status) {
|
||||
filesForTransfer.get(itemIndex).setFileStatus(status);
|
||||
((Callbacks) activity).onFileStatusChanged(itemIndex);
|
||||
}
|
||||
|
||||
private void cancelAsyncTasks() {
|
||||
if (peerGroupHandshakeAsyncTask != null) {
|
||||
peerGroupHandshakeAsyncTask.cancel(true);
|
||||
}
|
||||
@ -360,7 +371,6 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Shift async tasks to WDM and handle cleanup from here itself
|
||||
public void destroyWifiDirectManager() {
|
||||
cancelAsyncTasks();
|
||||
|
||||
@ -436,8 +446,16 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
void updatePeerDevicesList(@NonNull WifiP2pDeviceList peers);
|
||||
void onUserDeviceDetailsAvailable(@Nullable WifiP2pDevice userDevice);
|
||||
|
||||
void displayFileTransferProgress(ArrayList<FileItem> filesToSend);
|
||||
void clearListOfAvailablePeers();
|
||||
|
||||
void updateListOfAvailablePeers(@NonNull WifiP2pDeviceList peers);
|
||||
|
||||
void onSenderStartedConnection();
|
||||
|
||||
void onFilesForTransferAvailable(@NonNull ArrayList<FileItem> filesForTransfer);
|
||||
|
||||
void onFileStatusChanged(int itemIndex);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user