光环前端优化汇总(2021年2月)(4) https://git.ghzs.com/pm/halo-app-issues/-/issues/1154
This commit is contained in:
@ -225,6 +225,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_CATEGORY_LIST = "categoty_list";
|
||||
public static final String KEY_IS_FREE = "is_free";
|
||||
public static final String KEY_IS_SIGN = "is_sign";
|
||||
public static final String KEY_IS_CHOOSE_APK = "is_choose_apk";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
@ -2,8 +2,11 @@ package com.gh.gamecenter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.halo.assistant.fragment.ApkCleanerFragment;
|
||||
|
||||
/**
|
||||
@ -13,7 +16,14 @@ public class CleanApkActivity extends NormalActivity {
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context) {
|
||||
return getTargetIntent(context, CleanApkActivity.class, ApkCleanerFragment.class);
|
||||
return getIntent(context, false);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, Boolean isChooseApk) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(EntranceUtils.KEY_IS_CHOOSE_APK, isChooseApk);
|
||||
return getTargetIntent(context, CleanApkActivity.class, ApkCleanerFragment.class, bundle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import android.os.Environment;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
@ -18,6 +19,7 @@ import com.gh.common.util.BitmapUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.TimeUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.KcSelectGameViewHolder;
|
||||
import com.gh.gamecenter.entity.InstallGameEntity;
|
||||
@ -30,6 +32,7 @@ import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
@ -57,11 +60,13 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
|
||||
private boolean mIsStopScan;
|
||||
private boolean mIsScanOver;
|
||||
private boolean mIsChooseApk;
|
||||
|
||||
public CleanApkAdapter(Context context, OnScanListener listener, TextView apkDeleteBtn, CheckBox apkSelectAll) {
|
||||
public CleanApkAdapter(Context context, OnScanListener listener, TextView apkDeleteBtn, CheckBox apkSelectAll, boolean isChooseApk) {
|
||||
super(context);
|
||||
mApkDeleteBtn = apkDeleteBtn;
|
||||
mApkSelectAll = apkSelectAll;
|
||||
mIsChooseApk = isChooseApk;
|
||||
|
||||
mScanListener = listener;
|
||||
|
||||
@ -75,14 +80,11 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
}
|
||||
|
||||
private void init() {
|
||||
Observable.create(new ObservableOnSubscribe<Object>() {
|
||||
@Override
|
||||
public void subscribe(ObservableEmitter<Object> emitter) {
|
||||
// 扫描和获取apk数据 分步操作 尽量避免 StackoverflowError
|
||||
FindAllAPKPath(Environment.getExternalStorageDirectory());
|
||||
LoadApkData();
|
||||
emitter.onComplete();
|
||||
}
|
||||
Observable.create(emitter -> {
|
||||
// 扫描和获取apk数据 分步操作 尽量避免 StackoverflowError
|
||||
FindAllAPKPath(Environment.getExternalStorageDirectory());
|
||||
LoadApkData();
|
||||
emitter.onComplete();
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
@ -129,6 +131,8 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
|
||||
File file = new File(apk_path);
|
||||
apkEntity.setGameSize(file.length());
|
||||
apkEntity.setLastUpdateTime(file.lastModified());
|
||||
apkEntity.setPackageName(PackageUtils.getPackageNameByPath(mContext, apk_path));
|
||||
|
||||
/**安装处理类型*/
|
||||
/** 得到包名 */
|
||||
@ -139,12 +143,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
mApkList.add(apkEntity);
|
||||
mSelectPosition.put((mApkList.size() - 1), false);
|
||||
|
||||
RuntimeUtils.getInstance().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
notifyItemChanged((mApkList.size() - 1));
|
||||
}
|
||||
});
|
||||
RuntimeUtils.getInstance().runOnUiThread(() -> notifyItemChanged((mApkList.size() - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,17 +214,27 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
}
|
||||
|
||||
holder.gameNameAndSize.setText(gameEntity.getGameName());
|
||||
holder.gameDes.setText(mContext.getString(R.string.clean_apk_version, gameEntity.getGameVersion(), sizeName));
|
||||
holder.gameDes.setTextColor(ContextCompat.getColor(mContext, R.color.content));
|
||||
|
||||
holder.gameThumb.setImageBitmap(gameEntity.getGameBm());
|
||||
|
||||
if (gameEntity.getInstallStatus() == INSTALLED) {
|
||||
holder.gameSize.setText(R.string.installed);
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
if (!mIsChooseApk) {
|
||||
if (gameEntity.getInstallStatus() == INSTALLED) {
|
||||
holder.gameSize.setText(R.string.installed);
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
} else {
|
||||
holder.gameSize.setText(R.string.installed_not);
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.red));
|
||||
}
|
||||
holder.gameDes.setText(mContext.getString(R.string.clean_apk_version, gameEntity.getGameVersion(), sizeName));
|
||||
holder.gameDes.setTextColor(ContextCompat.getColor(mContext, R.color.content));
|
||||
} else {
|
||||
holder.gameSize.setText(R.string.installed_not);
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.red));
|
||||
holder.gameSize.setVisibility(View.GONE);
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.gameDes.getLayoutParams();
|
||||
params.bottomMargin = 0;
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
holder.gameDes.setLayoutParams(params);
|
||||
String des = TimeUtils.getFormatTime(gameEntity.getLastUpdateTime(), "yyyy-MM-dd HH:mm") + " " + sizeName;
|
||||
holder.gameDes.setText(des);
|
||||
}
|
||||
|
||||
if (mIsScanOver) {
|
||||
@ -234,9 +243,8 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
holder.selectCB.setEnabled(false);
|
||||
}
|
||||
|
||||
holder.checkBoxRl.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
holder.checkBoxRl.setOnClickListener(v -> {
|
||||
if (!mIsChooseApk) {
|
||||
if (mSelectPosition.get(holder.getAdapterPosition())) {
|
||||
checkBoxControl(false, holder.getAdapterPosition());
|
||||
holder.selectCB.setChecked(false);
|
||||
@ -244,12 +252,13 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
checkBoxControl(true, holder.getAdapterPosition());
|
||||
holder.selectCB.setChecked(true);
|
||||
}
|
||||
} else {
|
||||
singleChoose(position);
|
||||
}
|
||||
});
|
||||
|
||||
holder.selectCB.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
holder.selectCB.setOnClickListener(v -> {
|
||||
if (!mIsChooseApk) {
|
||||
if (mSelectPosition.get(holder.getAdapterPosition())) {
|
||||
checkBoxControl(false, holder.getAdapterPosition());
|
||||
holder.selectCB.setChecked(false);
|
||||
@ -259,12 +268,15 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
holder.selectCB.setChecked(true);
|
||||
MtaHelper.onEvent("我的光环_设置", "安装包清理", "选中");
|
||||
}
|
||||
} else {
|
||||
singleChoose(position);
|
||||
}
|
||||
});
|
||||
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mIsChooseApk) {
|
||||
singleChoose(position);
|
||||
} else {
|
||||
if (mIsScanOver) {
|
||||
mContext.startActivity(PackageInstaller.getInstallIntent(mContext, gameEntity.getGamePath()));
|
||||
}
|
||||
@ -304,10 +316,17 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
DecimalFormat df = new DecimalFormat("0.00");
|
||||
String sizeName = df.format(size) + "MB";
|
||||
mApkDeleteBtn.setText(mContext.getString(R.string.clean_apk_deleteall, i, sizeName));
|
||||
// mApkDeleteBtn.setText(StringUtils.buildString("一键删除(", String.valueOf(i), "个,释放" + sizeName, ")"));
|
||||
}
|
||||
}
|
||||
|
||||
public void singleChoose(int position) {
|
||||
for (Integer integer : mSelectPosition.keySet()) {
|
||||
mSelectPosition.put(integer, false);
|
||||
}
|
||||
mSelectPosition.put(position, true);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mApkList.size();
|
||||
|
||||
@ -17,6 +17,8 @@ class InstallGameEntity {
|
||||
|
||||
var gamePath: String? = null
|
||||
|
||||
var lastUpdateTime: Long = 0
|
||||
|
||||
/**
|
||||
* 安装状态 用于清理安装包
|
||||
*/
|
||||
|
||||
@ -20,6 +20,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.OnListClickListener
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.CleanApkActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.InstallGameEntity
|
||||
@ -404,10 +405,8 @@ class GameUploadFragment : NormalFragment() {
|
||||
}
|
||||
manualBtn.setOnClickListener {
|
||||
MtaHelper.onEvent("游戏上传", "安装包", "从设备上选择")
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
startActivityForResult(intent, MEDIA_APK_STORE_REQUEST)
|
||||
val intent = CleanApkActivity.getIntent(requireContext(), true)
|
||||
startActivityForResult(intent, CHOOSE_LOCAL_APK)
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,43 +453,25 @@ class GameUploadFragment : NormalFragment() {
|
||||
} catch (e: Exception) {
|
||||
ToastUtils.showToast(e.message ?: "")
|
||||
}
|
||||
} else if (requestCode == MEDIA_APK_STORE_REQUEST) {
|
||||
val uri = data.data ?: return
|
||||
val apkPath = PathUtils.getPath(requireContext(), uri)
|
||||
if (!apkPath.isNullOrEmpty()) {
|
||||
if (!apkPath.endsWith(".apk")) {
|
||||
ToastUtils.showToast("请选择正确的安装包")
|
||||
return
|
||||
}
|
||||
mSelectGameDialog?.cancel()
|
||||
try {
|
||||
val file = File(apkPath)
|
||||
if (file.length() > 5 * 1024 * 1024 * 1024) {
|
||||
ToastUtils.showToast(getString(R.string.apk_max_size_hint, 5))
|
||||
} else {
|
||||
val packageName = PackageUtils.getPackageNameByPath(requireContext(), apkPath)
|
||||
val version = PackageUtils.getVersionByPackage(packageName)
|
||||
mInstallGameEntity = InstallGameEntity().apply {
|
||||
this.packageName = packageName
|
||||
this.gameSize = File(apkPath).length()
|
||||
this.gamePath = apkPath
|
||||
this.gameVersion = version
|
||||
}
|
||||
chooseGameLl.background = null
|
||||
chooseGameLl.setPadding(0, 0, 0, 0)
|
||||
chooseGameIconIv.visibility = View.GONE
|
||||
tv_choose.text = packageName
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
ToastUtils.showToast(e.message ?: "")
|
||||
}
|
||||
} else {
|
||||
ToastUtils.showToast("文件选择失败,请从已安装游戏列表中选择")
|
||||
} else if (requestCode == CHOOSE_LOCAL_APK) {
|
||||
val packageName = data.getStringExtra(EntranceUtils.KEY_PACKAGENAME) ?: ""
|
||||
val gamePath = data.getStringExtra(EntranceUtils.KEY_PATH) ?: ""
|
||||
val version = PackageUtils.getVersionByPackage(packageName)
|
||||
val length = File(gamePath).length()
|
||||
if (length > 5 * 1024 * 1024 * 1024) {
|
||||
ToastUtils.showToast(getString(R.string.apk_max_size_hint, 5))
|
||||
return
|
||||
}
|
||||
mInstallGameEntity = InstallGameEntity().apply {
|
||||
this.packageName = packageName
|
||||
this.gameSize = length
|
||||
this.gamePath = gamePath
|
||||
this.gameVersion = version
|
||||
}
|
||||
loadDone(mInstallGameEntity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
if (!TextUtils.isEmpty(tv_choose.text.toString()) ||
|
||||
!TextUtils.isEmpty(et_game_name.text.toString()) ||
|
||||
@ -570,5 +551,6 @@ class GameUploadFragment : NormalFragment() {
|
||||
const val MEDIA_STORE_REQUEST = 100
|
||||
const val MEDIA_ICON_STORE_REQUEST = 101
|
||||
const val MEDIA_APK_STORE_REQUEST = 102
|
||||
const val CHOOSE_LOCAL_APK = 103
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package com.halo.assistant.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
@ -14,7 +16,9 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.ToastUtils;
|
||||
import com.gh.common.view.VerticalItemDecoration;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.MainActivity;
|
||||
@ -61,6 +65,7 @@ public class ApkCleanerFragment extends NormalFragment implements CleanApkAdapte
|
||||
View mInstallAllData;
|
||||
|
||||
private CleanApkAdapter mAdapter;
|
||||
private boolean isChooseApk = false;
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
@ -70,11 +75,11 @@ public class ApkCleanerFragment extends NormalFragment implements CleanApkAdapte
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setNavigationTitle(getString(R.string.title_clean_apk));
|
||||
|
||||
isChooseApk = requireArguments().getBoolean(EntranceUtils.KEY_IS_CHOOSE_APK, false);
|
||||
setNavigationTitle(isChooseApk ? getString(R.string.title_choose_apk) : getString(R.string.title_clean_apk));
|
||||
mNodataSkipLl.setVisibility(View.GONE);
|
||||
|
||||
mAdapter = new CleanApkAdapter(getContext(), this, mApkDeleteBtn, mApkSelectAll);
|
||||
mAdapter = new CleanApkAdapter(getContext(), this, mApkDeleteBtn, mApkSelectAll, isChooseApk);
|
||||
mApkRv.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
mApkRv.addItemDecoration(new VerticalItemDecoration(getContext(), 8, true));
|
||||
mApkRv.setAdapter(mAdapter);
|
||||
@ -111,10 +116,15 @@ public class ApkCleanerFragment extends NormalFragment implements CleanApkAdapte
|
||||
mAdapter.checkBoxControl(isChecked, 0);
|
||||
});
|
||||
|
||||
mNodataSkipBtn.setText("去首页看看");
|
||||
mNodataSkipTv.setText("安装包已清理干净\n快去发现更多好玩的游戏吧!");
|
||||
mNodataSkipTv.setLineSpacing(0, 1.5f);
|
||||
|
||||
if (isChooseApk) {
|
||||
mApkSelectAll.setVisibility(View.GONE);
|
||||
mNodataSkipBtn.setVisibility(View.GONE);
|
||||
mNodataSkipTv.setText("暂无安装包");
|
||||
} else {
|
||||
mNodataSkipBtn.setText("去首页看看");
|
||||
mNodataSkipTv.setText("安装包已清理干净\n快去发现更多好玩的游戏吧!");
|
||||
mNodataSkipTv.setLineSpacing(0, 1.5f);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick({R.id.delete_btn, R.id.reuse_nodata_skip_tv_btn})
|
||||
@ -126,26 +136,39 @@ public class ApkCleanerFragment extends NormalFragment implements CleanApkAdapte
|
||||
MtaHelper.onEvent("我的光环_设置", "安装包清理", "停止扫描");
|
||||
mAdapter.isStopScan();
|
||||
} else {
|
||||
final List<InstallGameEntity> apkList = mAdapter.getApkList();
|
||||
final ArrayMap<Integer, Boolean> selectPosition = mAdapter.getSelectPosition();
|
||||
if (isChooseApk) {
|
||||
InstallGameEntity installGameEntity = null;
|
||||
for (Integer integer : selectPosition.keySet()) {
|
||||
if (selectPosition.get(integer)) {
|
||||
installGameEntity = apkList.get(integer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (installGameEntity == null) {
|
||||
ToastUtils.showToast("请选择需要上传的安装包");
|
||||
} else {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EntranceUtils.KEY_PACKAGENAME, installGameEntity.getPackageName());
|
||||
intent.putExtra(EntranceUtils.KEY_PATH, installGameEntity.getGamePath());
|
||||
requireActivity().setResult(Activity.RESULT_OK, intent);
|
||||
requireActivity().finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ("一键删除".equals(s)) {
|
||||
Utils.toast(getContext(), "请选择需要删除的安装包");
|
||||
ToastUtils.showToast("请选择需要删除的安装包");
|
||||
return;
|
||||
}
|
||||
MtaHelper.onEvent("我的光环_设置", "安装包清理", "一键删除");
|
||||
|
||||
final List<InstallGameEntity> apkList = mAdapter.getApkList();
|
||||
final ArrayMap<Integer, Boolean> selectPosition = mAdapter.getSelectPosition();
|
||||
|
||||
for (int i = 0; i < apkList.size(); i++) {
|
||||
if (selectPosition.get(i) && apkList.get(i).getInstallStatus() == 1) {
|
||||
DialogUtils.showWarningDialog(getContext(), "删除安装包"
|
||||
, Html.fromHtml(getString(R.string.delete_apk_hint))
|
||||
, "取消 ", "确定"
|
||||
, new DialogUtils.ConfirmListener() {
|
||||
@Override
|
||||
public void onConfirm() {
|
||||
deleteApk(apkList, selectPosition);
|
||||
}
|
||||
}, null);
|
||||
, () -> deleteApk(apkList, selectPosition), null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -211,25 +234,31 @@ public class ApkCleanerFragment extends NormalFragment implements CleanApkAdapte
|
||||
@Override
|
||||
public void onScanOver() {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
||||
mApkDeleteBtn.setText("立即删除");
|
||||
mApkDeleteBtn.setTextColor(Color.WHITE);
|
||||
mApkDeleteBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
|
||||
|
||||
updateScanData();
|
||||
|
||||
mScanPb.setVisibility(View.GONE);
|
||||
mApkSelectAll.setVisibility(View.VISIBLE);
|
||||
mApkSelectAll.setChecked(true);
|
||||
if (!isChooseApk) {
|
||||
updateScanData();
|
||||
mApkDeleteBtn.setText("立即删除");
|
||||
mApkSelectAll.setVisibility(View.VISIBLE);
|
||||
mApkSelectAll.setChecked(true);
|
||||
} else {
|
||||
mApkCount.setText("扫描完成");
|
||||
mApkDeleteBtn.setText("确定");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noData() {
|
||||
if (isChooseApk) {
|
||||
mNodataSkipBtn.setVisibility(View.GONE);
|
||||
}
|
||||
mNodataSkipBtn.setText("去首页看看");
|
||||
mNodataSkipTv.setText("暂无安装包");
|
||||
mNodataSkipLl.setVisibility(View.VISIBLE);
|
||||
mInstallAllData.setVisibility(View.GONE);
|
||||
mDeleteBottom.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user