Commit f8cd3366 authored by 姜天宇's avatar 姜天宇

feat(v1.0.2): 1.增加【清空商品数据】、【SN解绑】、【下载远程工具】、【检查更新】功能

parent 43c3bc9e
......@@ -84,4 +84,6 @@ dependencies {
// 抽屉
api 'androidx.drawerlayout:drawerlayout:1.2.0'
api 'com.github.jenly1314.AppUpdater:app-updater:1.2.0'
}
\ No newline at end of file
......@@ -96,10 +96,6 @@ public abstract class BaseActivity extends AppCompatActivity {
finishAndRemoveTask();
}
@Override
public void onCancel() {
}
}).setTitle(getString(R.string.prompt)).setContent(getString(R.string.please_confirm_whether_quit));
popupWindow.showWindow();
}
......
......@@ -79,9 +79,9 @@ public class SecondConfirmWindow extends BasePopupWindow {
// 取消按钮
tvCancel.setOnClickListener(v -> {
dismissWindow();
if (clickListener != null){
/*if (clickListener != null){
clickListener.onCancel();
}
}*/
});
// 确认按钮
tvConfirm.setOnClickListener(v -> {
......@@ -97,7 +97,5 @@ public class SecondConfirmWindow extends BasePopupWindow {
* 点击确认按钮回调
*/
void onConfirm();
void onCancel();
}
}
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 背景 gradient是渐变,corners定义的是圆角 -->
<item android:id="@android:id/background">
<shape>
<corners android:radius="10dp" />
<solid android:color="#E5E5E5" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="10dp" />
<solid android:color="@color/green_479e85" />
</shape>
</clip>
</item>
</layer-list>
\ No newline at end of file
......@@ -78,4 +78,8 @@
<string name="unknown_product">未知商品</string>
<string name="save_success">保存成功</string>
<string name="title_download_remote_tool">下载远程工具</string>
<string name="confirm_download_remote_tool">请确认是否下载远程工具</string>
<string name="upgrade_progress">下载进度:</string>
</resources>
\ No newline at end of file
......@@ -9,6 +9,8 @@ import com.wmdigit.data.database.entity.ProductsPO;
import java.util.List;
import retrofit2.http.DELETE;
/**
* 商品DAO
* @author dizi
......@@ -63,4 +65,11 @@ public interface ProductsDao {
@Query("SELECT * FROM Products WHERE productCode = :productCode")
ProductsPO getByProductCode(String productCode);
/**
* 删除全部
* @return
*/
@Query("DELETE FROM Products")
int deleteAll();
}
......@@ -91,4 +91,11 @@ public class ProductsRepository {
public ProductsPO queryByProductCode(String productCode){
return getProductsDao().getByProductCode(productCode);
}
/**
* 删除全部
*/
public void deleteAll(){
getProductsDao().deleteAll();
}
}
......@@ -39,11 +39,14 @@ public class DiskRepository {
Context context = LocalDataModule.getAppContext();
// 识别记录根目录
String identifyRecordsRootPath = context.getExternalFilesDir("IdentifyRecords").getAbsolutePath();
// 商品的学习记录根目录
String productLearningRecordsRootPath = context.getExternalFilesDir("ProductLearningRecords").getAbsolutePath();
String imageFilename = UUID.randomUUID().toString() + ".jpg";
// 保存图片
BitmapUtils.saveBitmap(bitmap, identifyRecordsRootPath + "/" + imageFilename);
if (rectArray == null || products == null){
return identifyRecordsRootPath + "/" + imageFilename;
}
// 商品的学习记录根目录
String productLearningRecordsRootPath = context.getExternalFilesDir("ProductLearningRecords").getAbsolutePath();
// 根据框的坐标,拆分原图
for (int i = 0; i < rectArray.length; i++) {
if (products.get(i) == null || TextUtils.isEmpty(products.get(i).getProductCode())){
......
......@@ -115,4 +115,23 @@ public class UserLocalRepository {
return MMKV.defaultMMKV().getString(MmkvCons.MMKV_KEY_DEVICE_ID, "");
}
/**
* 清除用户相关设备信息和认证状态
* 此方法用于重置应用程序的设备和用户配置,将MMKV中存储的与设备和用户相关的数据清除
* 主要用于用户登出或其他需要清除用户设备信息的场景
*/
public void clearUser(){
// 将设备激活状态重置为未激活
MMKV.defaultMMKV().putBoolean(MmkvCons.MMKV_KEY_ACTIVATION, false);
// 清除设备ID
MMKV.defaultMMKV().putString(MmkvCons.MMKV_KEY_DEVICE_ID, "");
// 清除设备商店代码
MMKV.defaultMMKV().putString(MmkvCons.MMKV_KEY_STORE_CODE, "");
// 清除设备代码
MMKV.defaultMMKV().putString(MmkvCons.MMKV_KEY_DEVICE_CODE, "");
// 清除序列号代码
MMKV.defaultMMKV().putString(MmkvCons.MMKV_KEY_SN_CODE, "");
// 清除租户信息
MMKV.defaultMMKV().putString(MmkvCons.MMKV_KEY_TENANT, "");
}
}
......@@ -16,11 +16,13 @@ android {
buildTypes {
debug {
buildConfigField 'String', 'POS_URL', '"https://se.wmdigit.com/"'
buildConfigField 'String', 'VERSION_CODE', '"1000200"'
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
buildConfigField 'String', 'POS_URL', '"https://se.wmdigit.com/"'
buildConfigField 'String', 'VERSION_CODE', '"1000200"'
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
......
......@@ -9,6 +9,12 @@ public class QueryLatestAppVersionParam {
private String version;
private String osVersion;
public QueryLatestAppVersionParam(String type, String version, String osVersion) {
this.type = type;
this.version = version;
this.osVersion = osVersion;
}
public String getType() {
return type;
}
......
......@@ -8,6 +8,14 @@ public class UnbindSnParam {
private String mac;
private String snNo;
public UnbindSnParam() {
}
public UnbindSnParam(String mac, String snNo) {
this.mac = mac;
this.snNo = snNo;
}
public String getMac() {
return mac;
}
......
package com.wmdigit.network.repository;
import android.text.TextUtils;
import android.widget.Toast;
import com.elvishew.xlog.XLog;
import com.wmdigit.NetworkModule;
import com.wmdigit.common.base.mvvm.BaseMvvmNetworkRepository;
import com.wmdigit.common.base.mvvm.SingleLiveEvent;
import com.wmdigit.network.BuildConfig;
import com.wmdigit.network.R;
import com.wmdigit.network.bean.request.QueryLatestAppVersionParam;
import com.wmdigit.network.bean.response.AppVersionDTO;
import com.wmdigit.network.factory.ServiceFactory;
import com.wmdigit.network.service.PosService;
import com.wmdigit.network.utils.RxHelper;
import io.reactivex.disposables.Disposable;
/**
*
* @author dizi
*/
public class AppRemoteRepository extends BaseMvvmNetworkRepository {
private static AppRemoteRepository instance;
public static AppRemoteRepository getInstance(){
if (instance == null){
synchronized (AppRemoteRepository.class){
if (instance == null){
instance = new AppRemoteRepository();
}
}
}
return instance;
}
public AppRemoteRepository() {
}
/* public Disposable getLatestRemoteTool() {
return ServiceFactory.getServiceFactory().getPosService()
.getLatestRemoteToolWithType("REMOTE_TOOL_AN")
.compose(RxHelper.handlePosResult())
.subscribe(appVersionDTO -> {
}, throwable -> {
});
}*/
public SingleLiveEvent<AppVersionDTO> appVersion = new SingleLiveEvent<>();
public Disposable getLatestAppVersion() {
return ServiceFactory.getServiceFactory().getPosService()
.getAppLatestVersion(new QueryLatestAppVersionParam("FRESH_SERVE_ANDROID", BuildConfig.VERSION_CODE, "release"))
.compose(RxHelper.handlePosResult())
.subscribe(appVersionDTO -> {
if (TextUtils.isEmpty(appVersionDTO.getDownloadUrl())){
XLog.i("无需版本更新");
// 返回空,就表示已经是最新版本
showHttpToast(NetworkModule.getAppContext().getString(R.string.no_new_version));
return;
}
appVersion.postValue(appVersionDTO);
showHttpToast(NetworkModule.getAppContext().getString(R.string.check_new_version));
}, throwable -> {
showHttpToast(NetworkModule.getAppContext().getString(R.string.get_latest_version_failed));
XLog.e(throwable);
});
}
}
package com.wmdigit.network.repository;
import com.elvishew.xlog.XLog;
import com.wmdigit.common.base.mvvm.BaseMvvmNetworkRepository;
import com.wmdigit.common.utils.DateUtils;
import com.wmdigit.data.mmkv.repository.UserLocalRepository;
import com.wmdigit.network.bean.request.CateringIdentifyRecord;
......@@ -16,7 +17,7 @@ import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
public class IdentifyRecordRepository {
public class IdentifyRecordRepository extends BaseMvvmNetworkRepository {
private static IdentifyRecordRepository instance;
......
......@@ -2,11 +2,14 @@ package com.wmdigit.network.repository;
import android.text.TextUtils;
import com.elvishew.xlog.XLog;
import com.wmdigit.NetworkModule;
import com.wmdigit.common.base.mvvm.BaseMvvmNetworkRepository;
import com.wmdigit.common.base.mvvm.SingleLiveEvent;
import com.wmdigit.common.utils.DeviceUtils;
import com.wmdigit.data.mmkv.repository.UserLocalRepository;
import com.wmdigit.network.R;
import com.wmdigit.network.bean.request.UnbindSnParam;
import com.wmdigit.network.bean.response.PosMachine;
import com.wmdigit.network.factory.ServiceFactory;
import com.wmdigit.network.repository.impl.IUserRemoteRepository;
......@@ -17,7 +20,9 @@ import com.wmdigit.network.utils.RxHelper;
import java.net.UnknownHostException;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import retrofit2.HttpException;
/**
......@@ -118,29 +123,72 @@ public class UserRemoteRepository extends BaseMvvmNetworkRepository implements I
.bindPos(params)
.compose(RxHelper.<PosMachine>handlePosResult())
.subscribe(posMachine -> {
if (posMachine != null) {
String privateKeyUrl = posMachine.getPrivateKeyUrl();
String wmKeyUrl = posMachine.getWmKeyUrl();
if (TextUtils.isEmpty(privateKeyUrl) || TextUtils.isEmpty(wmKeyUrl)) {
// 密钥下载链接为空,注册失败
showHttpToast(NetworkModule.getAppContext().getString(R.string.in_review_concat_manager));
return;
}
showHttpToast(NetworkModule.getAppContext().getString(R.string.register_success));
responseRegister.postValue(posMachine);
} else {
// 返回值为null, 注册失败
showHttpToast(NetworkModule.getAppContext().getString(R.string.response_empty));
}
}, throwable -> {
if (throwable instanceof UnknownHostException) {
showHttpToast(NetworkModule.getAppContext().getString(R.string.check_net));
} else if (throwable instanceof HttpException){
showHttpToast(NetworkModule.getAppContext().getString(R.string.please_check_input_tenant));
}else if(throwable instanceof ServerException){
showHttpToast(throwable.toString());
}
});
if (posMachine != null) {
String privateKeyUrl = posMachine.getPrivateKeyUrl();
String wmKeyUrl = posMachine.getWmKeyUrl();
if (TextUtils.isEmpty(privateKeyUrl) || TextUtils.isEmpty(wmKeyUrl)) {
// 密钥下载链接为空,注册失败
showHttpToast(NetworkModule.getAppContext().getString(R.string.in_review_concat_manager));
return;
}
showHttpToast(NetworkModule.getAppContext().getString(R.string.register_success));
responseRegister.postValue(posMachine);
} else {
// 返回值为null, 注册失败
showHttpToast(NetworkModule.getAppContext().getString(R.string.response_empty));
}
}, throwable -> {
if (throwable instanceof UnknownHostException) {
showHttpToast(NetworkModule.getAppContext().getString(R.string.check_net));
} else if (throwable instanceof HttpException){
showHttpToast(NetworkModule.getAppContext().getString(R.string.please_check_input_tenant));
}else if(throwable instanceof ServerException){
showHttpToast(throwable.toString());
}
});
}
/**
* 解绑POS设备
*
* 该方法通过调用服务器接口实现从当前账户解绑POS设备的功能它首先获取设备的Android ID和用户的SN码,
* 然后使用这些信息调用服务解绑POS设备如果解绑成功,会显示成功提示并在日志中记录;若解绑失败,
* 则会显示错误信息并在日志中记录详细错误
*
* @return 返回一个Disposable对象,用于取消可能正在进行的网络请求
*/
@Override
public Disposable unbindPos() {
// 获取设备的Android ID
String androidId = DeviceUtils.getAndroidId();
// 获取用户SN码,SN码在用户信息数组中的索引为2
String snCode = UserLocalRepository.getInstance().getUser()[2];
// 通过ServiceFactory获取POS服务
return ServiceFactory.getServiceFactory().getPosService()
// 使用获取到的Android ID和SN码创建解绑参数,调用解绑POS接口
.unbindPos(new UnbindSnParam(androidId, snCode))
// 对结果进行处理,封装成RxJava的Observer
.compose(RxHelper.handlePosResult())
// 订阅Observer,处理成功和失败的情况
.subscribe(unused -> {
// 解绑成功,清空本地记录,显示提示信息,并在日志中记录
UserLocalRepository.getInstance().clearUser();
showHttpToast(NetworkModule.getAppContext().getString(R.string.unbind_success));
XLog.i("解绑成功");
}, throwable -> {
if (throwable.toString().equals("java.lang.Exception: data null")){
// 解绑成功,清空本地记录,显示提示信息,并在日志中记录
UserLocalRepository.getInstance().clearUser();
showHttpToast(NetworkModule.getAppContext().getString(R.string.unbind_success));
XLog.i("解绑成功");
}
else {
// 解绑失败,显示错误信息,并在日志中记录详细错误
showHttpToast(throwable.toString());
XLog.i("解绑失败:" + throwable.toString());
}
});
}
......
......@@ -22,4 +22,10 @@ public interface IUserRemoteRepository {
* @param params
*/
Disposable register(RegisterParams params);
/**
* 解绑POS
* @return
*/
Disposable unbindPos();
}
......@@ -28,6 +28,9 @@ import retrofit2.http.PUT;
import retrofit2.http.Part;
import retrofit2.http.Query;
/**
* @author dizi
*/
public interface PosService {
/**
......@@ -40,12 +43,11 @@ public interface PosService {
/**
* 解绑
* @param mac
* @param snCode
* @param param
* @return
*/
@POST("newretail/api/pos/machine/unbind")
Call<BasePosResponse> unbindPos(@Body UnbindSnParam param);
Observable<BasePosResponse<Void>> unbindPos(@Body UnbindSnParam param);
/**
* 上传图像
......@@ -95,6 +97,14 @@ public interface PosService {
@GET("newretail/api/sys/app/version/getLatestWithType")
Observable<BasePosResponse<AppVersionDTO>> getLatestRemoteToolWithType(@Query("type") String type);
/**
* 同步下载远程工具
* @param type
* @return
*/
@GET("newretail/api/sys/app/version/getLatestWithType")
Call<BasePosResponse<AppVersionDTO>> getLatestRemoteToolWithTypeSync(@Query("type") String type);
/**
* 上传餐饮识别记录
* @param record
......
......@@ -13,4 +13,8 @@
<string name="query_register_info_failed">查询注册信息失败</string>
<string name="query_register_info_success">查询注册信息成功</string>
<string name="register_success">注册成功</string>
<string name="unbind_success">解绑成功</string>
<string name="get_latest_version_failed">获取新版本失败</string>
<string name="no_new_version">已是最新版本</string>
<string name="check_new_version">检查到新版本</string>
</resources>
\ No newline at end of file
......@@ -11,4 +11,8 @@ v1.0.2 2024/08/06 1.增加系统信息页
8.集成标框、菜品识别、餐盘识别算法
9.集成索引库算法(索引库版本较老,可能存在最后一条索引删除不掉的BUG)
10.todo 菜品算法更新128模型
11.增加数据上传
\ No newline at end of file
11.增加数据上传
12.增加【清空商品数据】、【SN解绑】、【下载远程工具】、【检查更新】功能
13.增加摄像头断线重连
14.todo 增加学习记录管理模块
15.todo 替换LOGO
\ No newline at end of file
File added
......@@ -47,6 +47,7 @@ dependencies {
implementation project(path: ':data-remote')
implementation project(path: ':camera')
implementation project(path: ':core')
implementation project(path: ':module-upgrade')
implementation 'com.alibaba:arouter-api:1.5.2'
annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
......
......@@ -10,6 +10,7 @@ import androidx.recyclerview.widget.GridLayoutManager;
import com.wmdigit.camera.CameraxController;
import com.wmdigit.common.base.mvvm.BaseMvvmFragment;
import com.wmdigit.common.view.keyboard.EnglishAndNumberKeyboard;
import com.wmdigit.core.videopipe.VideoPipeRepository;
import com.wmdigit.setting.R;
import com.wmdigit.setting.adapter.ProductsAdapter;
import com.wmdigit.setting.databinding.FragmentDataLearningBinding;
......@@ -54,6 +55,10 @@ public class DataLearningFragment extends BaseMvvmFragment<DataLearningViewModel
mDataBinding.setViewModel(mViewModel);
productsAdapter = new ProductsAdapter(requireContext(), mViewModel.products);
mDataBinding.rvProducts.setAdapter(productsAdapter);
// 注册相机回调
CameraxController.getInstance(requireContext())
.setFrameInterval(2)
.setOnImageAnalyzeListener(mViewModel.getOnImageAnalyzeListener());
}
@Override
......@@ -99,16 +104,12 @@ public class DataLearningFragment extends BaseMvvmFragment<DataLearningViewModel
@Override
public void onStart() {
super.onStart();
// 注册相机回调
CameraxController.getInstance(requireContext())
.setFrameInterval(2)
.setOnImageAnalyzeListener(mViewModel.getOnImageAnalyzeListener());
}
@Override
public void onStop() {
super.onStop();
// 注销相机回调
CameraxController.getInstance().setOnImageAnalyzeListener(null);
// CameraxController.getInstance().setOnImageAnalyzeListener(null);
}
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import com.wmdigit.common.view.popupwindow.SecondConfirmWindow;
import com.wmdigit.setting.R;
import com.wmdigit.setting.adapter.FuncButtonAdapter;
import com.wmdigit.setting.databinding.FragmentDataManagerBinding;
import com.wmdigit.setting.view.popupwindow.DownloadRemoteToolPopupWindow;
import com.wmdigit.setting.viewmodel.DataManagerViewModel;
......@@ -45,6 +46,21 @@ public class DataManagerFragment extends BaseMvvmFragment<DataManagerViewModel,
clearLearningData();
break;
case 3:
// 清空商品数据
clearProductData();
break;
case 4:
// 解绑POS
unbindPos();
break;
case 5:
// 下载远程工具
downloadRemoteTool();
break;
default:
break;
}
......@@ -52,27 +68,64 @@ public class DataManagerFragment extends BaseMvvmFragment<DataManagerViewModel,
}
/**
* 清空学习数据
* 下载远程工具
*
* 此方法负责启动一个下载远程工具的流程,通过弹出一个专用的弹窗来实现
* 使用DownloadRemoteToolPopupWindow来显示一个用户界面,该界面用于管理远程工具的下载过程
* 在这个方法内部,首先创建了DownloadRemoteToolPopupWindow的一个实例,然后调用该实例的showWindow方法来显示弹窗
*/
private void clearLearningData() {
private void downloadRemoteTool() {
// 创建DownloadRemoteToolPopupWindow实例,传入当前活动的上下文
DownloadRemoteToolPopupWindow downloadRemoteToolPopupWindow = new DownloadRemoteToolPopupWindow(requireActivity());
// 显示下载远程工具的弹窗
downloadRemoteToolPopupWindow.showWindow();
}
/**
* 解绑位置信息方法
* 此方法通过弹出确认窗口,提示用户确认解绑当前位置信息
* 确认后调用解绑位置信息的ViewModel方法
*/
private void unbindPos() {
// 设置确认窗口的标题和内容,并响应点击事件解绑位置信息
mSecondConfirmWindow.setTitle(requireContext().getString(com.wmdigit.common.R.string.prompt))
.setContent(requireContext().getString(R.string.module_setting_confirm_unbind_pos))
.setClickListener(() -> mViewModel.unbindPos())
.showWindow();
}
/**
* 清除产品数据的方法
*
* 此方法通过显示一个确认窗口来提示用户即将清除学习数据
* 用户确认后,将调用ViewModel的clearProducts方法来执行清除操作
*/
private void clearProductData() {
// 设置确认窗口的标题和内容,提示用户将要清除学习数据
mSecondConfirmWindow.setTitle(requireContext().getString(com.wmdigit.common.R.string.prompt))
.setContent(requireContext().getString(R.string.module_setting_confirm_clear_learning_data))
.setClickListener(new SecondConfirmWindow.OnClickListener() {
@Override
public void onConfirm() {
mViewModel.clearLearningData();
}
// 设置确认按钮的点击事件,确认后调用ViewModel的clearProducts方法
.setClickListener(()->{mViewModel.clearProducts();})
.showWindow();
}
@Override
public void onCancel() {
}
}).showWindow();
/**
* 清空学习数据
*/
private void clearLearningData() {
mSecondConfirmWindow.setTitle(requireContext().getString(com.wmdigit.common.R.string.prompt))
.setContent(requireContext().getString(R.string.module_setting_confirm_clear_learning_data))
.setClickListener(() -> mViewModel.clearLearningData()).showWindow();
}
@Override
protected void initObserve() {
super.initObserve();
// 观察网络通知
mViewModel.httpToast.observe(this, this::showToast);
}
@Override
......
package com.wmdigit.setting.fragment;
import com.wmdigit.common.base.mvvm.BaseMvvmFragment;
import com.wmdigit.network.bean.response.AppVersionDTO;
import com.wmdigit.setting.R;
import com.wmdigit.setting.databinding.FragmentSystemInfoBinding;
import com.wmdigit.setting.viewmodel.SystemInfoViewModel;
import com.wmdigit.upgrade.AppUpgradePopupWindow;
/**
* 系统信息页
......@@ -20,6 +22,10 @@ public class SystemInfoFragment extends BaseMvvmFragment<SystemInfoViewModel, Fr
protected void initObserve() {
// 识别模式监听
mViewModel.aiMode.observe(this, position-> mViewModel.saveAiMode(position));
// 监听HTTP请求信息
mViewModel.httpToast.observe(this, this::showToast);
// 监听升级消息
mViewModel.newAppVersion.observe(this, this::appUpgrade);
}
@Override
......@@ -43,4 +49,12 @@ public class SystemInfoFragment extends BaseMvvmFragment<SystemInfoViewModel, Fr
protected Class<SystemInfoViewModel> getViewModel() {
return SystemInfoViewModel.class;
}
private void appUpgrade(AppVersionDTO appVersionDTO){
AppUpgradePopupWindow appUpgradePopupWindow = new AppUpgradePopupWindow(getActivity())
.setVersionName(appVersionDTO.getVersionName())
.setUpgradeContent(appVersionDTO.getDesciption())
.setDlUrl(appVersionDTO.getDownloadUrl());
appUpgradePopupWindow.showWindow();
}
}
\ No newline at end of file
package com.wmdigit.setting.view.popupwindow;
import android.app.Activity;
import android.os.Environment;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.widget.ContentLoadingProgressBar;
import com.elvishew.xlog.XLog;
import com.king.app.updater.AppUpdater;
import com.king.app.updater.UpdateConfig;
import com.king.app.updater.callback.UpdateCallback;
import com.king.app.updater.http.OkHttpManager;
import com.wmdigit.common.view.popupwindow.BasePopupWindow;
import com.wmdigit.network.factory.ServiceFactory;
import com.wmdigit.network.utils.RxHelper;
import com.wmdigit.setting.R;
import java.io.File;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
/**
* 下载远程工具弹窗
* @author dizi
*/
public class DownloadRemoteToolPopupWindow extends BasePopupWindow {
private CompositeDisposable compositeDisposable;
/**
* 下载进度条
*/
private ContentLoadingProgressBar progressBar;
private TextView tvDlTitle, tvDlProcess, tvCancel, tvConfirm;
private AppUpdater mDownloader;
private Activity mActivity;
public DownloadRemoteToolPopupWindow(Activity activity) {
super(LayoutInflater.from(activity).inflate(R.layout.layout_window_download_remote_tool, null),
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);
this.mActivity = activity;
hideOrShowDlProgressComponent(false);
closeInputWindow();
}
private void hideOrShowDlProgressComponent(boolean isShow) {
if (isShow){
progressBar.setVisibility(View.VISIBLE);
tvDlTitle.setVisibility(View.VISIBLE);
tvDlProcess.setVisibility(View.VISIBLE);
progressBar.setProgress(0);
}
else{
progressBar.setVisibility(View.GONE);
tvDlTitle.setVisibility(View.GONE);
tvDlProcess.setVisibility(View.GONE);
}
}
@Override
public void showWindow() {
showAtLocation(mActivity.getWindow().getDecorView(), Gravity.CENTER, 0, 0);
}
@Override
public void dismissWindow() {
if (isShowing()){
dismiss();
}
}
@Override
protected Activity getActivity() {
return mActivity;
}
@Override
protected void initView() {
progressBar = getContentView().findViewById(R.id.progressBar);
tvDlTitle = getContentView().findViewById(R.id.tv_title_progress);
tvDlProcess = getContentView().findViewById(R.id.tv_download_progress);
tvCancel = getContentView().findViewById(R.id.tv_cancel);
tvConfirm = getContentView().findViewById(R.id.tv_confirm);
}
@Override
protected void initData() {
compositeDisposable = new CompositeDisposable();
}
@Override
protected void initListener() {
tvCancel.setOnClickListener(v -> {
if (mDownloader != null){
mDownloader.stop();
}
dismiss();
});
tvConfirm.setOnClickListener(v -> {
getLatestRemoteTool();
});
}
private void getLatestRemoteTool() {
tvConfirm.setEnabled(false);
Disposable disposable = ServiceFactory.getServiceFactory().getPosService()
.getLatestRemoteToolWithType("REMOTE_TOOL_AN")
.compose(RxHelper.handlePosResult())
.subscribe(appVersionDTO -> {
if (appVersionDTO == null || TextUtils.isEmpty(appVersionDTO.getDownloadUrl())){
Toast.makeText(mActivity, mActivity.getString(R.string.error_get_remote_tool_url), Toast.LENGTH_SHORT).show();
tvConfirm.setEnabled(true);
return;
}
downloadRemoteToolWithUrl(appVersionDTO.getDownloadUrl());
}, throwable -> {
tvConfirm.setEnabled(true);
Toast.makeText(mActivity, mActivity.getString(R.string.error_get_remote_tool_url), Toast.LENGTH_SHORT).show();
});
compositeDisposable.add(disposable);
}
private void downloadRemoteToolWithUrl(String downloadUrl) {
String path = mActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/WmService/RemoteTool/";
File pathFile = new File(path);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
else{
}
UpdateConfig config = new UpdateConfig();
config.setUrl(downloadUrl);
config.setPath(path);
config.setFilename("RemoteTool.apk");
config.setChannelId("300");
config.setChannelName(getActivity().getString(com.wmdigit.common.R.string.prompt));
config.setNotificationIcon(com.wmdigit.common.R.drawable.ic_download_from_cloud);
config.setInstallApk(true);
mDownloader = new AppUpdater(getActivity(), config).setHttpManager(OkHttpManager.getInstance())
.setUpdateCallback(new UpdateCallback() {
@Override
public void onDownloading(boolean isDownloading) {
if (isDownloading) {
System.out.println("isDownloading==>");
}
}
@Override
public void onStart(String url) {
hideOrShowDlProgressComponent(true);
updateProgress(0);
}
@Override
public void onProgress(long progress, long total, boolean isChange) {
if (isChange) {
int curProgress = Math.round(progress * 1.0f / total * 100.0f);
updateProgress(curProgress);
}
}
@Override
public void onFinish(File file) {
progressBar.setProgress(100);
tvDlProcess.setText(getActivity().getString(R.string.packaging_remote_tool));
tvCancel.setEnabled(false);
dismiss();
}
@Override
public void onError(Exception e) {
XLog.e(e.toString());
tvDlProcess.setText(getActivity().getString(R.string.download_fail));
tvCancel.setEnabled(true);
tvConfirm.setEnabled(true);
tvConfirm.setText(getActivity().getString(R.string.download_retry));
}
@Override
public void onCancel() {
hideOrShowDlProgressComponent(false);
}
});
mDownloader.start();
}
private void updateProgress(int progress) {
progressBar.setProgress(progress);
tvDlProcess.setText(progress + "%");
}
@Override
public void onDismiss() {
super.onDismiss();
if (mDownloader != null){
mDownloader.stop();
}
compositeDisposable.clear();
}
}
......@@ -5,19 +5,25 @@ import android.app.Application;
import androidx.annotation.NonNull;
import com.wmdigit.common.base.mvvm.BaseViewModel;
import com.wmdigit.common.base.mvvm.SingleLiveEvent;
import com.wmdigit.core.hnsw.HnswRepository;
import com.wmdigit.data.database.repository.FeaturesRepository;
import com.wmdigit.data.database.repository.ProductsRepository;
import com.wmdigit.network.repository.UserRemoteRepository;
import com.wmdigit.setting.R;
import com.wmdigit.setting.model.FuncButton;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.disposables.Disposable;
/**
* 数据管理页ViewModel
* @author dizi
*/
public class DataManagerViewModel extends BaseViewModel {
public SingleLiveEvent<String> httpToast;
public List<FuncButton> funcButtons = new ArrayList<>();
public DataManagerViewModel(@NonNull Application application) {
......@@ -26,6 +32,7 @@ public class DataManagerViewModel extends BaseViewModel {
}
private void getData(){
httpToast = UserRemoteRepository.getInstance().mHttpToast;
// 初始化功能键列表
funcButtons.add(new FuncButton(getApplication().getString(R.string.module_setting_upload_database_to_server), R.drawable.ic_upload_learning_data));
funcButtons.add(new FuncButton(getApplication().getString(R.string.module_setting_download_database_from_server), R.drawable.ic_download_learning_data));
......@@ -50,4 +57,31 @@ public class DataManagerViewModel extends BaseViewModel {
// 发送成功清除学习数据的提示信息
toastMessage.postValue(getApplication().getString(R.string.module_setting_clear_learning_data_success));
}
/**
* 清除所有产品信息
*
* 此方法通过调用 ProductsRepository 实例的 deleteAll 方法来删除所有产品信息,
* 并在操作成功后显示一个提示信息给用户。
*/
public void clearProducts() {
// 删除所有产品信息
ProductsRepository.getInstance().deleteAll();
// 显示删除成功的提示信息
toastMessage.postValue(getApplication().getString(R.string.module_setting_clear_products_success));
}
/**
* 解绑POS
*
* 通过调用远程仓库中的unbindPos方法来实现POS的解绑功能,并将返回的Disposable对象添加到compositeDisposable中
* 以便于管理和取消可能的网络请求。
*/
public void unbindPos(){
// 调用远程仓库的解绑POS方法,发起网络请求
Disposable disposable = UserRemoteRepository.getInstance().unbindPos();
// 将请求的Disposable对象添加到复合Disposable中,用于后续请求状态的管理
compositeDisposable.add(disposable);
}
}
......@@ -15,6 +15,10 @@ import com.wmdigit.core.catering.TargetDetectionRepository;
import com.wmdigit.data.mmkv.repository.AiLocalRepository;
import com.wmdigit.data.mmkv.repository.CropLocalRepository;
import com.wmdigit.data.mmkv.repository.UserLocalRepository;
import com.wmdigit.network.bean.response.AppVersionDTO;
import com.wmdigit.network.repository.AppRemoteRepository;
import io.reactivex.disposables.Disposable;
/**
* 系统信息页的ViewModel
......@@ -62,6 +66,10 @@ public class SystemInfoViewModel extends BaseViewModel {
*/
public MutableLiveData<Integer> aiMode = new MutableLiveData<>();
public MutableLiveData<String> httpToast;
public SingleLiveEvent<AppVersionDTO> newAppVersion;
public SystemInfoViewModel(@NonNull Application application) {
super(application);
getData();
......@@ -97,13 +105,17 @@ public class SystemInfoViewModel extends BaseViewModel {
isCrop.set(CropLocalRepository.getInstance().getHasCropped());
// 获取AI模式
aiMode.postValue(AiLocalRepository.getInstance().getAiMode());
httpToast = AppRemoteRepository.getInstance().mHttpToast;
newAppVersion = AppRemoteRepository.getInstance().appVersion;
}
/**
* 检查APP版本升级
*/
public void checkAppUpgrade(){
Disposable disposable = AppRemoteRepository.getInstance().getLatestAppVersion();
compositeDisposable.add(disposable);
}
/**
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_a70"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_v_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.35"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_v_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.65"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_window"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/rect_10_white"
app:layout_constraintStart_toEndOf="@+id/gl_v_1"
app:layout_constraintEnd_toStartOf="@+id/gl_v_2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_v_50"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.50"/>
<!--标题-->
<TextView
android:id="@+id/tv_title"
style="@style/text_base.title"
android:text="@string/title_download_remote_tool"
android:layout_marginStart="0dp"
android:layout_marginTop="@dimen/dp_20"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/tv_desc"
style="@style/text_base.content"
android:text="@string/confirm_download_remote_tool"
android:gravity="center"
android:layout_marginTop="@dimen/dp_60"
android:layout_marginStart="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_10"
app:layout_constraintStart_toStartOf="@+id/tv_title"
app:layout_constraintEnd_toEndOf="@+id/tv_title"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
/>
<!--下载进度条-->
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:max="100"
android:progress="0"
android:progressDrawable="@drawable/progressbar_h"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginHorizontal="@dimen/dp_10"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/tv_desc"/>
<TextView
android:id="@+id/tv_title_progress"
style="@style/text_base.content"
android:text="@string/upgrade_progress"
android:gravity="center"
android:visibility="gone"
android:layout_marginTop="@dimen/dp_5"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintStart_toStartOf="@+id/progressBar"/>
<TextView
android:id="@+id/tv_download_progress"
style="@style/text_base.content"
android:text=""
android:gravity="center"
android:layout_marginTop="@dimen/dp_5"
android:layout_marginEnd="0dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintEnd_toEndOf="@+id/progressBar"/>
<!--取消-->
<TextView
android:id="@+id/tv_cancel"
style="@style/pop_window_lb_cancel_button"
android:text="@string/cancel"
android:layout_marginTop="@dimen/dp_60"
app:layout_constraintTop_toBottomOf="@+id/tv_title_progress"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/gl_v_50"
/>
<!--确认-->
<TextView
android:id="@+id/tv_confirm"
style="@style/pop_window_rb_confirm_button"
android:text="@string/confirm"
android:layout_marginTop="@dimen/dp_60"
app:layout_constraintTop_toBottomOf="@+id/tv_title_progress"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/gl_v_50"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -31,6 +31,7 @@
<string name="module_setting_download_database_from_server">从云端下载数据库</string>
<string name="module_setting_clear_learning_data">清空学习数据</string>
<string name="module_setting_confirm_clear_learning_data">请确认是否清空学习数据?</string>
<string name="module_setting_confirm_clear_product_data">请确认是否清空商品数据?</string>
<string name="module_setting_clear_products">清空商品数据</string>
<string name="module_setting_unbind">SN解绑</string>
<string name="module_setting_download_remote_tool">下载远程工具</string>
......@@ -39,5 +40,11 @@
<string name="module_setting_please_crop_first">请先对相机进行裁剪</string>
<string name="ai_mode_dish_recognition">菜品识别</string>
<string name="ai_mode_plate_recognition">餐盘识别</string>
<string name="module_setting_clear_learning_data_success">清空数据成功</string>
<string name="module_setting_clear_learning_data_success">清空学习数据成功</string>
<string name="module_setting_clear_products_success">清空商品数据成功</string>
<string name="module_setting_confirm_unbind_pos">请确认是否解绑该设备的激活密钥</string>
<string name="error_get_remote_tool_url">获取远程工具下载地址失败</string>
<string name="packaging_remote_tool">正在安装远程工具</string>
<string name="download_fail">下载失败</string>
<string name="download_retry">下载成功</string>
</resources>
\ No newline at end of file
/build
\ No newline at end of file
plugins {
id 'com.android.library'
}
android {
namespace 'com.wmdigit.upgrade'
compileSdk 33
defaultConfig {
minSdk 24
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
implementation project(path: ':common')
// implementation project(path: ':data-remote')
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
package com.wmdigit.upgrade;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.wmdigit.upgrade.test", appContext.getPackageName());
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
\ No newline at end of file
package com.wmdigit.upgrade;
import android.app.Activity;
import android.os.Environment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.widget.ContentLoadingProgressBar;
import com.elvishew.xlog.XLog;
import com.king.app.updater.AppUpdater;
import com.king.app.updater.UpdateConfig;
import com.king.app.updater.callback.UpdateCallback;
import com.king.app.updater.http.OkHttpManager;
import com.wmdigit.common.view.popupwindow.BasePopupWindow;
import java.io.File;
/**
* App更新弹窗
* @author dizi
*/
public class AppUpgradePopupWindow extends BasePopupWindow {
private ContentLoadingProgressBar progressBar;
private TextView tvProgress, tvTitleProgress;
private TextView tvUpgradeVersion, tvUpgradeContent;
private TextView tvConfirm, tvCancel;
/**
* 下载链接
*/
private String dlUrl;
/**
* 版本名称
*/
private String versionName;
/**
* 版本更新内容
*/
private String upgradeContent;
private Activity mActivity;
private AppUpdater mAppUpdater;
public AppUpgradePopupWindow(Activity activity) {
super(LayoutInflater.from(activity).inflate(R.layout.layout_window_app_upgrade, null),
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);
this.mActivity = activity;
}
@Override
public void showWindow() {
showAtLocation(mActivity.getWindow().getDecorView(), Gravity.CENTER, 0, 0);
}
@Override
public void dismissWindow() {
if (isShowing()){
dismiss();
}
}
@Override
protected Activity getActivity() {
return mActivity;
}
@Override
protected void initView() {
progressBar = getContentView().findViewById(R.id.progressBar);
tvProgress = getContentView().findViewById(R.id.tv_upgrade_progress);
tvCancel = getContentView().findViewById(R.id.tv_cancel);
tvConfirm = getContentView().findViewById(R.id.tv_confirm);
tvTitleProgress = getContentView().findViewById(R.id.tv_title_progress);
tvUpgradeVersion = getContentView().findViewById(R.id.tv_version_name);
tvUpgradeContent = getContentView().findViewById(R.id.tv_upgrade_content);
showOrHideProgressBar(false);
}
private void showOrHideProgressBar(boolean isShow) {
if (isShow){
progressBar.setVisibility(View.VISIBLE);
tvTitleProgress.setVisibility(View.VISIBLE);
tvProgress.setVisibility(View.VISIBLE);
}
else{
progressBar.setVisibility(View.INVISIBLE);
tvTitleProgress.setVisibility(View.INVISIBLE);
tvProgress.setVisibility(View.INVISIBLE);
}
}
public AppUpgradePopupWindow setDlUrl(String dlUrl) {
this.dlUrl = dlUrl;
return this;
}
public AppUpgradePopupWindow setVersionName(String versionName) {
this.versionName = versionName;
tvUpgradeVersion.setText(versionName);
return this;
}
public AppUpgradePopupWindow setUpgradeContent(String upgradeContent) {
this.upgradeContent = upgradeContent;
tvUpgradeContent.setText(upgradeContent);
return this;
}
@Override
protected void initData() {
}
@Override
protected void initListener() {
tvCancel.setOnClickListener(v->{
dismiss();
});
tvConfirm.setOnClickListener(v->{
downloadApk();
});
}
private void downloadApk() {
String path = mActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/WmService/" + versionName + "/";
File pathFile = new File(path);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
UpdateConfig config = new UpdateConfig();
config.setUrl(dlUrl);
config.setPath(path);
config.setFilename(mActivity.getPackageName() + ".apk");
config.setChannelId("100");
config.setChannelName(getActivity().getString(R.string.notify_title_download_apk));
config.setNotificationIcon(com.wmdigit.common.R.drawable.ic_download_from_cloud);
config.setInstallApk(true);
mAppUpdater = new AppUpdater(getActivity(), config)
.setHttpManager(OkHttpManager.getInstance())
.setUpdateCallback(new UpdateCallback() {
@Override
public void onDownloading(boolean isDownloading) {
if (isDownloading) {
Toast.makeText(getActivity(), getActivity().getString(R.string.downloading_apk), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onStart(String url) {
showOrHideProgressBar(true);
updateProgress(0);
}
@Override
public void onProgress(long progress, long total, boolean isChange) {
if (isChange) {
int currProgress = Math.round(progress * 1.0f / total * 100.0f);
updateProgress(currProgress);
}
}
@Override
public void onFinish(File file) {
showOrHideProgressBar(false);
dismiss();
}
@Override
public void onError(Exception e) {
Toast.makeText(getActivity(), getActivity().getString(R.string.error_download_apk), Toast.LENGTH_SHORT).show();
showOrHideProgressBar(false);
XLog.e(e.toString());
}
@Override
public void onCancel() {
showOrHideProgressBar(false);
}
});
mAppUpdater.start();
}
private void updateProgress(int progress){
progressBar.setProgress(progress);
tvProgress.setText(progress + "%");
}
@Override
public void onDismiss() {
super.onDismiss();
if (mAppUpdater != null){
mAppUpdater.stop();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/gray_999999" />
<corners android:bottomRightRadius="10dp"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/green_0fb9b1" />
<corners android:bottomRightRadius="10dp"/>
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_a70"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_v_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.35"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_v_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.65"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/rect_10_white"
app:layout_constraintStart_toEndOf="@+id/gl_v_1"
app:layout_constraintEnd_toStartOf="@+id/gl_v_2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/iv_logo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/img_upgrade"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_v_50"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.50"/>
<!--更新版本号-->
<TextView
android:id="@+id/tv_version_name"
style="@style/text_base.title"
android:layout_marginStart="@dimen/dp_5"
android:layout_marginTop="@dimen/dp_3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_logo"
/>
<!--更新内容-->
<TextView
android:id="@+id/tv_upgrade_content"
style="@style/text_base.content"
android:layout_width="0dp"
android:layout_margin="@dimen/dp_5"
android:gravity="start"
android:singleLine="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_version_name"
/>
<!--升级进度条-->
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:max="100"
android:progress="1"
android:progressDrawable="@drawable/progressbar_h"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginHorizontal="@dimen/dp_5"
app:layout_constraintTop_toBottomOf="@+id/tv_upgrade_content"/>
<TextView
android:id="@+id/tv_title_progress"
style="@style/text_base.content"
android:text="@string/upgrade_progress"
android:gravity="center"
android:layout_marginTop="@dimen/dp_5"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintStart_toStartOf="@+id/progressBar"/>
<TextView
android:id="@+id/tv_upgrade_progress"
style="@style/text_base.content"
android:text=""
android:gravity="center"
android:layout_marginTop="@dimen/dp_5"
android:layout_marginEnd="0dp"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintEnd_toEndOf="@+id/progressBar"/>
<!--取消-->
<TextView
android:id="@+id/tv_cancel"
style="@style/pop_window_lb_cancel_button"
android:text="@string/cancel"
android:layout_marginTop="@dimen/dp_60"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/gl_v_50"
/>
<!--确认-->
<TextView
android:id="@+id/tv_confirm"
style="@style/pop_window_rb_confirm_button"
android:background="@drawable/sel_rect_10_br_teal_gray"
android:text="@string/upgrade_now"
app:layout_constraintTop_toTopOf="@+id/tv_cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/gl_v_50"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="upgrade_now">立即升级</string>
<string name="notify_title_download_apk">下载安装包</string>
<string name="downloading_apk">正在下载安装包</string>
<string name="error_download_apk">下载安装包失败</string>
</resources>
\ No newline at end of file
package com.wmdigit.upgrade;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
......@@ -43,6 +43,7 @@ dependencies {
implementation project(path: ':common')
implementation project(path: ':core')
implementation project(path: ':data-local')
implementation project(path: ':data-remote')
implementation project(path: ':camera')
implementation project(path: ':module-setting')
......
......@@ -8,11 +8,15 @@ import androidx.lifecycle.LifecycleOwner;
import com.alibaba.android.arouter.launcher.ARouter;
import com.elvishew.xlog.XLog;
import com.google.gson.Gson;
import com.wmdigit.camera.CameraxController;
import com.wmdigit.camera.listener.OnImageAnalyzeListener;
import com.wmdigit.common.constants.ErrorCode;
import com.wmdigit.common.constants.RouteConstant;
import com.wmdigit.common.model.IdentifyRecordDTO;
import com.wmdigit.common.model.ProductsDTO;
import com.wmdigit.common.utils.BitmapUtils;
import com.wmdigit.common.utils.DateUtils;
import com.wmdigit.common.utils.ParcelHelper;
import com.wmdigit.core.catering.TargetDetectionRepository;
import com.wmdigit.core.catering.model.TargetDetectResult;
......@@ -21,14 +25,20 @@ import com.wmdigit.core.opencv.OpencvRepository;
import com.wmdigit.core.videopipe.VideoPipeRepository;
import com.wmdigit.data.database.entity.ProductsPO;
import com.wmdigit.data.database.repository.ProductsRepository;
import com.wmdigit.data.disk.repository.DiskRepository;
import com.wmdigit.data.mmkv.repository.CropLocalRepository;
import com.wmdigit.data.mmkv.repository.UserLocalRepository;
import com.wmdigit.network.bean.request.CateringIdentifyRecord;
import com.wmdigit.network.factory.ServiceFactory;
import com.wmdigit.network.oss.OSSManager;
import com.wmdigit.network.utils.RxHelper;
import com.wmdigit.service.ICateringInterface;
import com.wmdigit.service.IOnDetectionListener;
import com.wmdigit.service.IOnInitListener;
import com.wmdigit.service.ServiceModule;
import com.wmdigit.service.aidl.model.DetectResult;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
......@@ -36,6 +46,9 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
/**
* 餐饮AIDL服务实现类
* @author dizi
......@@ -351,8 +364,11 @@ public class CateringInterfaceImpl extends ICateringInterface.Stub{
return detectResult;
}
TargetDetectResult targetDetectResult;
// 仅当该方法由视频流触发时,才执行上传
boolean isUpload = false;
// 如果传入的Bitmap为空,使用备用的Bitmap
if (bitmap == null) {
isUpload = true;
bitmap = ParcelHelper.copy(bitmapCopy);
}
// 对图像进行处理,尝试检测目标
......@@ -362,15 +378,54 @@ public class CateringInterfaceImpl extends ICateringInterface.Stub{
return detectResult;
}
List<ProductsPO> productsPOList = new ArrayList<>();
// 根据检测到的特征检索产品,并将结果添加到列表中
for (int i = 0; i < targetDetectResult.getFeatures().length; i++) {
ProductsPO product = HnswRepository.getInstance().retrieveByFeature(targetDetectResult.getFeatures()[i]);
productsPOList.add(product);
}
targetDetectResult.setProducts(productsPOList);
String[] productNames = new String[targetDetectResult.getProducts().size()];
String[] productCodes = new String[targetDetectResult.getProducts().size()];
// 遍历检测到的产品,将产品代码添加到结果中
int index = 0;
for (ProductsPO temp : targetDetectResult.getProducts()){
detectResult.getProductCodes().add(temp.getProductCode());
productNames[index] = temp.getProductName();
productCodes[index] = temp.getProductCode();
index ++;
}
// 上传
if (isUpload){
IdentifyRecordDTO identifyRecordDTO = new IdentifyRecordDTO(targetDetectResult.getRectArray(), productNames, productCodes);
String json = new Gson().toJson(identifyRecordDTO);
Bitmap bitmapTemp = ParcelHelper.copy(bitmap);
Disposable disposable = Observable.create(emitter -> {
String filePath = DiskRepository.getInstance().saveIdentifyRecordToDisk(bitmapTemp, null, null);
String url = OSSManager.getInstance().syncUploadFileToOSS(new File(filePath));
emitter.onNext(url);
}).flatMap(url ->{
// 创建一个餐饮识别记录对象
CateringIdentifyRecord record = new CateringIdentifyRecord();
// 设置POS机编号
record.setPosCode(UserLocalRepository.getInstance().getPosId());
// 设置识别时间
record.setIdentifyTime(DateUtils.getTodayTime());
// 设置图片URL
record.setImageUrl((String) url);
// 设置帧图片URL
record.setFrameImageUrl((String) url);
// 设置JSON
record.setSmallImageSite(json);
// 异步上传餐饮识别记录到服务器
return ServiceFactory.getServiceFactory().getPosService()
.uploadCateringIdentifyRecord(record)
.compose(RxHelper.handlePosResult());
}).subscribe(aLong -> {
XLog.i("图片记录上传成功");
}, throwable -> {
XLog.e("图片记录上传失败");
});
}
// 如果需要生成Bitmap,进行相关处理
if (generateBitmap) {
......
......@@ -35,3 +35,4 @@ include ':data-remote'
include ':service'
include ':opencv'
include ':service-sdk'
include ':module-upgrade'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment