You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

603 lines
21 KiB

package com.community.pocket.ui.main.ui.info;
import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModelProvider;
import com.community.pocket.R;
import com.community.pocket.data.model.CreditScore;
import com.community.pocket.data.model.LocalToken;
import com.community.pocket.data.model.MyInfo;
import com.community.pocket.ui.BaseFragment;
import com.community.pocket.ui.listener.MyTextChange;
import com.community.pocket.ui.login.LoginActivity;
import com.community.pocket.ui.main.ui.share.Response;
import com.community.pocket.util.AppDatabase;
import com.community.pocket.util.Param;
import com.community.pocket.util.PermissionsUtils;
import com.community.pocket.util.PropertiesUtil;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.utils.Utils;
import org.xutils.view.annotation.ContentView;
import org.xutils.view.annotation.Event;
import org.xutils.view.annotation.ViewInject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 我的信息框架
*/
@ContentView(R.layout.info_fragment)
public class InfoFragment extends BaseFragment {
//昵称
@ViewInject(R.id.nickname)
private TextView nickname;
//信用分
@ViewInject(R.id.credit_score)
private TextView creditScore;
//头像
@ViewInject(R.id.headimg)
private ImageView headimg;
//最近发帖数
@ViewInject(R.id.recentPosts)
private TextView recentPosts;
//最近访客数
@ViewInject(R.id.recentVisitors)
private TextView recentVisitors;
//手机号
@ViewInject(R.id.mobie)
private TextView mobie;
//邮箱
@ViewInject(R.id.email)
private TextView email;
//信用分活动图表
@ViewInject(R.id.chart)
private LineChart lineChart;
//原密码
private EditText oldPwd;
//新密码
private EditText newPwd;
//确认新密码
private EditText confirmNewPwd;
//打开修改密码弹窗
@ViewInject(R.id.open_modify_password)
private Button openModify;
private InfoViewModel viewModel;
//注销登录
@ViewInject(R.id.logout)
private Button logout;
//修改密码
private Handler modifyPwdHandler;
//上传头像
private Handler uploadImgHandler;
//检测是否有读写文件权限
private MutableLiveData<Boolean> bool = new MutableLiveData<>();
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initChart();
viewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(InfoViewModel.class);
viewModel.loadInfo();
//监听修改密码表单状态
viewModel.getModifyFormState().observe(getViewLifecycleOwner(), infoFormState -> {
if (infoFormState == null) {
return;
}
if (infoFormState.getOldPwdError() != null) {
oldPwd.setError(getString(infoFormState.getOldPwdError(), PropertiesUtil.getIntValue("password.length")));
}
if (infoFormState.getNewPwdError() != null) {
if (infoFormState.getNewPwdError() == R.string.invalid_password) {
newPwd.setError(getString(infoFormState.getNewPwdError(), PropertiesUtil.getIntValue("password.length")));
} else {
newPwd.setError(getString(infoFormState.getNewPwdError()));
}
}
if (infoFormState.getConfirmNewPwdError() != null) {
if (infoFormState.getConfirmNewPwdError() == R.string.invalid_password) {
confirmNewPwd.setError(getString(infoFormState.getConfirmNewPwdError(), PropertiesUtil.getIntValue("password.length")));
} else {
confirmNewPwd.setError(getString(infoFormState.getConfirmNewPwdError()));
}
}
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putBoolean(Param.enable.name(), infoFormState.isDataValid());
message.setData(bundle);
modifyPwdHandler.sendMessage(message);
});
//监听修改密码的请求状态
viewModel.getModifyResponse().observe(getViewLifecycleOwner(), infoResponse -> {
if (infoResponse == null) {
return;
}
infoResponse.toast(getContext());
if (infoResponse.getResult() == Response.Result.OK) {
logout(logout);
}
});
//监听个人信息请求状态
viewModel.getInfoResponse().observe(getViewLifecycleOwner(), myInfoInfoResponse -> {
if (myInfoInfoResponse == null) {
return;
}
myInfoInfoResponse.toast(getContext());
if (myInfoInfoResponse.getResult() == Response.Result.OK) {
loadInfo(myInfoInfoResponse.getMyInfo());
}
});
//打开修改密码弹窗
openModify.setOnClickListener(v -> openModifyPassword());
checkPermissions();
clickHeadImg();
//监听上传头像状态
viewModel.getUploadImg().observe(getViewLifecycleOwner(), infoResponse -> {
if (infoResponse == null) {
return;
}
uploadImgHandler.sendEmptyMessage(infoResponse.getResult().ordinal());
infoResponse.toast(getContext());
});
//监听获取头像状态
viewModel.getGetImg().observe(getViewLifecycleOwner(), bitmap -> headimg.setImageBitmap(bitmap));
}
/**
* 加载个人信息
*
* @param myInfo 个人信息
*/
private void loadInfo(MyInfo myInfo) {
nickname.setText(getString(R.string.nick_name, myInfo.getId()));
creditScore.setText(getString(R.string.credit_score, myInfo.getCreditScore()));
recentVisitors.setText(getString(R.string.recent_visitors, myInfo.getVisitors()));
recentPosts.setText(getString(R.string.recent_posts, myInfo.getPosts()));
mobie.setText(myInfo.getMobie());
email.setText(myInfo.getEmail());
if (myInfo.getHeadImg() != null && !myInfo.getHeadImg().isEmpty()) {
viewModel.getImg(myInfo.getHeadImg());
}
if (myInfo.getScoreHistory() != null && myInfo.getScoreHistory().size() >= 2) {
loadChart(myInfo.getScoreHistory());
}
}
private enum Action {
//打开相册
OPEN_GALLERY,
//打开相机
OPEN_CAMERA,
//裁剪
CROP
}
/**
* 检查读写权限
*/
private void checkPermissions() {
PermissionsUtils.getInstance().checkPermissions(getActivity(), new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
new PermissionsUtils.IPermissionsResult() {
@Override
public void passPermissons() {
File file = getPhotoDir();
if (file.exists()) {
bool.postValue(true);
} else {
bool.postValue(false);
String msg = "无法创建照片目录";
Log.e(InfoFragment.class.getName(), msg);
throw new RuntimeException(msg);
}
}
@Override
public void forbitPermissons() {
bool.postValue(false);
}
});
}
/**
* 点击头像操作
*/
private void clickHeadImg() {
bool.observe(getViewLifecycleOwner(), aBoolean -> {
if (aBoolean) {
headimg.setOnClickListener(v -> new AlertDialog.Builder(Objects.requireNonNull(getContext()))
.setNegativeButton(R.string.open_photo_album, (dialog, which) -> {
// 打开相册
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, Action.OPEN_GALLERY.ordinal());
})
.setNeutralButton(R.string.take_photo, (dialog, which) -> {
//定义图片存储的位置
File file = getPhotoDir();
File photoFile = new File(file, System.currentTimeMillis() + "origin.png");
Log.i(InfoFragment.class.getName(), "图片存储到" + photoFile.getAbsolutePath());
// 隐式意图打开系统界面 --要求回传
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 存到什么位置
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
intent.putExtra(Action.OPEN_CAMERA.name(), photoFile);
startActivityForResult(intent, Action.OPEN_CAMERA.ordinal());
})
.setPositiveButton(R.string.action_close, (dialog, which) -> dialog.dismiss()).show());
} else {
headimg.setOnClickListener(v -> Toast.makeText(getContext(), R.string.not_permissions, Toast.LENGTH_LONG).show());
}
});
}
private File getPhotoDir() {
return new File(Environment.getExternalStorageDirectory(),
getString(R.string.app_name));
}
//打开裁剪应用
private Intent getCropIntent() {
return new Intent("com.android.camera.action.CROP");
}
//判断是否有裁剪应用
private boolean hasCrop() {
Context context = getContext();
return context != null && getCropIntent().resolveActivity(getContext().getPackageManager()) != null;
}
//设置头像
private void setHeadImg(Bitmap bitmap) {
File picFile = new File(getPhotoDir(), System.currentTimeMillis() + ".png");
try {
if (picFile.createNewFile()) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(
picFile));
Context context = Objects.requireNonNull(getContext());
TextView textView = new TextView(context);
textView.setTextSize(18);
textView.setGravity(Gravity.CENTER | Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
textView.setText(R.string.upload_img);
AlertDialog alertDialog = new AlertDialog.Builder(context)
.setView(textView).show();
uploadImgHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
alertDialog.dismiss();
if (msg.what == Response.Result.OK.ordinal()) {
headimg.setImageBitmap(bitmap);
}
}
};
viewModel.uploadImg(picFile);
}
} catch (IOException e) {
e.printStackTrace();
Log.e(InfoFragment.class.getName(), e.toString());
}
}
// 手机自带裁剪功能--调用系统裁剪的意图
private void crop(Uri uri) {
// 定义图片裁剪意图
Intent intent = getCropIntent();
intent.setDataAndType(uri, "image/*");
// 设置是否裁剪
intent.putExtra("crop", "true");
// 裁剪框的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// 设置输出图片的尺寸大小
int size = getResources().getInteger(R.integer.photo_size);
intent.putExtra("outputX", size);
intent.putExtra("outputY", size);
// 设置图片格式
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.name());
//是否返回数据
intent.putExtra("return-data", true);
startActivityForResult(intent, Action.CROP.ordinal());
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
Log.i(InfoFragment.class.getName(), "requestCode:" + requestCode + ",resultCode:" + resultCode);
if (data != null) {
//获取路径
if (requestCode == Action.OPEN_GALLERY.ordinal() || requestCode == Action.OPEN_CAMERA.ordinal()) {
if (hasCrop()) {
crop(data.getData());
} else {
Context context = getContext();
if (context != null) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), data.getData());
setHeadImg(bitmap);
} catch (IOException e) {
e.printStackTrace();
Log.e(InfoFragment.class.getName(), e.toString());
}
} else {
Log.e(InfoFragment.class.getName(), "无法获取Context");
}
}
} else if (requestCode == Action.CROP.ordinal()) {
//直接拿到一张图片
Bitmap bitmap = data.getParcelableExtra("data");
if (bitmap != null) {
setHeadImg(bitmap);
} else {
Log.e(InfoFragment.class.getName(), "无法获取裁剪图片");
}
}
}
}
/**
* 打开修改密码弹窗
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void openModifyPassword() {
View view = View.inflate(getContext(), R.layout.modify_password, null);
//原密码
oldPwd = view.findViewById(R.id.old_password);
//新密码
newPwd = view.findViewById(R.id.new_password);
//确认新密码
confirmNewPwd = view.findViewById(R.id.new_confirm_password);
TextWatcher textWatcher = new MyTextChange() {
@Override
public void afterTextChanged(Editable s) {
viewModel.modifyPwdChanged(oldPwd.getText().toString(), newPwd.getText().toString(), confirmNewPwd.getText().toString());
}
};
oldPwd.addTextChangedListener(textWatcher);
newPwd.addTextChangedListener(textWatcher);
confirmNewPwd.addTextChangedListener(textWatcher);
AlertDialog.Builder alert = new AlertDialog.Builder(Objects.requireNonNull(getContext()));
final AlertDialog alertDialog = alert.setTitle(R.string.modify_password).setView(view)
.setNegativeButton(R.string.modify_password, (dialog, which) -> {
viewModel.modifyPwd(oldPwd.getText().toString(), newPwd.getText().toString());
dialog.dismiss();
})
.setNeutralButton(R.string.action_close, (dialog, which) -> dialog.dismiss())
.create();
modifyPwdHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setEnabled(msg.getData().getBoolean(Param.enable.name()));
}
};
alertDialog.show();
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setEnabled(false);
}
/**
* 注销登录
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Event(value = R.id.logout)
private void logout(final View view) {
new Thread(() -> {
AppDatabase.getInstance(getContext()).tokenDao().delete(LocalToken.getTokenInstance());
LocalToken.logout();
startActivity(new Intent(view.getContext(), LoginActivity.class));
}).start();
}
/**
* 计算文本宽度
*/
private float computeTextWidth(String text, float textSize) {
Paint pain = new Paint();
pain.setAntiAlias(true);
pain.setTextSize(textSize);
Rect rect = new Rect();
pain.getTextBounds(text, 0, text.length(), rect);
return Utils.convertPixelsToDp(rect.left + rect.right);
}
//
private LineDataSet addChart(List<CreditScore> values) {
List<Entry> entryList = new ArrayList<>();
for (int i = 0; i < values.size(); i++) {
CreditScore score = values.get(i);
entryList.add(new Entry(i, score.getBeforeScore() + score.getScore()));
}
LineDataSet dataSet = new LineDataSet(entryList, "");
//线宽度
dataSet.setLineWidth(1.6f);
//不显示圆点
dataSet.setDrawCircles(false);
//线条平滑
// dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
dataSet.setValueTextSize(18);
dataSet.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
return String.valueOf((int) value);
}
});
return dataSet;
}
//设置图表格式
private void initChart() {
int textSize = 18;
//设置x轴数据格式
XAxis xAxis = lineChart.getXAxis();
//轴刻度最小值
xAxis.setAxisMinimum(1);
//轴刻度间隔最小值
xAxis.setGranularity(1);
//轴文本大小
xAxis.setTextSize(textSize);
//轴位置
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
//不显示网格线
xAxis.setDrawGridLines(false);
//设置Y轴数据格式
initYAxis(lineChart.getAxisLeft(), textSize);
initYAxis(lineChart.getAxisRight(), textSize);
//设置x轴0刻度和最后刻度的左右偏移,保证日期显示完整
float offset = computeTextWidth(getString(R.string.dateformat), textSize) + 3;
//设置轴左侧偏移
lineChart.setExtraLeftOffset(offset);
//设置轴右侧偏移
lineChart.setExtraRightOffset(offset);
// 设置底部偏移
lineChart.setExtraBottomOffset(20);
//隐藏描述信息
lineChart.getDescription().setEnabled(false);
//无数据时显示的文本
lineChart.setNoDataText(getString(R.string.no_score_history));
//图例:得到Lengend
Legend legend = lineChart.getLegend();
//隐藏Lengend
legend.setEnabled(false);
}
private void initYAxis(YAxis yAxis, int textSize) {
//轴细分粒度最小单位长度
yAxis.setAxisMinimum(1);
//轴间隔最小单位长度
yAxis.setGranularity(2);
//轴文本大小
yAxis.setTextSize(textSize);
//
yAxis.setXOffset(20);
}
//加载图表数据
private void loadChart(final List<CreditScore> values) {
LineData lineData;
if (lineChart.getData() == null) {
lineData = new LineData();
lineChart.setData(lineData);
} else {
lineData = lineChart.getData();
lineData.removeDataSet(0);
}
lineData.addDataSet(addChart(values));
//设置x轴数据格式
XAxis xAxis = lineChart.getXAxis();
//格式化日期数据
xAxis.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
int index = (int) (value - 1);
return formatUnix(values.get(index).getTime());
}
});
//设置标记
// lineChart.setMarker(new MyChartView(getContext(),R.layout.chart,values));
//刷新图表
lineChart.notifyDataSetChanged();
lineChart.invalidate();
}
}