个人主页编辑头像修改
This commit is contained in:
@@ -117,6 +117,8 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import fragmentation.ISupportActivity;
|
||||
import fragmentation.SupportActivityDelegate;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
@@ -126,7 +128,7 @@ import io.reactivex.disposables.CompositeDisposable;
|
||||
* @author alvin hwang
|
||||
*/
|
||||
public abstract class BaseActivity extends RxAppCompatActivity
|
||||
implements IDataStatus, DialogManagerInterface {
|
||||
implements IDataStatus, DialogManagerInterface, ISupportActivity {
|
||||
|
||||
/**
|
||||
* --------------------------------------------------
|
||||
@@ -146,9 +148,12 @@ public abstract class BaseActivity extends RxAppCompatActivity
|
||||
private OpenNobleGlobalNoticeDialog mNoticeDialog;
|
||||
private boolean isShowingChargeDialog;
|
||||
|
||||
private final SupportActivityDelegate mActivityDelegate = new SupportActivityDelegate(this);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.mActivityDelegate.onCreate();
|
||||
context = this;
|
||||
mCompositeDisposable = new CompositeDisposable();
|
||||
if (needSteepStateBar()) {
|
||||
@@ -321,6 +326,21 @@ public abstract class BaseActivity extends RxAppCompatActivity
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SupportActivityDelegate getSupportDelegate() {
|
||||
return this.mActivityDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onBackPressedPage() {
|
||||
this.mActivityDelegate.onBackPressedPage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressedSupport() {
|
||||
this.mActivityDelegate.onBackPressedSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResID) {
|
||||
super.setContentView(layoutResID);
|
||||
|
@@ -1,104 +0,0 @@
|
||||
package com.yizhuan.erban.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.GlideBuilder;
|
||||
import com.bumptech.glide.Registry;
|
||||
import com.bumptech.glide.load.engine.cache.DiskCache;
|
||||
import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper;
|
||||
import com.bumptech.glide.manager.ConnectivityMonitor;
|
||||
import com.bumptech.glide.manager.ConnectivityMonitorFactory;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
import com.netease.nim.uikit.api.NimUIKit;
|
||||
import com.netease.nim.uikit.common.util.log.LogUtil;
|
||||
import com.yizhuan.xchat_android_library.utils.file.StorageUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* <p> 应用工程的glide 配置 </p>
|
||||
* Created by Administrator on 2017/11/14.
|
||||
*/
|
||||
//@GlideModule
|
||||
public class XchatGlideModule extends AppGlideModule {
|
||||
private static final String TAG = "NIMGlideModule";
|
||||
|
||||
private static final int M = 1024 * 1024;
|
||||
private static final int MAX_DISK_CACHE_SIZE = 256 * M;
|
||||
private static DiskCache diskCache = null;
|
||||
|
||||
/**
|
||||
* ************************ Disk Cache ************************
|
||||
*/
|
||||
private static synchronized DiskCache getDiskCache() {
|
||||
if (diskCache == null) {
|
||||
diskCache = createDiskCache();
|
||||
}
|
||||
return diskCache;
|
||||
}
|
||||
|
||||
private static synchronized DiskCache createDiskCache() {
|
||||
final Context context = NimUIKit.getContext();
|
||||
File cacheDir = StorageUtils.getOwnCacheDirectory(context, context.getPackageName() + "/cache/image/");
|
||||
if (!cacheDir.exists()) {
|
||||
cacheDir.mkdirs();
|
||||
}
|
||||
return DiskLruCacheWrapper.get(cacheDir, MAX_DISK_CACHE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************ Memory Cache ************************
|
||||
*/
|
||||
|
||||
static void clearMemoryCache(Context context) {
|
||||
Glide.get(context).clearMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************ GlideModule override ************************
|
||||
*/
|
||||
@Override
|
||||
public void applyOptions(Context context, GlideBuilder builder) {
|
||||
builder.setDiskCache(new DiskCache.Factory() {
|
||||
@Override
|
||||
public DiskCache build() {
|
||||
return getDiskCache();
|
||||
}
|
||||
});
|
||||
//广播过多问题,这里不监听链接状态
|
||||
builder.setConnectivityMonitorFactory(new MyConnectivityMonitorFactory());
|
||||
|
||||
LogUtil.i(TAG, "NIMGlideModule apply options");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerComponents(Context context, Glide glide, Registry registry) {
|
||||
super.registerComponents(context, glide, registry);
|
||||
}
|
||||
|
||||
|
||||
public class MyConnectivityMonitorFactory implements ConnectivityMonitorFactory {
|
||||
public ConnectivityMonitor build(Context context, ConnectivityMonitor.ConnectivityListener listener) {
|
||||
return new ConnectivityMonitor() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -14,7 +14,7 @@ import kotlinx.coroutines.Job
|
||||
import com.yizhuan.xchat_android_library.EasyPermissions
|
||||
import com.yizhuan.erban.R
|
||||
import com.yizhuan.erban.application.XChatApplication
|
||||
import com.yizhuan.erban.base.BaseDialogFragment
|
||||
import base.BaseDialogFragment
|
||||
import com.yizhuan.erban.common.photo.PhotoProvider
|
||||
import com.yizhuan.erban.common.util.PhotoCompressCallback
|
||||
import com.yizhuan.erban.common.util.PhotoCompressUtil
|
||||
|
@@ -29,7 +29,7 @@ import com.bumptech.glide.request.target.DrawableImageViewTarget
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.yizhuan.erban.common.transform.AssignScaleTransformation
|
||||
import com.yizhuan.erban.common.transform.ComplexTransformation
|
||||
import com.yizhuan.erban.common.util.ActivityHelper
|
||||
import util.ActivityHelper
|
||||
import com.yizhuan.erban.common.util.Utils
|
||||
import com.yizhuan.xchat_android_core.utils.Logger
|
||||
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
|
||||
|
@@ -11,6 +11,8 @@ import com.yizhuan.erban.application.XChatApplication;
|
||||
import com.yizhuan.erban.location.LocationManager;
|
||||
import com.yizhuan.xchat_android_core.auth.AuthModel;
|
||||
|
||||
import util.CoreUtils;
|
||||
|
||||
/**
|
||||
* Activity生命周期工具类
|
||||
*/
|
||||
|
164
app/src/main/java/com/yizhuan/erban/common/util/BitmapUtil.java
Normal file
164
app/src/main/java/com/yizhuan/erban/common/util/BitmapUtil.java
Normal file
@@ -0,0 +1,164 @@
|
||||
package com.yizhuan.erban.common.util;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.yizhuan.erban.application.XChatApplication;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import util.Logger;
|
||||
|
||||
/**
|
||||
* Created by wushaocheng
|
||||
* Date: 2022/11/17
|
||||
*/
|
||||
public class BitmapUtil {
|
||||
|
||||
private static final String TAG = "BitmapUtil";
|
||||
|
||||
public static Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) {
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
options.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
BitmapFactory.decodeFileDescriptor(fd, null, options);
|
||||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
|
||||
options.inJustDecodeBounds = false;
|
||||
return BitmapFactory.decodeFileDescriptor(fd, null, options);
|
||||
}
|
||||
|
||||
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
||||
if (reqWidth == 0 || reqHeight == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
final int height = options.outHeight;
|
||||
final int width = options.outWidth;
|
||||
Logger.info(TAG, "origin, w= " + width + " h=" + height);
|
||||
int inSampleSize = 1;
|
||||
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
final int halfHeight = height / 2;
|
||||
final int halfWidth = width / 2;
|
||||
|
||||
while ((halfHeight / inSampleSize) >= reqHeight
|
||||
&& (halfWidth / inSampleSize) >= reqWidth) {
|
||||
inSampleSize *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info(TAG, "sampleSize:" + inSampleSize);
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
public static Bitmap setImgSize(Bitmap bm, float newWidth, float newHeight) {
|
||||
if (bm == null) {
|
||||
Logger.error(TAG, "bitmap is null.");
|
||||
return null;
|
||||
}
|
||||
// 获得图片的宽高.
|
||||
int width = bm.getWidth();
|
||||
int height = bm.getHeight();
|
||||
// 计算缩放比例.
|
||||
float scaleWidth = newWidth / width;
|
||||
float scaleHeight = newHeight / height;
|
||||
// 取得想要缩放的matrix参数.
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(scaleWidth, scaleHeight);
|
||||
// 得到新的图片.
|
||||
return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
|
||||
}
|
||||
|
||||
public static Point getImageSize(String imgPath) {
|
||||
Point point = new Point();
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(imgPath, options);
|
||||
point.x = options.outWidth;
|
||||
point.y = options.outHeight;
|
||||
return point;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取sd卡上的bitmap的大小
|
||||
* 不加载进内存
|
||||
*/
|
||||
public static long getSdBitmapSize(Uri imageUri) {
|
||||
return getSdBitmapSize(imageUri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* androidQ 以上使用path拿不到图片信息,换成Uri
|
||||
*
|
||||
* @param imageUri
|
||||
* @param inPreferredConfig
|
||||
* @return
|
||||
*/
|
||||
private static long getSdBitmapSize(Uri imageUri, Bitmap.Config inPreferredConfig) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
if (inPreferredConfig != null) {
|
||||
options.inPreferredConfig = inPreferredConfig;
|
||||
}
|
||||
try {
|
||||
InputStream stream = XChatApplication.gContext.getContentResolver().openInputStream(imageUri);
|
||||
BitmapFactory.decodeStream(stream, null, options);
|
||||
switch (options.inPreferredConfig) {
|
||||
case ALPHA_8:
|
||||
return options.outWidth * options.outHeight;
|
||||
case RGB_565:
|
||||
case ARGB_4444:
|
||||
return options.outWidth * options.outHeight * 2;
|
||||
case RGBA_F16:
|
||||
return options.outWidth * options.outHeight * 8;
|
||||
case ARGB_8888:
|
||||
default:
|
||||
return options.outWidth * options.outHeight * 4;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap convertBitmap(Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
float density = XChatApplication.gContext.getResources().getDisplayMetrics().density;
|
||||
return BitmapUtil.setImgSize(bitmap, bitmap.getWidth() * density / 3.0f, bitmap.getHeight() * density / 3.0f);
|
||||
}
|
||||
|
||||
public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
||||
int width = options.outWidth;
|
||||
int height = options.outHeight;
|
||||
int inSampleSize = 1;
|
||||
if (width > reqWidth || height > reqHeight) {
|
||||
int widthRadio = Math.round(width * 1.0f / reqWidth);
|
||||
int heightRadio = Math.round(height * 1.0f / reqHeight);
|
||||
inSampleSize = Math.max(widthRadio, heightRadio);
|
||||
}
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
|
||||
public static byte[] inputStream2ByteArr(InputStream inputStream) throws IOException {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buff = new byte[1024];
|
||||
int len = 0;
|
||||
while ( (len = inputStream.read(buff)) != -1) {
|
||||
outputStream.write(buff, 0, len);
|
||||
}
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
@@ -9,11 +9,14 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.yizhuan.erban.base.BaseActivity;
|
||||
import com.yizhuan.erban.base.BaseDialogFragment;
|
||||
import com.yizhuan.xchat_android_core.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import base.BaseDialogFragment;
|
||||
import util.ActivityHelper;
|
||||
import util.ReflectionUtils;
|
||||
|
||||
|
||||
/**
|
||||
* User: wukai
|
||||
|
@@ -11,6 +11,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import util.CoreUtils;
|
||||
|
||||
/**
|
||||
* Created by logwee on 2019/4/9.
|
||||
*/
|
||||
|
@@ -1,435 +0,0 @@
|
||||
package com.yizhuan.erban.ui.user;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.fourmob.datetimepicker.date.DatePickerDialog;
|
||||
import com.jph.takephoto.model.TResult;
|
||||
import com.netease.nim.uikit.StatusBarUtil;
|
||||
import com.netease.nim.uikit.common.util.sys.TimeUtil;
|
||||
import com.sleepbot.datetimepicker.time.RadialPickerLayout;
|
||||
import com.sleepbot.datetimepicker.time.TimePickerDialog;
|
||||
import com.trello.rxlifecycle3.android.ActivityEvent;
|
||||
import com.yizhuan.erban.ErbanTakePhotoActivity;
|
||||
import com.yizhuan.erban.R;
|
||||
import com.yizhuan.erban.UIHelper;
|
||||
import com.yizhuan.erban.audio.RecordingVoiceActivity;
|
||||
import com.yizhuan.erban.base.BaseActivity;
|
||||
import com.yizhuan.erban.common.permission.PermissionActivity;
|
||||
import com.yizhuan.erban.ui.login.ModifyInfoActivity;
|
||||
import com.yizhuan.erban.ui.utils.ImageLoadUtils;
|
||||
import com.yizhuan.erban.ui.widget.ButtonItem;
|
||||
import com.yizhuan.erban.utils.RegexUtil;
|
||||
import com.yizhuan.xchat_android_core.auth.AuthModel;
|
||||
import com.yizhuan.xchat_android_core.file.FileModel;
|
||||
import com.yizhuan.xchat_android_core.user.UserModel;
|
||||
import com.yizhuan.xchat_android_core.user.bean.UserInfo;
|
||||
import com.yizhuan.xchat_android_core.user.bean.UserPhoto;
|
||||
import com.yizhuan.xchat_android_library.utils.ResUtil;
|
||||
import com.yizhuan.xchat_android_library.utils.TimeUtils;
|
||||
import com.yizhuan.xchat_android_library.utils.log.MLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.SingleObserver;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* @author zhouxiangfeng
|
||||
*/
|
||||
public class UserInfoModifyActivity extends BaseActivity
|
||||
implements View.OnClickListener, TimePickerDialog.OnTimeSetListener,
|
||||
DatePickerDialog.OnDateSetListener, UserPhotoAdapter.ImageClickListener,
|
||||
ErbanTakePhotoActivity.TakePhotoCallBack {
|
||||
|
||||
private static final String TAG = "UserInfoModifyActivity";
|
||||
|
||||
private ImageView civAvatar;
|
||||
private DatePickerDialog datePickerDialog;
|
||||
private TextView tvBirth;
|
||||
private TextView tvNick;
|
||||
private TextView tvDesc;
|
||||
private UserInfo mUserInfo;
|
||||
private long userId;
|
||||
private TextView tvNoVoice;
|
||||
private String audioFileUrl;
|
||||
private RecyclerView photosRecyclerView;
|
||||
|
||||
private boolean showAvatarAuditing;
|
||||
private ImageView ivAvatarAuditiong;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_user_info_modify);
|
||||
initWhiteTitleBar(getString(R.string.label_title_modify_info));
|
||||
findViews();
|
||||
init();
|
||||
onSetListener();
|
||||
userId = getIntent().getLongExtra("userId", 0);
|
||||
UserModel.get().getUserInfo(userId).subscribe(userInfoUpdateObserver);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void click(int position, UserPhoto userPhoto, boolean isOwner) {
|
||||
if (userPhoto != null) {
|
||||
UserModifyPhotosActivity.startForResult(UserInfoModifyActivity.this, userId, Method.PHOTO);
|
||||
}
|
||||
}
|
||||
|
||||
private void onSetListener() {
|
||||
|
||||
}
|
||||
|
||||
private void initData(UserInfo userInfo) {
|
||||
if (null != userInfo) {
|
||||
audioFileUrl = userInfo.getUserVoice();
|
||||
ImageLoadUtils.loadAvatar(this, !TextUtils.isEmpty(userInfo.getNewAvatar()) ? userInfo.getNewAvatar() : userInfo.getAvatar(), civAvatar);
|
||||
ivAvatarAuditiong.setVisibility(userInfo.isReview() ? View.VISIBLE : View.GONE);
|
||||
String birth = TimeUtil.getDateTimeString(userInfo.getBirth(), "yyyy-MM-dd");
|
||||
tvBirth.setText(birth);
|
||||
tvNick.setText(RegexUtil.getPrintableString(userInfo.getNick()));
|
||||
setTvDesc(userInfo.getUserDesc());
|
||||
boolean hasVoice = userInfo.getVoiceDura() > 0;
|
||||
tvNoVoice.setVisibility(hasVoice ? View.GONE : View.VISIBLE);
|
||||
UserPhotoAdapter adapter = new UserPhotoAdapter(userInfo.getPrivatePhoto(), 1, userInfo.getUid());
|
||||
adapter.setSmall(true);
|
||||
adapter.setImageClickListener(this);
|
||||
photosRecyclerView.setAdapter(adapter);
|
||||
if (userInfo.getPrivatePhoto() != null && userInfo.getPrivatePhoto().size() > 0) {
|
||||
photosRecyclerView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
photosRecyclerView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findViews() {
|
||||
civAvatar = findViewById(R.id.civ_avatar);
|
||||
tvBirth = findViewById(R.id.tv_birth);
|
||||
tvNick = findViewById(R.id.tv_nick);
|
||||
tvDesc = findViewById(R.id.tv_desc);
|
||||
tvNoVoice = findViewById(R.id.tv_no_voice);
|
||||
photosRecyclerView = findViewById(R.id.rv_photos);
|
||||
findViewById(R.id.layout_avatar).setOnClickListener(this);
|
||||
tvBirth.setOnClickListener(this);
|
||||
findViewById(R.id.tv_nick).setOnClickListener(this);
|
||||
findViewById(R.id.layout_desc).setOnClickListener(this);
|
||||
findViewById(R.id.iv_desc_more).setOnClickListener(this);
|
||||
findViewById(R.id.layout_photos).setOnClickListener(this);
|
||||
findViewById(R.id.rl_audio_record).setOnClickListener(this);
|
||||
LinearLayoutManager mLayoutManager =
|
||||
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true);
|
||||
photosRecyclerView.setLayoutManager(mLayoutManager);
|
||||
ivAvatarAuditiong = findViewById(R.id.iv_avatar_auditing);
|
||||
|
||||
}
|
||||
|
||||
private void setTvDesc(String desc) {
|
||||
tvDesc.setText(TextUtils.isEmpty(desc) ? getString(R.string.label_hint_desc_setting) : desc);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
datePickerDialog = DatePickerDialog.newInstance(this, calendar.get(Calendar.YEAR),
|
||||
calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) {
|
||||
String monthStr;
|
||||
if ((month + 1) < 10) {
|
||||
monthStr = "0" + (month + 1);
|
||||
} else {
|
||||
monthStr = String.valueOf(month + 1);
|
||||
}
|
||||
String dayStr;
|
||||
if ((day) < 10) {
|
||||
dayStr = "0" + (day);
|
||||
} else {
|
||||
dayStr = String.valueOf(day);
|
||||
}
|
||||
String birth = String.valueOf(year) + "-" + monthStr + "-" + dayStr;
|
||||
UserInfo user = new UserInfo();
|
||||
user.setUid(AuthModel.get().getCurrentUid());
|
||||
user.setBirthStr(birth);
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public interface Method {
|
||||
/**
|
||||
* 录音
|
||||
*/
|
||||
int AUDIO = 2;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
int NICK = 3;
|
||||
/**
|
||||
* 个人介绍
|
||||
*/
|
||||
int DESC = 4;
|
||||
|
||||
int PHOTO = 5;
|
||||
}
|
||||
|
||||
|
||||
PermissionActivity.CheckPermListener checkPermissionListener = new PermissionActivity.CheckPermListener() {
|
||||
@Override
|
||||
public void superPermission() {
|
||||
takePhoto();
|
||||
}
|
||||
};
|
||||
|
||||
private void takePhoto() {
|
||||
ErbanTakePhotoActivity.startToTakePhoto(this, this);
|
||||
}
|
||||
|
||||
private void checkPermissionAndStartCamera() {
|
||||
//低版本授权检查
|
||||
checkPermission(checkPermissionListener, R.string.ask_camera, Manifest.permission.CAMERA);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
MLog.info(this, "return is not ok,resultCode=%d", resultCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestCode == Method.NICK) {
|
||||
getDialogManager().showProgressDialog(UserInfoModifyActivity.this, ResUtil.getString(R.string.ui_user_userinfomodifyactivity_01));
|
||||
String stringExtra = data.getStringExtra(ModifyInfoActivity.CONTENT_NICK);
|
||||
tvNick.setText(stringExtra);
|
||||
UserInfo user = new UserInfo();
|
||||
user.setUid(AuthModel.get().getCurrentUid());
|
||||
user.setNick(stringExtra);
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver);
|
||||
|
||||
}
|
||||
|
||||
if (requestCode == Method.DESC) {
|
||||
getDialogManager().showProgressDialog(UserInfoModifyActivity.this, ResUtil.getString(R.string.ui_user_userinfomodifyactivity_02));
|
||||
String stringExtra = data.getStringExtra(ModifyInfoActivity.CONTENT);
|
||||
setTvDesc(stringExtra);
|
||||
UserInfo user = new UserInfo();
|
||||
user.setUid(AuthModel.get().getCurrentUid());
|
||||
user.setUserDesc(stringExtra);
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver);
|
||||
}
|
||||
|
||||
// 刷新声音资源
|
||||
if (requestCode == Method.AUDIO) {
|
||||
// 传给上个页面
|
||||
setResult(RESULT_OK, data);
|
||||
|
||||
// 获取数据并刷新显示
|
||||
audioFileUrl = data.getStringExtra(RecordingVoiceActivity.AUDIO_FILE);
|
||||
int audioDura = data.getIntExtra(RecordingVoiceActivity.AUDIO_DURA, 0);
|
||||
|
||||
// 更新用户信息
|
||||
UserInfo user = new UserInfo();
|
||||
user.setUid(AuthModel.get().getCurrentUid());
|
||||
user.setUserVoice(audioFileUrl);
|
||||
user.setVoiceDura(audioDura);
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver);
|
||||
}
|
||||
|
||||
if (requestCode == Method.PHOTO && data != null) {
|
||||
boolean isChanged = data.getBooleanExtra(UserModifyPhotosActivity.FLAG_CHANGE, false);
|
||||
if (isChanged)
|
||||
UserModel.get().getUserInfo(userId).subscribe(userInfoUpdateObserver);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.layout_avatar:
|
||||
if (mUserInfo != null && mUserInfo.isReview()) {
|
||||
toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_03));
|
||||
return;
|
||||
}
|
||||
ButtonItem buttonItem = new ButtonItem(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_04), this::checkPermissionAndStartCamera);
|
||||
ButtonItem buttonItem1 = new ButtonItem(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_05), () -> {
|
||||
ErbanTakePhotoActivity.startToSelectPhoto(this, this);
|
||||
});
|
||||
List<ButtonItem> buttonItems = new ArrayList<>();
|
||||
buttonItems.add(buttonItem);
|
||||
buttonItems.add(buttonItem1);
|
||||
getDialogManager().showCommonPopupDialog(buttonItems, ResUtil.getString(R.string.ui_user_userinfomodifyactivity_06), false);
|
||||
|
||||
isAvatar = true;
|
||||
break;
|
||||
case R.id.tv_birth:
|
||||
if (mUserInfo != null) {
|
||||
int year = TimeUtils.getYear(mUserInfo.getBirth());
|
||||
int month = TimeUtils.getMonth(mUserInfo.getBirth());
|
||||
int day = TimeUtils.getDayOfMonth(mUserInfo.getBirth());
|
||||
datePickerDialog = DatePickerDialog.newInstance(this, year, (month - 1), day, true);
|
||||
}
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
datePickerDialog.setVibrate(true);
|
||||
datePickerDialog.setYearRange(1945, calendar.get(Calendar.YEAR) - 18);
|
||||
datePickerDialog.show(getSupportFragmentManager(), "DATEPICKER_TAG_1");
|
||||
break;
|
||||
case R.id.tv_nick:
|
||||
UIHelper.showModifyInfoAct(UserInfoModifyActivity.this, Method.NICK, ModifyInfoActivity.NICK_MODIFY);
|
||||
break;
|
||||
|
||||
case R.id.iv_desc_more:
|
||||
case R.id.layout_desc:
|
||||
UIHelper.showModifyInfoAct(UserInfoModifyActivity.this, Method.DESC, ModifyInfoActivity.CONTENT_MODIFY);
|
||||
break;
|
||||
|
||||
case R.id.rl_audio_record:
|
||||
checkPermission(() -> {
|
||||
// 点击跳转到我的声音页面
|
||||
UIHelper.showMyVoiceAct(UserInfoModifyActivity.this, Method.AUDIO, ResUtil.getString(R.string.ui_user_userinfomodifyactivity_07));
|
||||
isAvatar = false;
|
||||
}, R.string.ask_again,
|
||||
Manifest.permission.RECORD_AUDIO);
|
||||
|
||||
break;
|
||||
case R.id.layout_photos:
|
||||
UserModifyPhotosActivity.startForResult(UserInfoModifyActivity.this, userId, Method.PHOTO);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAvatar = false;
|
||||
|
||||
public void onUpload(String url) {
|
||||
if (isAvatar) {
|
||||
UserInfo user = new UserInfo();
|
||||
user.setUid(AuthModel.get().getCurrentUid());
|
||||
user.setAvatar(url);
|
||||
showAvatarAuditing = true;
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver);
|
||||
}
|
||||
}
|
||||
|
||||
public void onUploadFail() {
|
||||
toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_08));
|
||||
getDialogManager().dismissDialog();
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@Override
|
||||
public void takeSuccess(TResult result) {
|
||||
getDialogManager().showProgressDialog(UserInfoModifyActivity.this, ResUtil.getString(R.string.ui_user_userinfomodifyactivity_09));
|
||||
FileModel.get()
|
||||
.uploadFile(result.getImage().getCompressPath())
|
||||
.compose(bindToLifecycle())
|
||||
.subscribe((url, throwable) -> {
|
||||
if (throwable != null) {
|
||||
onUploadFail();
|
||||
} else {
|
||||
onUpload(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeFail(TResult result, String msg) {
|
||||
toast(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeCancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 观察用户信息
|
||||
*/
|
||||
private SingleObserver<UserInfo> userInfoUpdateObserver = new SingleObserver<UserInfo>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
mCompositeDisposable.add(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(UserInfo info) {
|
||||
if (info.getUid() == userId) {
|
||||
mUserInfo = info;
|
||||
initData(mUserInfo);
|
||||
}
|
||||
getDialogManager().dismissDialog();
|
||||
if (showAvatarAuditing) {
|
||||
showAvatarAuditing = false;
|
||||
showAvatarAuditingDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
getDialogManager().dismissDialog();
|
||||
toast(e.getMessage());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected boolean needSteepStateBar() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setStatusBar() {
|
||||
StatusBarUtil.transparencyBar(this);
|
||||
StatusBarUtil.StatusBarLightMode(this);
|
||||
}
|
||||
|
||||
private void showAvatarAuditingDialog() {
|
||||
toast(R.string.avatar_auditing);
|
||||
//延迟3秒重新获取用户信息更新状态
|
||||
ivAvatarAuditiong.setVisibility(View.VISIBLE);
|
||||
Completable.timer(3000, TimeUnit.MILLISECONDS)
|
||||
.compose(bindUntilEvent(ActivityEvent.STOP))
|
||||
.doOnComplete(() -> {
|
||||
UserModel.get().updateCurrentUserInfo().subscribe(userInfoUpdateObserver);
|
||||
}).doOnError(throwable -> {
|
||||
throwable.printStackTrace();
|
||||
}).subscribe();
|
||||
}
|
||||
}
|
@@ -0,0 +1,620 @@
|
||||
package com.yizhuan.erban.ui.user
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.fourmob.datetimepicker.date.DatePickerDialog
|
||||
import com.hjq.toast.ToastUtils
|
||||
import com.jph.takephoto.model.TResult
|
||||
import com.netease.nim.uikit.StatusBarUtil
|
||||
import com.netease.nim.uikit.common.util.sys.TimeUtil
|
||||
import com.sleepbot.datetimepicker.time.RadialPickerLayout
|
||||
import com.sleepbot.datetimepicker.time.TimePickerDialog
|
||||
import com.trello.rxlifecycle3.android.ActivityEvent
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import com.yizhuan.erban.ErbanTakePhotoActivity
|
||||
import com.yizhuan.erban.ErbanTakePhotoActivity.TakePhotoCallBack
|
||||
import com.yizhuan.erban.R
|
||||
import com.yizhuan.erban.UIHelper
|
||||
import com.yizhuan.erban.application.XChatApplication
|
||||
import com.yizhuan.erban.audio.RecordingVoiceActivity
|
||||
import com.yizhuan.erban.base.BaseViewBindingActivity
|
||||
import com.yizhuan.erban.common.file.FileHelper
|
||||
import com.yizhuan.erban.common.permission.PermissionActivity.CheckPermListener
|
||||
import com.yizhuan.erban.common.photo.PhotoProvider
|
||||
import com.yizhuan.erban.common.util.PhotoCompressCallback
|
||||
import com.yizhuan.erban.common.util.PhotoCompressUtil
|
||||
import com.yizhuan.erban.databinding.ActivityUserInfoModifyBinding
|
||||
import com.yizhuan.erban.ui.login.ModifyInfoActivity
|
||||
import com.yizhuan.erban.ui.user.UserPhotoAdapter.ImageClickListener
|
||||
import com.yizhuan.erban.ui.utils.ImageLoadUtils
|
||||
import com.yizhuan.erban.ui.widget.dialog.CommonTipDialog
|
||||
import com.yizhuan.erban.utils.RegexUtil
|
||||
import com.yizhuan.xchat_android_core.auth.AuthModel
|
||||
import com.yizhuan.xchat_android_core.file.FileModel
|
||||
import com.yizhuan.xchat_android_core.user.UserModel
|
||||
import com.yizhuan.xchat_android_core.user.bean.UserInfo
|
||||
import com.yizhuan.xchat_android_core.user.bean.UserPhoto
|
||||
import com.yizhuan.xchat_android_core.utils.Logger
|
||||
import com.yizhuan.xchat_android_library.EasyPermissions
|
||||
import com.yizhuan.xchat_android_library.utils.ResUtil
|
||||
import com.yizhuan.xchat_android_library.utils.TimeUtils
|
||||
import com.yizhuan.xchat_android_library.utils.log.MLog
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.SingleObserver
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.coroutines.Job
|
||||
import com.yizhuan.erban.common.util.BitmapUtil
|
||||
import java.io.FileNotFoundException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* @author zhouxiangfeng
|
||||
*/
|
||||
class UserInfoModifyActivity : BaseViewBindingActivity<ActivityUserInfoModifyBinding>(),
|
||||
View.OnClickListener,
|
||||
TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener, ImageClickListener,
|
||||
TakePhotoCallBack, EasyPermissions.PermissionCallbacks {
|
||||
private var datePickerDialog: DatePickerDialog? = null
|
||||
private var mUserInfo: UserInfo? = null
|
||||
private var userId: Long = 0
|
||||
private var audioFileUrl: String? = null
|
||||
private var showAvatarAuditing = false
|
||||
|
||||
private var mUri: Uri? = null
|
||||
private var mJob: Job? = null
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UserInfoModifyActivity"
|
||||
private const val PERMISSION_CODE_STORAGE = 12
|
||||
private const val REQUEST_CODE_STORAGE = 42
|
||||
private const val REQUEST_CODE_LOCATION = 222
|
||||
private const val REQUEST_CODE_OPEN_PHOTO_PROVIDER = 111 // 从相册中选择
|
||||
private const val MAX_BITMAP_SIZE = 100 * 1024 * 1024 // 剪切的图片最大为100 MB
|
||||
private const val MIN_HEAD_PHOTO_SIZE = 20 * 1024 // 剪切的图片最小为20kb
|
||||
|
||||
//头像压缩后的大小不能超过大小 200KB
|
||||
private const val IMAGE_MOST_COMPRESS_SIZE = 200
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
initWhiteTitleBar(getString(R.string.label_title_modify_info))
|
||||
findViews()
|
||||
initView()
|
||||
userId = intent.getLongExtra("userId", 0)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
UserModel.get().getUserInfo(userId).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
|
||||
override fun click(position: Int, userPhoto: UserPhoto, isOwner: Boolean) {
|
||||
UserModifyPhotosActivity.startForResult(
|
||||
this@UserInfoModifyActivity,
|
||||
userId,
|
||||
Method.PHOTO
|
||||
)
|
||||
}
|
||||
|
||||
private fun initData(userInfo: UserInfo?) {
|
||||
if (null != userInfo) {
|
||||
audioFileUrl = userInfo.userVoice
|
||||
ImageLoadUtils.loadAvatar(
|
||||
this,
|
||||
if (!TextUtils.isEmpty(userInfo.newAvatar)) userInfo.newAvatar else userInfo.avatar,
|
||||
binding.civAvatar
|
||||
)
|
||||
binding.ivAvatarAuditing.visibility = if (userInfo.isReview) View.VISIBLE else View.GONE
|
||||
val birth = TimeUtil.getDateTimeString(userInfo.birth, "yyyy-MM-dd")
|
||||
binding.tvBirth.text = birth
|
||||
binding.tvNick.text = RegexUtil.getPrintableString(userInfo.nick)
|
||||
setTvDesc(userInfo.userDesc)
|
||||
val hasVoice = userInfo.voiceDura > 0
|
||||
binding.tvNoVoice.visibility = if (hasVoice) View.GONE else View.VISIBLE
|
||||
val adapter = UserPhotoAdapter(userInfo.privatePhoto, 1, userInfo.uid)
|
||||
adapter.setSmall(true)
|
||||
adapter.setImageClickListener(this)
|
||||
binding.rvPhotos.adapter = adapter
|
||||
if (userInfo.privatePhoto != null && userInfo.privatePhoto.size > 0) {
|
||||
binding.rvPhotos.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.rvPhotos.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findViews() {
|
||||
binding.layoutAvatar.setOnClickListener(this)
|
||||
binding.tvBirth.setOnClickListener(this)
|
||||
binding.tvNick.setOnClickListener(this)
|
||||
binding.layoutDesc.setOnClickListener(this)
|
||||
binding.ivDescMore.setOnClickListener(this)
|
||||
binding.layoutPhotos.setOnClickListener(this)
|
||||
binding.rlAudioRecord.setOnClickListener(this)
|
||||
val mLayoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true)
|
||||
binding.rvPhotos.layoutManager = mLayoutManager
|
||||
}
|
||||
|
||||
private fun setTvDesc(desc: String?) {
|
||||
binding.tvDesc.text =
|
||||
if (TextUtils.isEmpty(desc)) getString(R.string.label_hint_desc_setting) else desc
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
val calendar = Calendar.getInstance()
|
||||
datePickerDialog = DatePickerDialog.newInstance(
|
||||
this, calendar[Calendar.YEAR],
|
||||
calendar[Calendar.MONTH], calendar[Calendar.DAY_OF_MONTH], true
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDateSet(datePickerDialog: DatePickerDialog, year: Int, month: Int, day: Int) {
|
||||
val monthStr: String = if (month + 1 < 10) {
|
||||
"0" + (month + 1)
|
||||
} else {
|
||||
(month + 1).toString()
|
||||
}
|
||||
val dayStr: String = if (day < 10) {
|
||||
"0$day"
|
||||
} else {
|
||||
day.toString()
|
||||
}
|
||||
val birth = "$year-$monthStr-$dayStr"
|
||||
val user = UserInfo()
|
||||
user.uid = AuthModel.get().currentUid
|
||||
user.birthStr = birth
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
|
||||
override fun onTimeSet(view: RadialPickerLayout, hourOfDay: Int, minute: Int) {}
|
||||
interface Method {
|
||||
companion object {
|
||||
/**
|
||||
* 录音
|
||||
*/
|
||||
const val AUDIO = 2
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
const val NICK = 3
|
||||
|
||||
/**
|
||||
* 个人介绍
|
||||
*/
|
||||
const val DESC = 4
|
||||
const val PHOTO = 5
|
||||
}
|
||||
}
|
||||
|
||||
var checkPermissionListener = CheckPermListener { takePhoto() }
|
||||
private fun takePhoto() {
|
||||
ErbanTakePhotoActivity.startToTakePhoto(this, this)
|
||||
}
|
||||
|
||||
private fun checkPermissionAndStartCamera() {
|
||||
//低版本授权检查
|
||||
checkPermission(checkPermissionListener, R.string.ask_camera, Manifest.permission.CAMERA)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode != RESULT_OK) {
|
||||
MLog.info(this, "return is not ok,resultCode=%d", resultCode)
|
||||
return
|
||||
}
|
||||
if (requestCode == Method.NICK) {
|
||||
dialogManager.showProgressDialog(
|
||||
this@UserInfoModifyActivity,
|
||||
ResUtil.getString(R.string.ui_user_userinfomodifyactivity_01)
|
||||
)
|
||||
val stringExtra = data!!.getStringExtra(ModifyInfoActivity.CONTENT_NICK)
|
||||
binding.tvNick.text = stringExtra
|
||||
val user = UserInfo()
|
||||
user.uid = AuthModel.get().currentUid
|
||||
user.nick = stringExtra
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
if (requestCode == Method.DESC) {
|
||||
dialogManager.showProgressDialog(
|
||||
this@UserInfoModifyActivity,
|
||||
ResUtil.getString(R.string.ui_user_userinfomodifyactivity_02)
|
||||
)
|
||||
val stringExtra = data!!.getStringExtra(ModifyInfoActivity.CONTENT)
|
||||
setTvDesc(stringExtra)
|
||||
val user = UserInfo()
|
||||
user.uid = AuthModel.get().currentUid
|
||||
user.userDesc = stringExtra
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
|
||||
// 刷新声音资源
|
||||
if (requestCode == Method.AUDIO) {
|
||||
// 传给上个页面
|
||||
setResult(RESULT_OK, data)
|
||||
|
||||
// 获取数据并刷新显示
|
||||
audioFileUrl = data!!.getStringExtra(RecordingVoiceActivity.AUDIO_FILE)
|
||||
val audioDura = data.getIntExtra(RecordingVoiceActivity.AUDIO_DURA, 0)
|
||||
|
||||
// 更新用户信息
|
||||
val user = UserInfo()
|
||||
user.uid = AuthModel.get().currentUid
|
||||
user.userVoice = audioFileUrl
|
||||
user.voiceDura = audioDura
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
if (requestCode == Method.PHOTO && data != null) {
|
||||
val isChanged = data.getBooleanExtra(UserModifyPhotosActivity.FLAG_CHANGE, false)
|
||||
if (isChanged) UserModel.get().getUserInfo(userId).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
when (requestCode) {
|
||||
REQUEST_CODE_OPEN_PHOTO_PROVIDER -> data?.let {
|
||||
val photos = PhotoProvider.getResultPhotoList(data) ?: return
|
||||
if (photos.isNotEmpty()) {
|
||||
val photo = photos[0]
|
||||
crop(photo.uri, photo.size, mUri)
|
||||
}
|
||||
}
|
||||
UCrop.REQUEST_CROP -> mUri?.path?.let {
|
||||
try {
|
||||
mJob?.cancel()
|
||||
mJob = PhotoCompressUtil.compress(
|
||||
XChatApplication.gContext,
|
||||
it,
|
||||
PhotoCompressUtil.getCompressCachePath(),
|
||||
object : PhotoCompressCallback {
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onSuccess(compressedImg: String) {
|
||||
dialogManager.showProgressDialog(
|
||||
this@UserInfoModifyActivity,
|
||||
ResUtil.getString(R.string.ui_user_userinfomodifyactivity_09)
|
||||
)
|
||||
FileModel.get()
|
||||
.uploadFile(compressedImg)
|
||||
.compose(bindToLifecycle())
|
||||
.subscribe { url: String?, throwable: Throwable? ->
|
||||
if (throwable != null) {
|
||||
onUploadFail()
|
||||
} else {
|
||||
onUpload(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFail(e: Throwable) {
|
||||
toast(e.message)
|
||||
}
|
||||
},
|
||||
mostCompressSize = IMAGE_MOST_COMPRESS_SIZE
|
||||
)
|
||||
} catch (e: FileNotFoundException) {
|
||||
Logger.error(TAG, e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方图片裁剪框架Ucrop
|
||||
*/
|
||||
private fun crop(sourceUri: Uri?, sourceSize: Long, destinationUri: Uri?) {
|
||||
if (sourceUri == null || destinationUri == null) {
|
||||
return
|
||||
} //防止too large导致oom,大于100m不处理,内存大小
|
||||
if (BitmapUtil.getSdBitmapSize(sourceUri) >= MAX_BITMAP_SIZE) {
|
||||
toast(R.string.text_bitmap_too_large)
|
||||
return
|
||||
}
|
||||
if (sourceSize > 0) {
|
||||
//不能上传图片的最小文件大小
|
||||
Logger.debug(TAG, "sourceSize: $sourceSize")
|
||||
if (sourceSize < MIN_HEAD_PHOTO_SIZE) {
|
||||
toast(R.string.text_bitmap_too_small)
|
||||
return
|
||||
}
|
||||
}
|
||||
val options = UCrop.Options().apply {
|
||||
setCompressionQuality(100)
|
||||
setShowCropGrid(false)
|
||||
setToolbarColor(
|
||||
ContextCompat.getColor(
|
||||
XChatApplication.gContext,
|
||||
android.R.color.black
|
||||
)
|
||||
)
|
||||
setStatusBarColor(
|
||||
ContextCompat.getColor(
|
||||
XChatApplication.gContext,
|
||||
android.R.color.black
|
||||
)
|
||||
)
|
||||
setHideBottomControls(true)
|
||||
setCompressionFormat(Bitmap.CompressFormat.JPEG)
|
||||
setToolbarCancelDrawable(R.drawable.user_ucrop_ic_closs)
|
||||
setToolbarCropDrawable(R.drawable.user_ucrop_ic_sure)
|
||||
setToolbarWidgetColor(
|
||||
ContextCompat.getColor(
|
||||
XChatApplication.gContext,
|
||||
R.color.color_white
|
||||
)
|
||||
)
|
||||
}
|
||||
UCrop.of(sourceUri, destinationUri).withOptions(options).withAspectRatio(1f, 1f)
|
||||
.withMaxResultSize(800, 800).start(this)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.layout_avatar -> {
|
||||
if (mUserInfo != null && mUserInfo!!.isReview) {
|
||||
toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_03))
|
||||
return
|
||||
}
|
||||
checkStoragePermission()
|
||||
// val buttonItem =
|
||||
// ButtonItem(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_04)) { checkPermissionAndStartCamera() }
|
||||
// val buttonItem1 =
|
||||
// ButtonItem(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_05)) {
|
||||
// ErbanTakePhotoActivity.startToSelectPhoto(
|
||||
// this,
|
||||
// this
|
||||
// )
|
||||
// }
|
||||
// val buttonItems: MutableList<ButtonItem> = ArrayList()
|
||||
// buttonItems.add(buttonItem)
|
||||
// buttonItems.add(buttonItem1)
|
||||
// dialogManager.showCommonPopupDialog(buttonItems,
|
||||
// ResUtil.getString(R.string.ui_user_userinfomodifyactivity_06),
|
||||
// false
|
||||
// )
|
||||
|
||||
// PhotoDialog photoDialog = (PhotoDialog) (DialogFragmentUtils.show("photoDialog", this, PhotoDialog.class));
|
||||
// photoDialog.setOnResultCallBack(new PhotoDialog.OnResultCallBack() {
|
||||
// @Override
|
||||
// public void takePhotoCallBack(@Nullable String path) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void choicePhotoCallBack(@Nullable List<String> paths) {
|
||||
//
|
||||
// }
|
||||
// });
|
||||
isAvatar = true
|
||||
}
|
||||
R.id.tv_birth -> {
|
||||
if (mUserInfo != null) {
|
||||
val year = TimeUtils.getYear(
|
||||
mUserInfo!!.birth
|
||||
)
|
||||
val month = TimeUtils.getMonth(
|
||||
mUserInfo!!.birth
|
||||
)
|
||||
val day = TimeUtils.getDayOfMonth(
|
||||
mUserInfo!!.birth
|
||||
)
|
||||
datePickerDialog =
|
||||
DatePickerDialog.newInstance(this, year, month - 1, day, true)
|
||||
}
|
||||
val calendar = Calendar.getInstance()
|
||||
datePickerDialog?.apply {
|
||||
setVibrate(true)
|
||||
setYearRange(1945, calendar[Calendar.YEAR] - 18)
|
||||
show(supportFragmentManager, "DATEPICKER_TAG_1")
|
||||
}
|
||||
}
|
||||
R.id.tv_nick -> UIHelper.showModifyInfoAct(
|
||||
this@UserInfoModifyActivity,
|
||||
Method.NICK,
|
||||
ModifyInfoActivity.NICK_MODIFY
|
||||
)
|
||||
R.id.iv_desc_more, R.id.layout_desc -> UIHelper.showModifyInfoAct(
|
||||
this@UserInfoModifyActivity,
|
||||
Method.DESC,
|
||||
ModifyInfoActivity.CONTENT_MODIFY
|
||||
)
|
||||
R.id.rl_audio_record -> checkPermission(
|
||||
{
|
||||
|
||||
// 点击跳转到我的声音页面
|
||||
UIHelper.showMyVoiceAct(
|
||||
this@UserInfoModifyActivity,
|
||||
Method.AUDIO,
|
||||
ResUtil.getString(R.string.ui_user_userinfomodifyactivity_07)
|
||||
)
|
||||
isAvatar = false
|
||||
}, R.string.ask_again,
|
||||
Manifest.permission.RECORD_AUDIO
|
||||
)
|
||||
R.id.layout_photos -> UserModifyPhotosActivity.startForResult(
|
||||
this@UserInfoModifyActivity,
|
||||
userId,
|
||||
Method.PHOTO
|
||||
)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkStoragePermission() {
|
||||
if (context?.let {
|
||||
EasyPermissions.hasPermissions(
|
||||
it, Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
} == false) {
|
||||
context?.getString(R.string.permission_storage_rationale)?.let {
|
||||
EasyPermissions.requestPermissions(
|
||||
this, it, PERMISSION_CODE_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
} else {
|
||||
mUri = Uri.parse("file://${FileHelper.getRootCacheDir()?.path}/${getNowTime()}.jpg")
|
||||
PhotoProvider.photoProvider(
|
||||
this,
|
||||
resultCode = REQUEST_CODE_OPEN_PHOTO_PROVIDER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNowTime(): String {
|
||||
val date = Date(System.currentTimeMillis())
|
||||
val dateFormat = SimpleDateFormat("MMddHHmmssSS")
|
||||
return dateFormat.format(date)
|
||||
}
|
||||
|
||||
private var isAvatar = false
|
||||
|
||||
private fun onUpload(url: String?) {
|
||||
if (isAvatar) {
|
||||
val user = UserInfo()
|
||||
user.uid = AuthModel.get().currentUid
|
||||
user.avatar = url
|
||||
showAvatarAuditing = true
|
||||
UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onUploadFail() {
|
||||
toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_08))
|
||||
dialogManager.dismissDialog()
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun takeSuccess(result: TResult) {
|
||||
dialogManager.showProgressDialog(
|
||||
this@UserInfoModifyActivity,
|
||||
ResUtil.getString(R.string.ui_user_userinfomodifyactivity_09)
|
||||
)
|
||||
FileModel.get()
|
||||
.uploadFile(result.image.compressPath)
|
||||
.compose(bindToLifecycle())
|
||||
.subscribe { url: String?, throwable: Throwable? ->
|
||||
if (throwable != null) {
|
||||
onUploadFail()
|
||||
} else {
|
||||
onUpload(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun takeFail(result: TResult, msg: String) {
|
||||
toast(msg)
|
||||
}
|
||||
|
||||
override fun takeCancel() {}
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mJob?.cancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* 观察用户信息
|
||||
*/
|
||||
private val userInfoUpdateObserver: SingleObserver<UserInfo> =
|
||||
object : SingleObserver<UserInfo> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
mCompositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onSuccess(info: UserInfo) {
|
||||
if (info.uid == userId) {
|
||||
mUserInfo = info
|
||||
initData(mUserInfo)
|
||||
}
|
||||
dialogManager.dismissDialog()
|
||||
if (showAvatarAuditing) {
|
||||
showAvatarAuditing = false
|
||||
showAvatarAuditingDialog()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
dialogManager.dismissDialog()
|
||||
toast(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun needSteepStateBar(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setStatusBar() {
|
||||
StatusBarUtil.transparencyBar(this)
|
||||
StatusBarUtil.StatusBarLightMode(this)
|
||||
}
|
||||
|
||||
private fun showAvatarAuditingDialog() {
|
||||
toast(R.string.avatar_auditing)
|
||||
//延迟3秒重新获取用户信息更新状态
|
||||
binding.ivAvatarAuditing.visibility = View.VISIBLE
|
||||
Completable.timer(3000, TimeUnit.MILLISECONDS)
|
||||
.compose(bindUntilEvent<Any>(ActivityEvent.STOP))
|
||||
.doOnComplete {
|
||||
UserModel.get().updateCurrentUserInfo().subscribe(userInfoUpdateObserver)
|
||||
}
|
||||
.doOnError { throwable: Throwable -> throwable.printStackTrace() }.subscribe()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<out String>, grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
|
||||
}
|
||||
|
||||
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
|
||||
if (requestCode == PERMISSION_CODE_STORAGE) {
|
||||
checkStoragePermission()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
|
||||
if (requestCode == PERMISSION_CODE_STORAGE) {
|
||||
val requestTip = getString(R.string.permission_storage_denied)
|
||||
val mPrivacyDialog = CommonTipDialog(context)
|
||||
mPrivacyDialog.setTipMsg(requestTip)
|
||||
mPrivacyDialog.setOkText(getString(R.string.room_perform_go_update))
|
||||
mPrivacyDialog.setOnActionListener(
|
||||
object : CommonTipDialog.OnActionListener {
|
||||
override fun onOk() {
|
||||
//同意跳到应用详情页面
|
||||
val packageUri =
|
||||
Uri.parse("package:${packageName}")
|
||||
val intent = Intent(
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
packageUri
|
||||
)
|
||||
startActivityForResult(
|
||||
intent, REQUEST_CODE_STORAGE
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
super.onCancel()
|
||||
//取消跳到应用详情页面
|
||||
ToastUtils.show(getString(R.string.permission_storage_refused))
|
||||
}
|
||||
}
|
||||
)
|
||||
mPrivacyDialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -26,5 +26,4 @@
|
||||
<item name="month_text_view" type="id"/>
|
||||
<item name="viewpager_inner" type="id"/>
|
||||
|
||||
<item name="baseViewTagID" type="id" />
|
||||
</resources>
|
@@ -30,6 +30,7 @@ android {
|
||||
'src/module_easypermission/java',
|
||||
'src/module_luban/java',
|
||||
'src/module_easyphoto/java',
|
||||
'src/module_common/java',
|
||||
|
||||
]
|
||||
|
||||
@@ -37,6 +38,7 @@ android {
|
||||
'src/main/res',
|
||||
'src/module_easypermission/res',
|
||||
'src/module_easyphoto/res',
|
||||
'src/module_common/res',
|
||||
|
||||
]
|
||||
|
||||
@@ -122,6 +124,8 @@ dependencies {
|
||||
api 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
||||
api 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||
|
||||
api 'com.github.yalantis:ucrop:2.2.7'
|
||||
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
BIN
library/src/main/res/drawable-xhdpi/user_ucrop_ic_closs.webp
Normal file
BIN
library/src/main/res/drawable-xhdpi/user_ucrop_ic_closs.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 461 B |
BIN
library/src/main/res/drawable-xhdpi/user_ucrop_ic_sure.webp
Normal file
BIN
library/src/main/res/drawable-xhdpi/user_ucrop_ic_sure.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 437 B |
210
library/src/module_common/java/base/BaseActivity.java
Normal file
210
library/src/module_common/java/base/BaseActivity.java
Normal file
@@ -0,0 +1,210 @@
|
||||
package base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewbinding.ViewBinding;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import fragmentation.ISupportActivity;
|
||||
import fragmentation.SupportActivityDelegate;
|
||||
import util.Logger;
|
||||
import util.ViewBindingUtil;
|
||||
|
||||
public abstract class BaseActivity<VB extends ViewBinding> extends AppCompatActivity implements ISupportActivity {
|
||||
private final String TAG = getClass().getSimpleName();
|
||||
private final SupportActivityDelegate mActivityDelegate = new SupportActivityDelegate(this);
|
||||
@Nullable
|
||||
private VB mViewBinding;
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
try {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
this.handleFragmentActivityResult(this.getSupportFragmentManager(), requestCode, resultCode, data);
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, "onActivityResult", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFragmentActivityResult(FragmentManager fragmentManager, int requestCode, int resultCode, Intent data) {
|
||||
if (fragmentManager != null) {
|
||||
List<Fragment> fragmentList = fragmentManager.getFragments();
|
||||
int size = fragmentList.size();
|
||||
if (size > 0) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
Fragment fragment = fragmentList.get(i);
|
||||
if (fragment != null) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
this.handleFragmentActivityResult(fragment.getChildFragmentManager(), requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.mActivityDelegate.onCreate();
|
||||
this.initBefore(savedInstanceState);
|
||||
mViewBinding = ViewBindingUtil.inflateWithActivity(this, getLayoutInflater());
|
||||
if (mViewBinding != null) {
|
||||
View mContentView = mViewBinding.getRoot();
|
||||
mContentView.setTag(BaseViewTag.TAG_NAME, this);
|
||||
setContentView(mContentView);
|
||||
}
|
||||
this.findView();
|
||||
this.setView();
|
||||
this.setListener();
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 建议子类相关操作写在super.onResume()之前
|
||||
*/
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onResume() {
|
||||
try {
|
||||
super.onResume();
|
||||
} catch (Exception e) {
|
||||
callUpActivity();
|
||||
Logger.error(TAG, "onResume", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解决onResume()不明原因导致的java.lang.IllegalArgumentException
|
||||
* 参考文档:https://blog.csdn.net/ahubenkui/article/details/80038381
|
||||
*/
|
||||
private void callUpActivity() {
|
||||
try {
|
||||
Class<Activity> superClass = Activity.class;
|
||||
Field field = superClass.getDeclaredField("mCalled");
|
||||
field.setAccessible(true);
|
||||
field.setBoolean(this, true);
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, "callUpActivity", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 建议子类相关操作写在super.onPause()之前
|
||||
*/
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
//当isFinishing()返回为true时,表示当前Activity将要销毁,但最终不会走Activity#onDestroy()方法。
|
||||
if (this.isFinishing()) {
|
||||
this.onWillDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
try {
|
||||
super.onSaveInstanceState(outState);
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, "onSaveInstanceState", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不建议子类在Activity#onDestroy()方法里面做各种释放操作,因为onDestroy()方法不一定会执行,有可能会导致内存泄露,请使用:onWillDestroy()方法。
|
||||
* 参考文档:https://blog.csdn.net/wangsf1112/article/details/79108856
|
||||
*/
|
||||
@CallSuper
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
this.onWillDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 建议子类各种释放操作,放到onWillDestroy()中方法执行,因为Activity#onDestroy()方法不一定会执行,有可能会导致内存泄露。
|
||||
*/
|
||||
protected void onWillDestroy() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SupportActivityDelegate getSupportDelegate() {
|
||||
return this.mActivityDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onBackPressed() {
|
||||
this.mActivityDelegate.onBackPressedPage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressedSupport() {
|
||||
this.mActivityDelegate.onBackPressedSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
try {
|
||||
return super.dispatchTouchEvent(ev);
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, "dispatchTouchEvent", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final VB getBinding() {
|
||||
return mViewBinding;
|
||||
}
|
||||
|
||||
////////////////////////////////////////以下是提供给子类复写的方法////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 该方法是在onCreate()方法里执行,在setContentView()方法被调用之前触发,可用于处理解析Activity#getIntent()中的数据时的场景
|
||||
*/
|
||||
protected void initBefore(@Nullable Bundle savedInstanceState) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法是在onCreate()方法里执行,在setContentView()方法被调用之后触发,可用于处理控件的初始化
|
||||
*/
|
||||
protected void findView() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法是在onCreate()方法里执行,在setContentView()方法被调用之后触发,可用于处理控件的加载数据
|
||||
*/
|
||||
protected void setView() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 该方法是在onCreate()方法里执行,在setContentView()方法被调用之后触发,可用于处理控件的设置监听器
|
||||
*/
|
||||
protected void setListener() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base;
|
||||
package base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
@@ -14,13 +14,13 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewbinding.ViewBinding;
|
||||
import com.yizhuan.erban.base.fragmentation.ISupportActivity;
|
||||
import com.yizhuan.erban.base.fragmentation.ISupportFragment;
|
||||
import com.yizhuan.erban.base.fragmentation.SupportFragmentDelegate;
|
||||
import com.yizhuan.erban.base.fragmentation.windowcallback.WindowCallbackProxyUtil;
|
||||
import com.yizhuan.erban.base.util.ViewBindingUtil;
|
||||
import com.yizhuan.erban.common.util.ActivityHelper;
|
||||
import com.yizhuan.xchat_android_core.utils.Logger;
|
||||
import fragmentation.ISupportActivity;
|
||||
import fragmentation.ISupportFragment;
|
||||
import fragmentation.SupportFragmentDelegate;
|
||||
import fragmentation.windowcallback.WindowCallbackProxyUtil;
|
||||
import util.ActivityHelper;
|
||||
import util.Logger;
|
||||
import util.ViewBindingUtil;
|
||||
|
||||
public abstract class BaseDialogFragment<VB extends ViewBinding> extends DialogFragment implements ISupportFragment {
|
||||
private final String TAG = getClass().getSimpleName();
|
@@ -1,12 +1,13 @@
|
||||
package com.yizhuan.erban.base;
|
||||
package base;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import com.yizhuan.erban.R;
|
||||
import com.yizhuan.xchat_android_core.utils.Logger;
|
||||
import com.yizhuan.xchat_android_library.R;
|
||||
|
||||
import util.Logger;
|
||||
|
||||
/**
|
||||
* author: wushaocheng
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation;
|
||||
package fragmentation;
|
||||
|
||||
/**
|
||||
* Created by YoKey on 17/6/13.
|
||||
@@ -6,7 +6,7 @@ package com.yizhuan.erban.base.fragmentation;
|
||||
public interface ISupportActivity {
|
||||
SupportActivityDelegate getSupportDelegate();
|
||||
|
||||
void onBackPressed();
|
||||
void onBackPressedPage();
|
||||
|
||||
void onBackPressedSupport();
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation;
|
||||
package fragmentation;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
@@ -1,10 +1,10 @@
|
||||
package com.yizhuan.erban.base.fragmentation;
|
||||
package fragmentation;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.yizhuan.erban.base.fragmentation.queue.Action;
|
||||
import fragmentation.queue.Action;
|
||||
|
||||
public class SupportActivityDelegate {
|
||||
private final ISupportActivity mSupport;
|
||||
@@ -33,7 +33,7 @@ public class SupportActivityDelegate {
|
||||
/**
|
||||
* 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
|
||||
*/
|
||||
public void onBackPressed() {
|
||||
public void onBackPressedPage() {
|
||||
mTransactionDelegate.mActionQueue.enqueue(new Action(Action.ACTION_BACK, getSupportFragmentManager()) {
|
||||
@Override
|
||||
public void run() {
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation;
|
||||
package fragmentation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
@@ -11,8 +11,8 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.yizhuan.erban.base.fragmentation.internal.ResultRecord;
|
||||
import com.yizhuan.erban.base.fragmentation.internal.TransactionRecord;
|
||||
import fragmentation.internal.ResultRecord;
|
||||
import fragmentation.internal.TransactionRecord;
|
||||
|
||||
public class SupportFragmentDelegate {
|
||||
int mContainerId;
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation;
|
||||
package fragmentation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation;
|
||||
package fragmentation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -9,10 +9,10 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.yizhuan.erban.base.fragmentation.internal.ResultRecord;
|
||||
import com.yizhuan.erban.base.fragmentation.internal.TransactionRecord;
|
||||
import com.yizhuan.erban.base.fragmentation.queue.Action;
|
||||
import com.yizhuan.erban.base.fragmentation.queue.ActionQueue;
|
||||
import fragmentation.internal.ResultRecord;
|
||||
import fragmentation.internal.TransactionRecord;
|
||||
import fragmentation.queue.Action;
|
||||
import fragmentation.queue.ActionQueue;
|
||||
|
||||
import java.util.List;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation.internal;
|
||||
package fragmentation.internal;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation.internal;
|
||||
package fragmentation.internal;
|
||||
|
||||
/**
|
||||
* @hide Created by YoKey on 16/11/25.
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation.queue;
|
||||
package fragmentation.queue;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation.queue;
|
||||
package fragmentation.queue;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation.windowcallback
|
||||
package fragmentation.windowcallback
|
||||
|
||||
import android.view.Window
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.base.fragmentation.windowcallback
|
||||
package fragmentation.windowcallback
|
||||
|
||||
import android.view.Window
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.yizhuan.erban.common.util;
|
||||
package util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
@@ -1,6 +1,4 @@
|
||||
package com.yizhuan.erban.common.util;
|
||||
|
||||
import com.yizhuan.xchat_android_core.utils.Logger;
|
||||
package util;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.EventBusException;
|
719
library/src/module_common/java/util/Logger.java
Normal file
719
library/src/module_common/java/util/Logger.java
Normal file
@@ -0,0 +1,719 @@
|
||||
/**
|
||||
* Log类。可以直接使用静态函数
|
||||
* 也可以用某个tag生成一个logger对象
|
||||
* 使用前需要先调用init初始化
|
||||
* 内部使用android的Log类实现,并支持写入文件
|
||||
*/
|
||||
package util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.yizhuan.xchat_android_library.utils.StringUtils;
|
||||
import com.yizhuan.xchat_android_library.utils.config.BasicConfig;
|
||||
import com.yizhuan.xchat_android_library.utils.log.MLog;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
/**
|
||||
* @author daixiang
|
||||
*
|
||||
*/
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public class Logger {
|
||||
|
||||
public enum LogLevel {
|
||||
Verbose,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error
|
||||
}
|
||||
|
||||
// 写log文件策略
|
||||
public enum LogFilePolicy {
|
||||
NoLogFile, // 不写文件
|
||||
PerDay, // 一天只产生一个log文件
|
||||
PerLaunch // 每次运行均产生一个log文件
|
||||
}
|
||||
|
||||
public static class LogConfig {
|
||||
public String dir; // log文件目录,绝对路径
|
||||
public LogFilePolicy policy;
|
||||
public LogLevel outputLevel; // 输出级别,大于等于此级别的log才会输出
|
||||
public LogLevel fileLevel; // 输出到文件的级别,大于等于此级别的log才会写入文件
|
||||
public int fileFlushCount; // 每次累计log超过此条数时,会检查是否需要flush log文件
|
||||
public int fileFlushInterval; // 定时每隔一定秒数检查是否需要flush log文件
|
||||
public int fileFlushMinInterval; // 距离上次flush最少需要多少秒
|
||||
|
||||
public LogConfig() {
|
||||
policy = LogFilePolicy.PerLaunch;
|
||||
outputLevel = LogLevel.Verbose;
|
||||
fileLevel = LogLevel.Info;
|
||||
fileFlushCount = 10;
|
||||
fileFlushInterval = 60;
|
||||
fileFlushMinInterval = 10;
|
||||
}
|
||||
public LogConfig(LogConfig cfg) {
|
||||
this.dir = cfg.dir;
|
||||
this.policy = cfg.policy;
|
||||
this.outputLevel = cfg.outputLevel;
|
||||
this.fileLevel = cfg.fileLevel;
|
||||
this.fileFlushCount = cfg.fileFlushCount;
|
||||
this.fileFlushInterval = cfg.fileFlushInterval;
|
||||
this.fileFlushMinInterval = cfg.fileFlushMinInterval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ConcurrentHashMap<String, Logger> loggers = new ConcurrentHashMap<String, Logger>();
|
||||
// private static Context context;
|
||||
private static LoggerThread loggerThread; // 用于在另一个线程写log文件
|
||||
|
||||
private static LogConfig config = new LogConfig();
|
||||
// 写文件线程未准备好的时候,将可以写入文件的log先缓存起来
|
||||
private static List<String> logList = Collections.synchronizedList(new ArrayList<String>());
|
||||
|
||||
private String myTag;
|
||||
|
||||
private Logger(String tag) {
|
||||
myTag = tag;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return myTag;
|
||||
}
|
||||
|
||||
// public static void init(Context ctx) {
|
||||
//
|
||||
// LogConfig cfg = new LogConfig();
|
||||
// if (ctx != null) {
|
||||
// File f = ctx.getExternalCacheDir();
|
||||
// if (f != null
|
||||
// && Environment.getExternalStorageState().equals(
|
||||
// Environment.MEDIA_MOUNTED)) {
|
||||
// Log.i("Logger", "cache dir = " + f.getAbsolutePath());
|
||||
// cfg.dir = f.getAbsolutePath() + "/logs";
|
||||
// } else {
|
||||
// Log.i("Logger", "no extenal storage available");
|
||||
// f = ctx.getCacheDir();
|
||||
// if (f != null) {
|
||||
// cfg.dir = f.getAbsolutePath() + "/logs";
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// cfg.policy = LogFilePolicy.PerLaunch;
|
||||
// cfg.outputLevel = LogLevel.Verbose;
|
||||
// cfg.fileLevel = LogLevel.Info;
|
||||
//
|
||||
// Logger.init(ctx, cfg);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 使用Logger之前,必须先init
|
||||
* @param cfg
|
||||
*/
|
||||
public static void init(LogConfig cfg) {
|
||||
|
||||
// context = ctx;
|
||||
info("Logger", "init Logger");
|
||||
config = new LogConfig(cfg);
|
||||
|
||||
// if (config.policy != LogFilePolicy.NoLogFile && loggerThread == null) {
|
||||
// loggerThread = new LoggerThread("LoggerThread", config);
|
||||
// loggerThread.start();
|
||||
// }
|
||||
|
||||
initMLog(config);
|
||||
}
|
||||
|
||||
public static void initMLog(LogConfig cfg) {
|
||||
if (cfg.policy != LogFilePolicy.NoLogFile) {
|
||||
String logDir = cfg.dir;
|
||||
MLog.LogOptions options = new MLog.LogOptions();
|
||||
if (BasicConfig.INSTANCE.isDebuggable()) {
|
||||
options.logLevel = MLog.LogOptions.LEVEL_VERBOSE;
|
||||
} else {
|
||||
options.logLevel = MLog.LogOptions.LEVEL_INFO;
|
||||
}
|
||||
options.honorVerbose = false;
|
||||
options.logFileName = "logs.txt";
|
||||
MLog.initialize(logDir, options);
|
||||
MLog.info("Logger", "init MLog, logFilePath = " + logDir + File.separator + options.logFileName);
|
||||
}
|
||||
}
|
||||
|
||||
public static Logger getLogger(String tag) {
|
||||
if (StringUtils.isEmpty(tag)) {
|
||||
tag = "Default";
|
||||
}
|
||||
Logger logger;
|
||||
try {
|
||||
logger = loggers.get(tag);
|
||||
if (logger == null) {
|
||||
logger = new Logger(tag);
|
||||
loggers.put(tag, logger);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MLog.error("Logger", "getLogger error! " + e);
|
||||
logger = new Logger(tag);
|
||||
}
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
public static Logger getLogger(Class<?> cls) {
|
||||
if (cls == null) {
|
||||
return Logger.getLogger("");
|
||||
}
|
||||
|
||||
// String className = cls.getName();
|
||||
// String tag = className.substring(className.lastIndexOf(".") + 1);
|
||||
return Logger.getLogger(cls.getSimpleName());
|
||||
}
|
||||
|
||||
private static boolean isLoggable(LogLevel level) {
|
||||
return level.compareTo(config.outputLevel) >= 0;
|
||||
}
|
||||
|
||||
private static String levelToString(LogLevel level) {
|
||||
String str = "";
|
||||
switch (level) {
|
||||
case Debug:
|
||||
str = "Debug";
|
||||
break;
|
||||
case Error:
|
||||
str = "Error";
|
||||
break;
|
||||
case Info:
|
||||
str = "Info";
|
||||
break;
|
||||
case Verbose:
|
||||
str = "Verbose";
|
||||
break;
|
||||
case Warn:
|
||||
str = "Warn";
|
||||
break;
|
||||
default:
|
||||
str = "Debug";
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String getLogFilePath() {
|
||||
if (loggerThread != null) {
|
||||
return loggerThread.getFilePath();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void logToFile(String tag, LogLevel level, String message, Throwable t) {
|
||||
|
||||
if (config.policy != LogFilePolicy.NoLogFile) {
|
||||
if (loggerThread == null || !loggerThread.isReady()) {
|
||||
// 文件线程未准备好,先缓存
|
||||
logList.add(LoggerThread.getFormattedString(tag, level, message));
|
||||
} else {
|
||||
loggerThread.logToFile(tag, level, message, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void log(String tag, LogLevel level, String message) {
|
||||
if (Logger.isLoggable(level)) {
|
||||
message = msgForTextLog(tag, message);
|
||||
switch (level) {
|
||||
case Debug:
|
||||
// Log.d(tag, message);
|
||||
MLog.debugWithoutLineNumber(tag, message);
|
||||
break;
|
||||
case Error:
|
||||
// Log.e(tag, message);
|
||||
MLog.errorWithoutLineNumber(tag, message);
|
||||
break;
|
||||
case Info:
|
||||
// Log.i(tag, message);
|
||||
MLog.infoWithoutLineNumber(tag, message);
|
||||
break;
|
||||
case Verbose:
|
||||
// Log.v(tag, message);
|
||||
MLog.verboseWithoutLineNumber(tag, message);
|
||||
break;
|
||||
case Warn:
|
||||
// Log.w(tag, message);
|
||||
MLog.warnWithoutLineNumber(tag, message);
|
||||
break;
|
||||
default:
|
||||
// Log.d(tag, message);
|
||||
MLog.debugWithoutLineNumber(tag, message);
|
||||
break;
|
||||
}
|
||||
// logToFile(tag, level, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void logError(String tag, String msg, Throwable tr) {
|
||||
if (Logger.isLoggable(LogLevel.Error)) {
|
||||
// msg = msgForTextLog(tag, msg);
|
||||
if (tr == null) {
|
||||
// Log.e(tag, msg);
|
||||
MLog.error(tag, msg);
|
||||
} else {
|
||||
// Log.e(tag, msg, tr);
|
||||
MLog.error(tag, msg, tr);
|
||||
}
|
||||
// logToFile(tag, LogLevel.Error, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
// public static void log(String tag, LogLevel level, String message, Throwable throwable) {
|
||||
// switch (level) {
|
||||
// case Debug:
|
||||
// Log.d(tag, message, throwable);
|
||||
// break;
|
||||
// case Error:
|
||||
// Log.e(tag, message, throwable);
|
||||
// break;
|
||||
// case Info:
|
||||
// Log.i(tag, message, throwable);
|
||||
// break;
|
||||
// case Verbose:
|
||||
// Log.v(tag, message, throwable);
|
||||
// break;
|
||||
// case Warn:
|
||||
// Log.v(tag, message, throwable);
|
||||
// break;
|
||||
// default:
|
||||
// Log.d(tag, message, throwable);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
private static String msgForTextLog(String tag, String message) {
|
||||
if (message == null) {
|
||||
message = "null";
|
||||
}
|
||||
int line = -1;
|
||||
String filename = null;
|
||||
if (Thread.currentThread().getStackTrace().length > 4) {
|
||||
line = Thread.currentThread().getStackTrace()[4].getLineNumber();
|
||||
filename = Thread.currentThread().getStackTrace()[4].getFileName();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
sb.append(tag);
|
||||
sb.append("] ");
|
||||
sb.append(message);
|
||||
sb.append("(P:");
|
||||
sb.append(android.os.Process.myPid());
|
||||
sb.append(")");
|
||||
sb.append("(T:");
|
||||
if (Looper.getMainLooper() == Looper.myLooper())
|
||||
sb.append("Main&");
|
||||
else
|
||||
sb.append(Thread.currentThread().getId());
|
||||
sb.append(")");
|
||||
// sb.append("(C:");
|
||||
// sb.append(tag);
|
||||
// sb.append(")");
|
||||
if (filename != null) {
|
||||
sb.append(" at (");
|
||||
sb.append(filename);
|
||||
}
|
||||
if (line > 0) {
|
||||
sb.append(":");
|
||||
sb.append(line);
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void verbose(String tag, String message) {
|
||||
// message = msgForTextLog(tag, message);
|
||||
Logger.log(tag, LogLevel.Verbose, message);
|
||||
}
|
||||
|
||||
public static void debug(String tag, String message) {
|
||||
// message = msgForTextLog(tag, message);
|
||||
Logger.log(tag, LogLevel.Debug, message);
|
||||
}
|
||||
|
||||
public static void info(String tag, String message) {
|
||||
// message = msgForTextLog(tag, message);
|
||||
Logger.log(tag, LogLevel.Info, message);
|
||||
}
|
||||
|
||||
public static void warn(String tag, String message) {
|
||||
// message = msgForTextLog(tag, message);
|
||||
Logger.log(tag, LogLevel.Warn, message);
|
||||
}
|
||||
|
||||
public static void error(String tag, String message) {
|
||||
// message = msgForTextLog(tag, message);
|
||||
Logger.log(tag, LogLevel.Error, message);
|
||||
}
|
||||
|
||||
public static void error(String tag, String message, Throwable throwable) {
|
||||
// message = msgForTextLog(tag, message);
|
||||
Logger.logError(tag, message, throwable);
|
||||
}
|
||||
|
||||
public void verbose(String message) {
|
||||
Logger.verbose(myTag, message);
|
||||
// message = msgForTextLog(myTag, message);
|
||||
// MLog.verboseWithoutLineNumber(myTag, message);
|
||||
}
|
||||
|
||||
public void debug(String message) {
|
||||
Logger.debug(myTag, message);
|
||||
// message = msgForTextLog(myTag, message);
|
||||
// MLog.debugWithoutLineNumber(myTag, message);
|
||||
}
|
||||
|
||||
public void info(String message) {
|
||||
Logger.info(myTag, message);
|
||||
// message = msgForTextLog(myTag, message);
|
||||
// MLog.infoWithoutLineNumber(myTag, message);
|
||||
}
|
||||
|
||||
public void warn(String message) {
|
||||
Logger.warn(myTag, message);
|
||||
// message = msgForTextLog(myTag, message);
|
||||
// MLog.warnWithoutLineNumber(myTag, message);
|
||||
}
|
||||
|
||||
public void error(String message) {
|
||||
Logger.error(myTag, message);
|
||||
// message = msgForTextLog(myTag, message);
|
||||
// MLog.errorWithoutLineNumber(myTag, message);
|
||||
}
|
||||
|
||||
public void error(String message, Throwable throwable) {
|
||||
Logger.logError(myTag, message, throwable);
|
||||
// message = msgForTextLog(myTag, message);
|
||||
// MLog.errorWithoutLineNumber(myTag, message, throwable);
|
||||
}
|
||||
|
||||
public static void onTerminate() {
|
||||
if (loggerThread != null) {
|
||||
loggerThread.sendFlush();
|
||||
}
|
||||
}
|
||||
|
||||
// private static class SdkLogger implements ILog {
|
||||
//
|
||||
// @Override
|
||||
// public void verbose(String tag, String msg) {
|
||||
//
|
||||
// Logger.verbose(tag, msg);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void debug(String tag, String msg) {
|
||||
//
|
||||
// Logger.debug(tag, msg);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void info(String tag, String msg) {
|
||||
//
|
||||
// Logger.info(tag, msg);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void warn(String tag, String msg) {
|
||||
//
|
||||
// Logger.warn(tag, msg);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void error(String tag, String msg) {
|
||||
//
|
||||
// Logger.error(tag, msg);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void error(String tag, String msg, Throwable t) {
|
||||
// Logger.error(tag, msg, t);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* 用于写log文件的线程
|
||||
* @author daixiang
|
||||
*
|
||||
*/
|
||||
private static class LoggerThread extends Thread {
|
||||
|
||||
private static final int LogMessageType = 0;
|
||||
private static final int TimerMessageType = 1;
|
||||
private static final int LogThrowableType = 2;
|
||||
private static final int FlushLog = 3;
|
||||
|
||||
private LogThreadHandler handler; // 使用此handler将log消息发到此线程处理
|
||||
private LogConfig config;
|
||||
private String filePath;
|
||||
private boolean isReady = false;
|
||||
|
||||
public LoggerThread(String name, LogConfig cfg) {
|
||||
super(name);
|
||||
config = cfg;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return isReady;
|
||||
}
|
||||
|
||||
private static String getFormattedString(String tag, LogLevel level, String msg) {
|
||||
|
||||
String thread = (Looper.getMainLooper() == Looper.myLooper()) ? "[Main]"
|
||||
: ("[" + Thread.currentThread().getId() + "]");
|
||||
String strLevel = "[" + Logger.levelToString(level) + "]";
|
||||
String logMsg = thread + "[" + tag + "]" + strLevel + " " + msg;
|
||||
return logMsg;
|
||||
}
|
||||
|
||||
public void logToFile(String tag, LogLevel level, String msg, Throwable t) {
|
||||
if ((config.policy != LogFilePolicy.NoLogFile)
|
||||
&& (level.compareTo(config.fileLevel) >= 0)
|
||||
&& (handler != null)) {
|
||||
|
||||
String logMsg = getFormattedString(tag, level, msg);
|
||||
|
||||
Message threadMessage = null;
|
||||
if (t == null) {
|
||||
threadMessage = handler.obtainMessage(LogMessageType);
|
||||
threadMessage.obj = logMsg;
|
||||
} else {
|
||||
threadMessage = handler.obtainMessage(LogThrowableType);
|
||||
threadMessage.obj = logMsg;
|
||||
Bundle b = new Bundle();
|
||||
b.putSerializable("throwable", t);
|
||||
threadMessage.setData(b);
|
||||
}
|
||||
|
||||
if (threadMessage != null) {
|
||||
handler.sendMessage(threadMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendFlush() {
|
||||
if (handler != null) {
|
||||
handler.sendEmptyMessage(FlushLog);
|
||||
}
|
||||
}
|
||||
|
||||
// public void logToFile(String tag, LogLevel level, String msg) {
|
||||
// logToFile(tag, level, msg, null);
|
||||
// }
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
Looper.prepare();
|
||||
|
||||
File logDir = new File(config.dir);
|
||||
if (!logDir.exists()) {
|
||||
Logger.info("Logger", "create log dir: " + logDir.getAbsolutePath());
|
||||
logDir.mkdirs();
|
||||
}
|
||||
|
||||
SimpleDateFormat f;
|
||||
if (config.policy == LogFilePolicy.PerLaunch) {
|
||||
f = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss-SSS");
|
||||
} else {
|
||||
f = new SimpleDateFormat("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
filePath = config.dir + "/" + f.format(new Date()) + ".log";
|
||||
Logger.info("Logger", "log file name: " + filePath);
|
||||
|
||||
handler = new LogThreadHandler(this);
|
||||
isReady = true;
|
||||
|
||||
// 将之前缓存的log先写入文件
|
||||
List<String> list = new ArrayList<String>(logList);
|
||||
try {
|
||||
if (list.size() > 0) {
|
||||
Logger.debug("Logger", "write logs before logger thread ready to file: " + list.size());
|
||||
for (String s : list) {
|
||||
handler.writeLine(s);
|
||||
}
|
||||
handler.flush(true);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
logList.clear();
|
||||
list.clear();
|
||||
list = null;
|
||||
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
private static class LogThreadHandler extends Handler {
|
||||
|
||||
private SimpleDateFormat dateFormat;
|
||||
private BufferedWriter writer;
|
||||
private LoggerThread loggerThread;
|
||||
private int logCounter;
|
||||
private long lastFlushTime;
|
||||
|
||||
private void writeLine(String formattedStr) throws IOException {
|
||||
if (writer != null) {
|
||||
writer.write(dateFormat.format(new Date()) + " " + formattedStr);
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
public LogThreadHandler(LoggerThread thread) {
|
||||
loggerThread = thread;
|
||||
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
boolean append;
|
||||
if (loggerThread.config.policy == LogFilePolicy.PerLaunch) {
|
||||
append = false;
|
||||
|
||||
} else {
|
||||
append = true;
|
||||
}
|
||||
|
||||
try {
|
||||
FileWriter fw = new FileWriter(loggerThread.filePath, append);
|
||||
writer = new BufferedWriter(fw);
|
||||
if (loggerThread.config.policy == LogFilePolicy.PerDay) {
|
||||
writer.newLine();
|
||||
}
|
||||
// writer.write(dateFormat.format(new Date()) + " " + loggerThread.getFormattedString("Logger", loggerThread.config.fileLevel, "---------------------Log Begin---------------------"));
|
||||
// writer.newLine();
|
||||
|
||||
// 在文件开头加入一个易于识别的行
|
||||
writeLine(getFormattedString("Logger", loggerThread.config.fileLevel, "---------------------Log Begin---------------------"));
|
||||
flush(true);
|
||||
} catch (IOException e) {
|
||||
writer = null;
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (writer != null && loggerThread.config.fileFlushInterval > 0) {
|
||||
long time = loggerThread.config.fileFlushInterval * 1000;
|
||||
new Timer().schedule(new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Message msg = obtainMessage(TimerMessageType);
|
||||
sendMessage(msg);
|
||||
}
|
||||
}, time, time);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush(boolean force) throws IOException {
|
||||
if (writer != null) {
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
// 不要太频繁flush,最低间隔
|
||||
if ((now - lastFlushTime) > (loggerThread.config.fileFlushMinInterval * 1000)) {
|
||||
writer.flush();
|
||||
lastFlushTime = System.currentTimeMillis();
|
||||
logCounter = 0;
|
||||
} else {
|
||||
logCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void flushIfNeeded() throws IOException {
|
||||
if (logCounter > loggerThread.config.fileFlushCount) {
|
||||
flush(false);
|
||||
} else {
|
||||
logCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
|
||||
if (writer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
switch (msg.what) {
|
||||
|
||||
case LogMessageType:
|
||||
{
|
||||
// String str = dateFormat.format(new Date()) + " "
|
||||
// + msg.obj;
|
||||
// writer.write(str);
|
||||
// writer.newLine();
|
||||
writeLine((String)msg.obj);
|
||||
flushIfNeeded();
|
||||
break;
|
||||
}
|
||||
case LogThrowableType:
|
||||
{
|
||||
// String str = dateFormat.format(new Date()) + " "
|
||||
// + msg.obj;
|
||||
// writer.write(str);
|
||||
// writer.newLine();
|
||||
writeLine((String)msg.obj);
|
||||
Bundle data = msg.getData();
|
||||
if (data != null) {
|
||||
Throwable t = (Throwable) data
|
||||
.getSerializable("throwable");
|
||||
if (t != null) {
|
||||
PrintWriter pw = new PrintWriter(writer);
|
||||
t.printStackTrace(pw);
|
||||
//pw.close(); // 不能close,否则内部的bufferedwriter也会被close!
|
||||
writer.newLine();
|
||||
flush(true); // 异常,立刻flush
|
||||
} else {
|
||||
flushIfNeeded();
|
||||
}
|
||||
} else {
|
||||
flushIfNeeded();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TimerMessageType:
|
||||
flush(false);
|
||||
break;
|
||||
case FlushLog:
|
||||
flush(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,4 @@
|
||||
package com.yizhuan.erban.common.util;
|
||||
|
||||
import com.yizhuan.xchat_android_core.utils.Logger;
|
||||
package util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
178
library/src/module_common/java/util/Utils.java
Normal file
178
library/src/module_common/java/util/Utils.java
Normal file
@@ -0,0 +1,178 @@
|
||||
package util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* author: wushaocheng
|
||||
* time: 2022/11/15
|
||||
* desc: 转换帮助类
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
public static <T> boolean notEmpty(List<T> list) {
|
||||
return !isEmpty(list);
|
||||
}
|
||||
|
||||
public static <T> boolean isEmpty(List<T> list) {
|
||||
if (list == null || list.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getNavigationBarHeight(Context context) {
|
||||
int statusBarHeight = 0;
|
||||
int resourceId = context.getResources().getIdentifier("config_showNavigationBar", "bool", "android");
|
||||
if (resourceId != 0) {
|
||||
resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
|
||||
//根据资源ID获取响应的尺寸值
|
||||
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
|
||||
}
|
||||
return statusBarHeight;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断底部navigator是否已经显示
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
public static boolean hasSoftKeys(Context context) {
|
||||
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display d = windowManager.getDefaultDisplay();
|
||||
|
||||
|
||||
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
|
||||
d.getRealMetrics(realDisplayMetrics);
|
||||
|
||||
|
||||
int realHeight = realDisplayMetrics.heightPixels;
|
||||
int realWidth = realDisplayMetrics.widthPixels;
|
||||
|
||||
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
d.getMetrics(displayMetrics);
|
||||
|
||||
|
||||
int displayHeight = displayMetrics.heightPixels;
|
||||
int displayWidth = displayMetrics.widthPixels;
|
||||
|
||||
|
||||
return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
|
||||
}
|
||||
|
||||
// 将px值转换为dip或dp值
|
||||
public static int px2dip(Context context, float pxValue) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (pxValue / scale + 0.5f);
|
||||
}
|
||||
|
||||
// 将dip或dp值转换为px值
|
||||
public static int dip2px(Context context, float dipValue) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dipValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
// 将px值转换为sp值
|
||||
public static int px2sp(Context context, float pxValue) {
|
||||
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (pxValue / fontScale + 0.5f);
|
||||
}
|
||||
|
||||
// 将sp值转换为px值
|
||||
public static int sp2px(Context context, float spValue) {
|
||||
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (spValue * fontScale + 0.5f);
|
||||
}
|
||||
|
||||
// 屏幕宽度(像素)
|
||||
public static int getWindowWidth(Context context) {
|
||||
DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
|
||||
return dm.widthPixels;
|
||||
}
|
||||
|
||||
// 屏幕高度(像素)
|
||||
public static int getWindowHeight(Context context) {
|
||||
DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
|
||||
return dm.heightPixels;
|
||||
}
|
||||
|
||||
// 根据Unicode编码判断中文汉字和符号
|
||||
private static boolean isChinese(char c) {
|
||||
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
|
||||
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|
||||
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
|
||||
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
|
||||
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断中文汉字和符号
|
||||
public static boolean isChinese(String strName) {
|
||||
char[] ch = strName.toCharArray();
|
||||
for (int i = 0; i < ch.length; i++) {
|
||||
char c = ch[i];
|
||||
if (isChinese(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getScreenPxWidth(Context context) {
|
||||
WindowManager wm = (WindowManager) context
|
||||
.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(outMetrics);
|
||||
return outMetrics.widthPixels;
|
||||
}
|
||||
|
||||
public static int getScreenDpWidth(Context context) {
|
||||
int pxWidth = getScreenPxWidth(context);
|
||||
return (int) px2dip(context, pxWidth);
|
||||
}
|
||||
|
||||
public static int getScreenPxHeight(Context context) {
|
||||
WindowManager wm = (WindowManager) context
|
||||
.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(outMetrics);
|
||||
return outMetrics.heightPixels;
|
||||
}
|
||||
|
||||
public static int getScreenDpHeight(Context context) {
|
||||
int pxHeight = getScreenPxHeight(context);
|
||||
return (int) px2dip(context, pxHeight);
|
||||
}
|
||||
|
||||
public static void executePendingTransactionsSafely(String TAG, FragmentManager fragmentManager) {
|
||||
if (fragmentManager == null) {
|
||||
Logger.error(TAG, "executePendingTransactionsSafely fragmentManager == null");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
fragmentManager.executePendingTransactions();
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, String.valueOf(e));
|
||||
try {
|
||||
Field mExecutingActions = fragmentManager.getClass().getDeclaredField("mExecutingActions");
|
||||
mExecutingActions.setAccessible(true);
|
||||
mExecutingActions.set(fragmentManager, false);
|
||||
} catch (Exception e1) {
|
||||
Logger.error(TAG, "set field value fail", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,9 +1,8 @@
|
||||
package com.yizhuan.erban.base.util
|
||||
package util
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.yizhuan.xchat_android_core.utils.Logger
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
|
6
library/src/module_common/res/values/ids.xml
Normal file
6
library/src/module_common/res/values/ids.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<item name="baseViewTagID" type="id" />
|
||||
|
||||
</resources>
|
4
library/src/module_common/res/values/strings.xml
Normal file
4
library/src/module_common/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<resources>
|
||||
<string name="text_bitmap_too_large">上傳失敗,圖片太大啦~</string>
|
||||
<string name="text_bitmap_too_small">上傳圖片不能小於20kb</string>
|
||||
</resources>
|
Reference in New Issue
Block a user