feat: SP7功能开发

This commit is contained in:
xiaoyan 2023-07-13 16:14:25 +08:00
parent b329f9dc54
commit b9bb75063b
14 changed files with 433 additions and 249 deletions

View File

@ -37,8 +37,8 @@ android {
applicationId "com.navinfo.outdoor" applicationId "com.navinfo.outdoor"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 30 targetSdkVersion 30
versionCode 104 versionCode 106
versionName "8.230619-正式版-OCR" versionName "8.230713-正式版-OCR"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk { ndk {

View File

@ -387,6 +387,7 @@ public class HomeActivity extends BaseActivity {
ArrayList<String> toAddressList = new ArrayList<>(); ArrayList<String> toAddressList = new ArrayList<>();
toAddressList.add("xiaoyan159@qq.com"); toAddressList.add("xiaoyan159@qq.com");
toAddressList.add("huangjichao@navinfo.com"); toAddressList.add("huangjichao@navinfo.com");
toAddressList.add("ZhouQi@navinfo.com");
mail.setToAddress(toAddressList); mail.setToAddress(toAddressList);
mail.setSubject("疑似违规记录"); mail.setSubject("疑似违规记录");
mail.setContent(stringBuilder.append("用户名:").append(Constant.USER_NAME).append("\n") mail.setContent(stringBuilder.append("用户名:").append(Constant.USER_NAME).append("\n")

View File

@ -79,6 +79,26 @@ public class StaySubmitAdapter extends RecyclerView.Adapter<StaySubmitAdapter.Vi
}).start(); }).start();
} }
/**
* 设置所有的勾选数据的当前状态
* */
public void setAllWorkType(int workType) {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (allRoad) {
for (PoiEntity poiEntity : allRoad) {
if (poiEntity.isChecked()) {
poiEntity.setWork_type(workType);
}
PoiDatabase.getInstance(context).getPoiDao().updatePoiEntity(poiEntity);
}
handler.sendEmptyMessage(0x105);
}
}
}).start();
}
//全选 //全选
public void setAllDataChecked(boolean isChecked) { public void setAllDataChecked(boolean isChecked) {
for (PoiEntity entity : this.allRoad) { for (PoiEntity entity : this.allRoad) {
@ -152,7 +172,7 @@ public class StaySubmitAdapter extends RecyclerView.Adapter<StaySubmitAdapter.Vi
} }
}); });
// 显示进度 // 显示进度
if (poiEntity.getUploadMax()>0&&poiEntity.getUploadProgress()!=poiEntity.getUploadMax()) { if (poiEntity.getWork_type()!=0&&poiEntity.getUploadMax()>0&&poiEntity.getUploadProgress()!=poiEntity.getUploadMax()) {
holder.layerProgress.setVisibility(View.VISIBLE); holder.layerProgress.setVisibility(View.VISIBLE);
holder.pbUpload.setMax(poiEntity.getUploadMax()); holder.pbUpload.setMax(poiEntity.getUploadMax());
holder.pbUpload.setProgress(poiEntity.getUploadProgress()); holder.pbUpload.setProgress(poiEntity.getUploadProgress());

View File

@ -725,7 +725,7 @@ public class AreaHubFragment extends BaseDrawerFragment implements View.OnClickL
} }
// 更新当前POI的置信度 // 更新当前POI的置信度
showPoiEntity.setCredible(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0)); showPoiEntity.setScore(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0));
} }
} }
} }

View File

@ -826,7 +826,7 @@ public class BuildingInFragment extends BaseDrawerFragment implements View.OnCli
} }
// 更新当前POI的置信度 // 更新当前POI的置信度
showPoiEntity.setCredible(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0)); showPoiEntity.setScore(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0));
} }
} }
} }

View File

@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -16,6 +17,7 @@ import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import com.github.lazylibrary.util.FileUtils; import com.github.lazylibrary.util.FileUtils;
import com.github.lazylibrary.util.ToastUtils;
import com.kongzue.dialog.interfaces.OnDialogButtonClickListener; import com.kongzue.dialog.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialog.util.BaseDialog; import com.kongzue.dialog.util.BaseDialog;
import com.kongzue.dialog.util.DialogSettings; import com.kongzue.dialog.util.DialogSettings;
@ -48,10 +50,6 @@ import com.navinfo.outdoor.util.GeometryTools;
import com.navinfo.outdoor.util.LocationLifeCycle; import com.navinfo.outdoor.util.LocationLifeCycle;
import com.navinfo.outdoor.util.NaviUtils; import com.navinfo.outdoor.util.NaviUtils;
import com.navinfo.outdoor.util.TimestampUtil; import com.navinfo.outdoor.util.TimestampUtil;
import com.navinfo.outdoor.util.ToastUtils;
import com.tencent.lbssearch.httpresponse.Poi;
import com.tencent.map.navi.car.TencentCarNaviManager;
import com.tencent.map.navi.data.NaviPoi;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng; import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
@ -362,7 +360,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
LatLng endLatLng = new LatLng(Double.parseDouble(poiEntity.getY()), Double.parseDouble(poiEntity.getX())); LatLng endLatLng = new LatLng(Double.parseDouble(poiEntity.getY()), Double.parseDouble(poiEntity.getX()));
double geometry = GeometryTools.distanceToDouble(startLatLng, endLatLng); double geometry = GeometryTools.distanceToDouble(startLatLng, endLatLng);
if (geometry > 5000) { if (geometry > 5000) {
ToastUtils.Message(getActivity(),"作业不在领取范围内,无法采集"); ToastUtils.showToast(getActivity(),"作业不在领取范围内,无法采集");
return; return;
} else { } else {
if (geometry > 50) { if (geometry > 50) {
@ -540,7 +538,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
} else if (response.getCode() == 230) { } else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity()); FlushTokenUtil.flushToken(getActivity());
} else { } else {
ToastUtils.Message(getActivity(),response.getMessage()); ToastUtils.showToast(getActivity(),response.getMessage());
} }
} }
@ -550,9 +548,9 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
Log.d("TAG", "onError: " + e.getMessage()); Log.d("TAG", "onError: " + e.getMessage());
} }
@ -564,85 +562,95 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
*/ */
private void initPolygonTask(String url, PoiEntity poiEntity, boolean aBoolean) { private void initPolygonTask(String url, PoiEntity poiEntity, boolean aBoolean) {
if (poiEntity.getTaskId() == 0) { if (poiEntity.getTaskId() == 0) {
ToastUtils.Message(getActivity(),"无此任务"); ToastUtils.showToast(getActivity(),"无此任务");
return; return;
} }
// 如果当前存在未关闭的面状任务提示用户无法领取先关闭已领取的面状任务 // 如果当前存在未关闭的面状任务提示用户无法领取先关闭已领取的面状任务
List<PoiEntity> recivePolygonPoi = PoiDatabase.getInstance(requireContext()).getPoiDao().getPoiEntityByTaskStatus(1, 6); new Thread(new Runnable() {
if (recivePolygonPoi!=null&&!recivePolygonPoi.isEmpty()) { @Override
ToastUtils.Message(requireActivity(),"您当前存在已领取的其他面状任务,请先关闭该任务后再领取!"); public void run() {
return; List<PoiEntity> recivePolygonPoi = PoiDatabase.getInstance(requireContext()).getPoiDao().getPoiEntityByTaskStatus(1, 6);
} requireActivity().runOnUiThread(new Runnable() {
showLoadingDialog();
OkGoBuilder.getInstance()
.time(30)
.Builder(getActivity())
.url(url + "/" + poiEntity.getTaskId())
.cls(PolygonTaskBean.class)
.token(Constant.ACCESS_TOKEN)
.params(new HttpParams())
.getRequest(new Callback<PolygonTaskBean>() {
@Override @Override
public void onSuccess(PolygonTaskBean response, int id) { public void run() {
dismissLoadingDialog(); if (recivePolygonPoi!=null&&!recivePolygonPoi.isEmpty()) {
if (response.getCode() == 200) {// 0.未领取 1.已领取2.未保存(保存到本地但未提交成功),3.已保存(保存到本地提交成功)4已上传结束采集, ToastUtils.showToast(requireActivity(),"您当前存在已领取的其他面状任务,请先关闭该任务后再领取!");
PolygonTaskBean.BodyBean listBean = response.getBody(); return;
PoiEntity polygonEntity = new PoiEntity(); }
if (listBean != null) {
polygonEntity.setTaskId(listBean.getId()); showLoadingDialog();
polygonEntity.setName(listBean.getName()); OkGoBuilder.getInstance()
polygonEntity.setType(listBean.getType()); .time(30)
polygonEntity.setGeoWkt(listBean.getGeo()); .Builder(getActivity())
String encodeStr = listBean.getGeo(); .url(url + "/" + poiEntity.getTaskId())
String geo = Geohash.getInstance().decode(encodeStr); .cls(PolygonTaskBean.class)
// 生成对应的x和y poiEntity.setX .token(Constant.ACCESS_TOKEN)
GeometryTools.obitainPoiEntityXY(geo, polygonEntity); .params(new HttpParams())
polygonEntity.setTaskStatus(1); .getRequest(new Callback<PolygonTaskBean>() {
} @Override
new Thread(new Runnable() { public void onSuccess(PolygonTaskBean response, int id) {
@Override dismissLoadingDialog();
public void run() { if (response.getCode() == 200) {// 0.未领取 1.已领取2.未保存(保存到本地但未提交成功),3.已保存(保存到本地提交成功)4已上传结束采集,
InsertAndUpdateUtils.getInstance().insertOrUpdate(getContext(), polygonEntity); PolygonTaskBean.BodyBean listBean = response.getBody();
if (getActivity() != null) { PoiEntity polygonEntity = new PoiEntity();
getActivity().runOnUiThread(new Runnable() { if (listBean != null) {
@Override polygonEntity.setTaskId(listBean.getId());
public void run() { polygonEntity.setName(listBean.getName());
initViewByTaskStatus(1); polygonEntity.setType(listBean.getType());
ToastUtils.Message(getActivity(),"领取成功"); polygonEntity.setGeoWkt(listBean.getGeo());
if (aBoolean) { String encodeStr = listBean.getGeo();
initCompleteTask(HttpInterface.SUBMIT_POLYGON_TASK, polygonEntity); String geo = Geohash.getInstance().decode(encodeStr);
} else { // 生成对应的x和y poiEntity.setX
Message obtains = Message.obtain(); GeometryTools.obitainPoiEntityXY(geo, polygonEntity);
obtains.what = Constant.JOB_WORD_MONITOR; polygonEntity.setTaskStatus(1);
obtains.obj = true;
EventBus.getDefault().post(obtains);
}
} }
}); new Thread(new Runnable() {
@Override
public void run() {
InsertAndUpdateUtils.getInstance().insertOrUpdate(getContext(), polygonEntity);
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
initViewByTaskStatus(1);
ToastUtils.showToast(getActivity(),"领取成功");
if (aBoolean) {
initCompleteTask(HttpInterface.SUBMIT_POLYGON_TASK, polygonEntity);
} else {
Message obtains = Message.obtain();
obtains.what = Constant.JOB_WORD_MONITOR;
obtains.obj = true;
EventBus.getDefault().post(obtains);
}
}
});
}
}
}).start();
} else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity());
} else {
ToastUtils.showToast(getActivity(),response.getMessage());
}
} }
}
}).start();
} else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity());
} else {
ToastUtils.Message(getActivity(),response.getMessage());
}
}
@Override @Override
public void onError(Throwable e, int id) { public void onError(Throwable e, int id) {
dismissLoadingDialog(); dismissLoadingDialog();
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
Log.d("TAG", "onError: " + e.getMessage()); Log.d("TAG", "onError: " + e.getMessage());
}
});
} }
}); });
}
}).start();
} }
/* /*
@ -651,7 +659,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
*/ */
private void initEndReceiveTask(String url, PoiEntity poiEntity) { private void initEndReceiveTask(String url, PoiEntity poiEntity) {
if (poiEntity.getTaskId() == 0) { if (poiEntity.getTaskId() == 0) {
ToastUtils.Message(getActivity(),"无此任务"); ToastUtils.showToast(getActivity(),"无此任务");
return; return;
} }
showLoadingDialog(); showLoadingDialog();
@ -695,7 +703,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
} else if (response.getCode() == 230) { } else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity()); FlushTokenUtil.flushToken(getActivity());
} else { } else {
ToastUtils.Message(getActivity(),response.getMessage()); ToastUtils.showToast(getActivity(),response.getMessage());
} }
} }
@ -705,9 +713,9 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
} }
}); });
@ -718,7 +726,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
*/ */
private void initCompleteTask(String url, PoiEntity poiEntity) { private void initCompleteTask(String url, PoiEntity poiEntity) {
if (poiEntity.getTaskId() == 0) { if (poiEntity.getTaskId() == 0) {
ToastUtils.Message(getActivity(),"无此任务"); ToastUtils.showToast(getActivity(),"无此任务");
return; return;
} }
showLoadingDialog(); showLoadingDialog();
@ -762,7 +770,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
} else if (response.getCode() == 230) { } else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity()); FlushTokenUtil.flushToken(getActivity());
} else { } else {
ToastUtils.Message(getActivity(),response.getMessage()); ToastUtils.showToast(getActivity(),response.getMessage());
} }
} }
@ -772,9 +780,9 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
} }
}); });
@ -785,7 +793,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
*/ */
private void initSubmitPolygonTask(String url, PoiEntity poiEntity) { private void initSubmitPolygonTask(String url, PoiEntity poiEntity) {
if (poiEntity.getTaskId() == 0) { if (poiEntity.getTaskId() == 0) {
ToastUtils.Message(getActivity(),"无此任务"); ToastUtils.showToast(getActivity(),"无此任务");
return; return;
} }
HttpParams httpParams = new HttpParams(); HttpParams httpParams = new HttpParams();
@ -820,7 +828,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
dismissLoadingDialog(); dismissLoadingDialog();
if (response.getCode() == 200) { if (response.getCode() == 200) {
ToastUtils.Message(getActivity(), "结束采集成功!"); ToastUtils.showToast(getActivity(), "结束采集成功!");
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -841,7 +849,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
} else if (response.getCode() == 230) { } else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity()); FlushTokenUtil.flushToken(getActivity());
} else { } else {
ToastUtils.Message(getActivity(),response.getMessage()); ToastUtils.showToast(getActivity(),response.getMessage());
} }
} }
@ -851,9 +859,9 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
} }
}); });
@ -864,7 +872,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
*/ */
private void receivedTaskByNet(String url, PoiEntity poiEntity, boolean isSaver, int statusId) { private void receivedTaskByNet(String url, PoiEntity poiEntity, boolean isSaver, int statusId) {
if (poiEntity.getTaskId() == 0) { if (poiEntity.getTaskId() == 0) {
ToastUtils.Message(getActivity(),"无此任务"); ToastUtils.showToast(getActivity(),"无此任务");
return; return;
} }
showLoadingDialog(); showLoadingDialog();
@ -959,7 +967,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
} else if (response.getCode() == 230) { } else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity()); FlushTokenUtil.flushToken(getActivity());
} else { } else {
ToastUtils.Message(getActivity(),response.getMessage()); ToastUtils.showToast(getActivity(),response.getMessage());
} }
} }
@ -969,9 +977,9 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
} }
}); });
@ -1077,7 +1085,7 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
} else if (response.getCode() == 230) { } else if (response.getCode() == 230) {
FlushTokenUtil.flushToken(getActivity()); FlushTokenUtil.flushToken(getActivity());
} else { } else {
ToastUtils.Message(getActivity(),response.getMessage()); ToastUtils.showToast(getActivity(),response.getMessage());
} }
dismissLoadingDialog(); dismissLoadingDialog();
} }
@ -1088,9 +1096,9 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe
String message = e.getMessage(); String message = e.getMessage();
assert message != null; assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) { if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(getActivity(),"请求超时"); ToastUtils.showToast(getActivity(),"请求超时");
} else { } else {
ToastUtils.Message(getActivity(),message); ToastUtils.showToast(getActivity(),message);
} }
} }
}); });

View File

@ -729,7 +729,7 @@ public class PoiVideoFragment extends BaseDrawerFragment implements View.OnClick
} }
// 更新当前POI的置信度 // 更新当前POI的置信度
showPoiEntity.setCredible(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0)); showPoiEntity.setScore(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0));
} }
} }
} }

View File

@ -640,23 +640,20 @@ public class RoadFragment extends BaseDrawerFragment implements View.OnClickList
ToastUtils.Message(getActivity(), poiCheckResult.getMsg()); ToastUtils.Message(getActivity(), poiCheckResult.getMsg());
return; return;
} }
poiEntity.setTaskStatus(2); if (existence == 0) {
new Thread(new Runnable() { DataSaveUtils.checkRoadPoiPicture(showPoiEntity, (List<File>) fmRoadPic.getTag(), new DataSaveUtils.RoadPercentCheckCallback() {
@Override @Override
public void run() { public void callback(double percent) {
InsertAndUpdateUtils.getInstance().insertOrUpdate(getContext(), poiEntity); if (percent<=0.1) {
requireActivity().runOnUiThread(new Runnable() { ToastUtils.Message(getActivity(), "手动拍摄的道路任务覆盖度小于10%时,不能选择‘道路正常开通’");
@Override return;
public void run() {
if (isLocal) {
roadSaveBetWork(poiEntity);
} else {
roadSaveWork(poiEntity);
}
} }
}); doSaveRoadData(poiEntity, isLocal);
} }
}).start(); });
} else {
doSaveRoadData(poiEntity, isLocal);
}
} else { } else {
ToastUtils.Message(getActivity(), "没有申请权限,请手动申请"); ToastUtils.Message(getActivity(), "没有申请权限,请手动申请");
} }
@ -673,6 +670,26 @@ public class RoadFragment extends BaseDrawerFragment implements View.OnClickList
}); });
} }
private void doSaveRoadData(PoiEntity poiEntity, boolean isLocal) {
poiEntity.setTaskStatus(2);
new Thread(new Runnable() {
@Override
public void run() {
InsertAndUpdateUtils.getInstance().insertOrUpdate(getContext(), poiEntity);
requireActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isLocal) {
roadSaveBetWork(poiEntity);
} else {
roadSaveWork(poiEntity);
}
}
});
}
}).start();
}
private void roadSaveWork(PoiEntity poiEntity) { private void roadSaveWork(PoiEntity poiEntity) {
HttpParams httpParams = new HttpParams(); HttpParams httpParams = new HttpParams();
httpParams.put("taskId", poiEntity.getTaskId()); httpParams.put("taskId", poiEntity.getTaskId());
@ -729,7 +746,7 @@ public class RoadFragment extends BaseDrawerFragment implements View.OnClickList
@Override @Override
public void onError() { public void onError() {
Constant.isPresent = true;
} }
}); });
} else { } else {
@ -986,6 +1003,7 @@ public class RoadFragment extends BaseDrawerFragment implements View.OnClickList
poiEntity.setCreateTime(format); poiEntity.setCreateTime(format);
poiEntity.setType(4); poiEntity.setType(4);
poiEntity.setChecked(false); poiEntity.setChecked(false);
poiEntity.setExistence(existence);
if (showPoiEntity.getId() != null) { if (showPoiEntity.getId() != null) {
List<File> fileListByUUID = AWMp4ParserHelper.getInstance().getFileListByUUID(showPoiEntity.getId()); List<File> fileListByUUID = AWMp4ParserHelper.getInstance().getFileListByUUID(showPoiEntity.getId());
if (fileListByUUID != null) { if (fileListByUUID != null) {

View File

@ -115,6 +115,8 @@ public class StaySubmitFragment extends BaseFragment implements View.OnClickList
Button btnStaySubmit = findViewById(R.id.btn_stay_submit); Button btnStaySubmit = findViewById(R.id.btn_stay_submit);
tvNumber = findViewById(R.id.tv_number); tvNumber = findViewById(R.id.tv_number);
btnStaySubmit.setOnClickListener(this); btnStaySubmit.setOnClickListener(this);
Button btnStayCancel = findViewById(R.id.btn_stay_cancel);
btnStayCancel.setOnClickListener(this);
RecyclerView stayXrv = findViewById(R.id.stay_xrv); RecyclerView stayXrv = findViewById(R.id.stay_xrv);
stayXrv.setLayoutManager(new LinearLayoutManager(getActivity())); stayXrv.setLayoutManager(new LinearLayoutManager(getActivity()));
stayXrv.addItemDecoration(new DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)); stayXrv.addItemDecoration(new DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL));
@ -363,6 +365,14 @@ public class StaySubmitFragment extends BaseFragment implements View.OnClickList
ToastUtils.Message(getActivity(), "有正在提交的数据,等提交成功后,方可操作"); ToastUtils.Message(getActivity(), "有正在提交的数据,等提交成功后,方可操作");
} }
break; break;
case R.id.btn_stay_cancel:
// 用户点击取消上传
PoiSaveUtils.getInstance(requireActivity()).cancelUploadPoiEntityBatch();
// 数据上传取消后重置上传状态
staySubmitAdapter.setAllWorkType(0);
// 设置当前没有正在上传的数据
Constant.isPresent = true;
break;
} }
} }

View File

@ -725,7 +725,7 @@ public class TrafficHubFragment extends BaseDrawerFragment implements View.OnCli
} }
// 更新当前POI的置信度 // 更新当前POI的置信度
showPoiEntity.setCredible(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0)); showPoiEntity.setScore(data.getIntExtra(Constant.INTENT_PICTURES_CREDIBLE, 0));
} }
} }
} }

View File

@ -53,7 +53,7 @@ public class PoiEntity implements Serializable {
private int record_way; //等同于 canReceived : 1是可领取 0是不可领取 private int record_way; //等同于 canReceived : 1是可领取 0是不可领取
private int uploadProgress; // 上传进度 private int uploadProgress; // 上传进度
private int uploadMax; // 上传数据总量-这里一般使用需要上传的文件数量作为总数因此上传进度为已上传的文件数 private int uploadMax; // 上传数据总量-这里一般使用需要上传的文件数量作为总数因此上传进度为已上传的文件数
private int credible; // 置信度 private int score; // 置信度
private String drawLine; // 用户绘制的线型 private String drawLine; // 用户绘制的线型
private String uploadResult; //上传结果 private String uploadResult; //上传结果
@ -302,12 +302,12 @@ public class PoiEntity implements Serializable {
this.uploadMax = uploadMax; this.uploadMax = uploadMax;
} }
public int getCredible() { public int getScore() {
return credible; return score;
} }
public void setCredible(int credible) { public void setScore(int score) {
this.credible = credible; this.score = score;
} }
public String getDrawLine() { public String getDrawLine() {

View File

@ -2,11 +2,14 @@ package com.navinfo.outdoor.util;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import com.elvishew.xlog.Logger;
import com.elvishew.xlog.XLog; import com.elvishew.xlog.XLog;
import com.github.lazylibrary.util.FileUtils; import com.github.lazylibrary.util.FileUtils;
import com.github.lazylibrary.util.MD5; import com.github.lazylibrary.util.MD5;
@ -19,27 +22,38 @@ import com.kongzue.dialog.v3.WaitDialog;
import com.lzy.okgo.OkGo; import com.lzy.okgo.OkGo;
import com.lzy.okgo.model.HttpParams; import com.lzy.okgo.model.HttpParams;
import com.lzy.okgo.model.Response; import com.lzy.okgo.model.Response;
import com.navinfo.outdoor.activity.PicturesActivity;
import com.navinfo.outdoor.api.Constant; import com.navinfo.outdoor.api.Constant;
import com.navinfo.outdoor.api.UserApplication; import com.navinfo.outdoor.api.UserApplication;
import com.navinfo.outdoor.bean.CommonRequestSend; import com.navinfo.outdoor.bean.CommonRequestSend;
import com.navinfo.outdoor.bean.CommonResponse; import com.navinfo.outdoor.bean.CommonResponse;
import com.navinfo.outdoor.bean.LocationRecorder;
import com.navinfo.outdoor.bean.PoiSaveBean; import com.navinfo.outdoor.bean.PoiSaveBean;
import com.navinfo.outdoor.http.Callback; import com.navinfo.outdoor.http.Callback;
import com.navinfo.outdoor.http.DialogCallback; import com.navinfo.outdoor.http.DialogCallback;
import com.navinfo.outdoor.http.HttpInterface; import com.navinfo.outdoor.http.HttpInterface;
import com.navinfo.outdoor.http.OkGoBuilder; import com.navinfo.outdoor.http.OkGoBuilder;
import com.navinfo.outdoor.room.InsertAndUpdateUtils; import com.navinfo.outdoor.room.InsertAndUpdateUtils;
import com.navinfo.outdoor.room.LocationRecorderDao;
import com.navinfo.outdoor.room.PoiDatabase; import com.navinfo.outdoor.room.PoiDatabase;
import com.navinfo.outdoor.room.PoiEntity; import com.navinfo.outdoor.room.PoiEntity;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import com.umeng.commonsdk.debug.UMLog; import com.umeng.commonsdk.debug.UMLog;
import com.umeng.umcrash.UMCrash; import com.umeng.umcrash.UMCrash;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -60,10 +74,12 @@ import io.reactivex.schedulers.Schedulers;
public class DataSaveUtils { public class DataSaveUtils {
private static DataSaveUtils instance; private static DataSaveUtils instance;
private static Logger logger;
public static DataSaveUtils getInstance() { public static DataSaveUtils getInstance() {
if (instance == null) { if (instance == null) {
instance = new DataSaveUtils(); instance = new DataSaveUtils();
logger = XLogUtils.Companion.getInstance().getUploadLogWriter();
} }
return instance; return instance;
} }
@ -82,6 +98,9 @@ public class DataSaveUtils {
@Override @Override
public void subscribe(ObservableEmitter<File> emitter) throws Exception { public void subscribe(ObservableEmitter<File> emitter) throws Exception {
if (!zipFile.exists()) { if (!zipFile.exists()) {
// 首先检查图片中是否存在已损坏的图片
List<File> corruptImage = filterCorruptImages(poiPicList);
logger.d("存在损坏的照片:"+poiEntity.getId()+":"+poiEntity.getName()+list2Str(corruptImage));
// 开始压缩文件 // 开始压缩文件
ZipUtil.zipFiles(poiPicList, zipFile, "", null); ZipUtil.zipFiles(poiPicList, zipFile, "", null);
} }
@ -396,4 +415,69 @@ public class DataSaveUtils {
} }
return result.toString(); return result.toString();
} }
private List<File> filterCorruptImages(List<File> files) {
List<File> corruptImage = new ArrayList<>();
Iterator<File> iterator = files.iterator();
while (iterator.hasNext()) {
File file = iterator.next();
if (file.length()==0) {
corruptImage.add(file);
iterator.remove();
continue;
}
try {
Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
if (bitmap == null) {
corruptImage.add(file);
iterator.remove();
}
} catch (Exception e) {
corruptImage.add(file);
iterator.remove();
}
}
return corruptImage;
}
/**
* 检查道路POI的照片数据轨迹与道路任务长度比率必须大于0.1
* */
public static void checkRoadPoiPicture(PoiEntity poiEntity, List<File> fileList, RoadPercentCheckCallback callback) {
new Thread(new Runnable() {
@Override
public void run() {
double lengthPercent = 0.0;
// 获取任务数据长度
String geoWkt = poiEntity.getGeoWkt();
if (geoWkt!=null) {
String geoDecode = Geohash.getInstance().decode(geoWkt);
Geometry originGeometry = GeometryTools.createGeometry(geoDecode);
// 获取轨迹对应的geometry
if (fileList!=null&&!fileList.isEmpty()) {
File txtFile = new File(fileList.get(0).getParentFile(), "paper.txt");
// 读取第一条数据和最后一条数据获取时间然后根据数据查询轨迹数据
List<String> txtStringList = FileUtils.readFileToList(txtFile.getAbsolutePath(), "utf-8");
// 读取位置信息
List<LatLng> latLngList = new ArrayList<>(txtStringList.size());
for (String line: txtStringList) {
String[] itemArray = line.split(",");
// 获取数据的经纬度
latLngList.add(new LatLng(Double.parseDouble(itemArray[2]), Double.parseDouble(itemArray[3])));
}
// 构建轨迹的geometry
LineString trackLine = GeometryTools.getLineStainGeo(latLngList);
lengthPercent = trackLine.getLength()/originGeometry.getLength();
}
}
callback.callback(lengthPercent);
}
}).start();
}
public interface RoadPercentCheckCallback{
void callback(double percent);
}
} }

View File

@ -3,6 +3,7 @@ package com.navinfo.outdoor.util;
import android.app.Activity; import android.app.Activity;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import com.elvishew.xlog.Logger; import com.elvishew.xlog.Logger;
import com.github.lazylibrary.util.FileUtils; import com.github.lazylibrary.util.FileUtils;
@ -55,6 +56,7 @@ public class PoiSaveUtils {
private int bInt = 0; // 上传失败的个数 private int bInt = 0; // 上传失败的个数
private int uploadCount = 0; // 上传的总个数 private int uploadCount = 0; // 上传的总个数
private Logger logger = XLogUtils.Companion.getInstance().getUploadLogWriter(); private Logger logger = XLogUtils.Companion.getInstance().getUploadLogWriter();
private Disposable mDisposable;// Observeable取消订阅的对象
public static PoiSaveUtils getInstance(Activity mContext) { public static PoiSaveUtils getInstance(Activity mContext) {
if (instance == null) { if (instance == null) {
@ -198,6 +200,7 @@ public class PoiSaveUtils {
uploadCount = chargePoiEntityList.size()+spliteFilePoiEntityList.size()+otherPoiEntityList.size(); uploadCount = chargePoiEntityList.size()+spliteFilePoiEntityList.size()+otherPoiEntityList.size();
Log.d("PoiSaveUtils", "开始上传"); Log.d("PoiSaveUtils", "开始上传");
ToastUtils.showToast(mContext, "开始批量上传数据,本次共需上传"+uploadCount+"条数据"); ToastUtils.showToast(mContext, "开始批量上传数据,本次共需上传"+uploadCount+"条数据");
mDisposable = d;
} }
@Override @Override
@ -287,6 +290,8 @@ public class PoiSaveUtils {
httpParams.put("address", poiEntity.getAddress()); httpParams.put("address", poiEntity.getAddress());
httpParams.put("workType", 1); httpParams.put("workType", 1);
httpParams.put("memo", poiEntity.getMemo()); httpParams.put("memo", poiEntity.getMemo());
httpParams.put("score", poiEntity.getScore());
httpParams.put("drawLine", poiEntity.getDrawLine());
url = HttpInterface.INSIDE_API_LIST; url = HttpInterface.INSIDE_API_LIST;
} else if (poiEntity.getType() == 4) { } else if (poiEntity.getType() == 4) {
httpParams.put("taskId", poiEntity.getTaskId()); httpParams.put("taskId", poiEntity.getTaskId());
@ -705,4 +710,14 @@ public class PoiSaveUtils {
} }
return isExistsPic; return isExistsPic;
} }
public void cancelUploadPoiEntityBatch() {
if (mDisposable!=null&&!mDisposable.isDisposed()) {
mDisposable.dispose();
Toast.makeText(mContext, "已取消批量上传流程", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "没有需要取消的批量上传数据", Toast.LENGTH_SHORT).show();
}
Constant.submitIdSet.clear(); // 清空记录的正在上传的id表
}
} }

View File

@ -1,140 +1,168 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
tools:context=".fragment.StaySubmitFragment"> <LinearLayout
android:id="@+id/layer_operate"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_stay_type"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/road_shape"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
style="@style/text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_marginBottom="5dp"
android:text="类型"
android:textColor="#333"
app:layout_constraintBottom_toTopOf="@+id/tv_stay_type"
app:layout_constraintStart_toStartOf="@+id/tv_stay_type"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_stay_type"
style="@style/main_about_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginBottom="20dp"
android:text="全部"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:background="@drawable/ic_baseline_arrow_forward"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<RelativeLayout
android:id="@+id/ll_results"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/road_shape"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cl_stay_type">
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="筛选结果"
android:textColor="#333"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:text="全选"
android:textColor="#333"
android:textSize="17sp" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/stay_xrv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_results" />
<LinearLayout
android:id="@+id/ll_del"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/stay_xrv">
<CheckBox
android:id="@+id/cb_select"
style="@style/CheckBoxTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="全选"
android:textSize="17sp" />
<TextView
android:id="@+id/tv_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="删除"
android:textColor="@color/colorPrimaryBlue"
android:textSize="18sp" />
</LinearLayout>
<Button <Button
android:id="@+id/btn_stay_submit" android:id="@+id/btn_stay_submit"
style="@style/user_data_style" style="@style/user_data_style"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="20dp" android:layout_margin="20dp"
android:text="提交" android:text="提交"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_del" /> app:layout_constraintTop_toBottomOf="@+id/ll_del" />
<Button
android:id="@+id/btn_stay_cancel"
style="@style/user_data_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="20dp"
android:text="取消"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_del" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> <androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/layer_operate"
app:layout_constraintTop_toTopOf="parent"
tools:context=".fragment.StaySubmitFragment">
</androidx.core.widget.NestedScrollView> <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_stay_type"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/road_shape"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
style="@style/text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_marginBottom="5dp"
android:text="类型"
android:textColor="#333"
app:layout_constraintBottom_toTopOf="@+id/tv_stay_type"
app:layout_constraintStart_toStartOf="@+id/tv_stay_type"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_stay_type"
style="@style/main_about_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginBottom="20dp"
android:text="全部"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:background="@drawable/ic_baseline_arrow_forward"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<RelativeLayout
android:id="@+id/ll_results"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/road_shape"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cl_stay_type">
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="筛选结果"
android:textColor="#333"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:text="全选"
android:textColor="#333"
android:textSize="17sp" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/stay_xrv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_results" />
<LinearLayout
android:id="@+id/ll_del"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/stay_xrv">
<CheckBox
android:id="@+id/cb_select"
style="@style/CheckBoxTheme"
android:padding="@dimen/default_widget_padding"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="全选"
android:textSize="17sp" />
<TextView
android:id="@+id/tv_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="@dimen/default_widget_padding"
android:text="删除"
android:textColor="@color/colorPrimaryBlue"
android:textSize="18sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>