FileRecoverViewModel.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. package com.datarecovery.master.module.filerecover;
  2. import static com.datarecovery.master.data.consts.EventId.EVENT_3000004;
  3. import androidx.lifecycle.LiveData;
  4. import androidx.lifecycle.MutableLiveData;
  5. import androidx.lifecycle.Transformations;
  6. import com.atmob.app.lib.base.BaseViewModel;
  7. import com.atmob.app.lib.livedata.SingleLiveEvent;
  8. import com.atmob.common.runtime.ActivityUtil;
  9. import com.atmob.common.runtime.ContextUtil;
  10. import com.datarecovery.master.R;
  11. import com.datarecovery.master.data.consts.AdFuncId;
  12. import com.datarecovery.master.data.consts.EventId;
  13. import com.datarecovery.master.data.repositories.DeviceFuncRepository;
  14. import com.datarecovery.master.handler.EventHelper;
  15. import com.datarecovery.master.module.member.MemberActivity;
  16. import com.datarecovery.master.module.member.MemberType;
  17. import com.datarecovery.master.sdk.ad.AtmobAdHelper;
  18. import com.datarecovery.master.sdk.bugly.BuglyHelper;
  19. import com.datarecovery.master.utils.BoxingUtil;
  20. import com.datarecovery.master.utils.FileUtil;
  21. import com.datarecovery.master.utils.FilesSearch;
  22. import com.datarecovery.master.utils.MediaStoreHelper;
  23. import com.datarecovery.master.utils.ReverseArrayList;
  24. import com.datarecovery.master.utils.ToastUtil;
  25. import org.reactivestreams.Subscriber;
  26. import org.reactivestreams.Subscription;
  27. import java.util.ArrayList;
  28. import java.util.Iterator;
  29. import java.util.List;
  30. import java.util.concurrent.TimeUnit;
  31. import javax.inject.Inject;
  32. import atmob.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
  33. import atmob.reactivex.rxjava3.annotations.NonNull;
  34. import atmob.reactivex.rxjava3.core.Single;
  35. import atmob.reactivex.rxjava3.core.SingleObserver;
  36. import atmob.reactivex.rxjava3.disposables.Disposable;
  37. import atmob.rxjava.utils.RxJavaUtil;
  38. import dagger.hilt.android.lifecycle.HiltViewModel;
  39. @HiltViewModel
  40. public class FileRecoverViewModel extends BaseViewModel {
  41. private final long SCANNING_COUNTDOWN = 1000 * 60 * 6;
  42. private final long SCANNING_IS_TRIAL_COUNTDOWN = 1000 * 5;
  43. private final int[] tabTitle = {R.string.word, R.string.excel, R.string.ppt, R.string.pdf};
  44. private final List<MutableLiveData<Boolean>> checkList = new ArrayList<>();
  45. private final List<FilesSearch.DocumentFile> wordList = new ReverseArrayList<>();
  46. private final List<FilesSearch.DocumentFile> excelList = new ReverseArrayList<>();
  47. private final List<FilesSearch.DocumentFile> pptList = new ReverseArrayList<>();
  48. private final List<FilesSearch.DocumentFile> pdfList = new ReverseArrayList<>();
  49. private final List<FilesSearch.DocumentFile> selectList = new ArrayList<>();
  50. private final MutableLiveData<List<FilesSearch.DocumentFile>> detectedWordList = new MutableLiveData<>();
  51. private final MutableLiveData<List<FilesSearch.DocumentFile>> detectedExcelList = new MutableLiveData<>();
  52. private final MutableLiveData<List<FilesSearch.DocumentFile>> detectedPPTList = new MutableLiveData<>();
  53. private final MutableLiveData<List<FilesSearch.DocumentFile>> detectedPDFList = new MutableLiveData<>();
  54. private final MutableLiveData<List<FilesSearch.DocumentFile>> selectedList = new MutableLiveData<>(selectList);
  55. private final SingleLiveEvent<?> scrollTop = new SingleLiveEvent<>();
  56. private final MutableLiveData<Boolean> showTrialView = new MutableLiveData<>();
  57. private final MutableLiveData<String> detectedLastFileName = new MutableLiveData<>();
  58. private final MutableLiveData<Integer> checkPosition = new MutableLiveData<>();
  59. private final SingleLiveEvent<?> showTrialFinishDialog = new SingleLiveEvent<>();
  60. private final SingleLiveEvent<?> showTrialExportFailDialog = new SingleLiveEvent<>();
  61. private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
  62. private final SingleLiveEvent<Boolean> showScanDialogEvent = new SingleLiveEvent<>();
  63. private final SingleLiveEvent<?> showUnlockEvent = new SingleLiveEvent<>();
  64. private final DeviceFuncRepository deviceFuncRepository;
  65. private final LiveData<String> selectedCountTxt;
  66. private Disposable scanDisposable;
  67. @Inject
  68. public FileRecoverViewModel(DeviceFuncRepository deviceFuncRepository) {
  69. this.deviceFuncRepository = deviceFuncRepository;
  70. selectedCountTxt = Transformations.map(selectedList, list -> {
  71. if (list == null || list.isEmpty()) {
  72. return ContextUtil.getContext().getString(R.string.export);
  73. }
  74. return ContextUtil.getContext().getString(R.string.export_count, list.size());
  75. });
  76. for (int i = 0; i < tabTitle.length; i++) checkList.add(new MutableLiveData<>(false));
  77. }
  78. public LiveData<?> getScrollTop() {
  79. return scrollTop;
  80. }
  81. public LiveData<?> getShowTrialFinishDialog() {
  82. return showTrialFinishDialog;
  83. }
  84. public LiveData<?> getShowTrialExportFailDialog() {
  85. return showTrialExportFailDialog;
  86. }
  87. public LiveData<Boolean> getShowTrialView() {
  88. return showTrialView;
  89. }
  90. public LiveData<String> getDetectedLastFileName() {
  91. return detectedLastFileName;
  92. }
  93. public LiveData<Integer> getCheckPosition() {
  94. return checkPosition;
  95. }
  96. public void setCheckPosition(int position) {
  97. this.checkPosition.setValue(position);
  98. }
  99. public int[] getTabTitle() {
  100. return tabTitle;
  101. }
  102. public LiveData<List<FilesSearch.DocumentFile>> getDetectedWordList() {
  103. return detectedWordList;
  104. }
  105. public LiveData<List<FilesSearch.DocumentFile>> getDetectedExcelList() {
  106. return detectedExcelList;
  107. }
  108. public LiveData<List<FilesSearch.DocumentFile>> getDetectedPPTList() {
  109. return detectedPPTList;
  110. }
  111. public LiveData<List<FilesSearch.DocumentFile>> getDetectedPDFList() {
  112. return detectedPDFList;
  113. }
  114. public LiveData<Boolean> getShowLoadingEvent() {
  115. return showLoadingEvent;
  116. }
  117. public LiveData<List<FilesSearch.DocumentFile>> getSelectedList() {
  118. return selectedList;
  119. }
  120. public LiveData<String> getSelectedCountTxt() {
  121. return selectedCountTxt;
  122. }
  123. public LiveData<Boolean> getShowScanDialogEvent() {
  124. return showScanDialogEvent;
  125. }
  126. public LiveData<?> getShowUnlockEvent() {
  127. return showUnlockEvent;
  128. }
  129. public void startFileScanning() {
  130. if (scanDisposable != null && !scanDisposable.isDisposed()) {
  131. return;
  132. }
  133. FilesSearch.search(ContextUtil.getContext(), FilesSearch.DocumentFile.WORD, FilesSearch.DocumentFile.EXCEL, FilesSearch.DocumentFile.PPT, FilesSearch.DocumentFile.PDF)
  134. .take(SCANNING_COUNTDOWN, TimeUnit.MILLISECONDS)
  135. .observeOn(AndroidSchedulers.mainThread())
  136. .subscribe(new Subscriber<List<FilesSearch.DocumentFile>>() {
  137. @Override
  138. public void onSubscribe(Subscription s) {
  139. s.request(Integer.MAX_VALUE);
  140. scanDisposable = Disposable.fromSubscription(s);
  141. addDisposable(scanDisposable);
  142. showScanDialogEvent.setValue(true);
  143. wordList.clear();
  144. excelList.clear();
  145. pptList.clear();
  146. pdfList.clear();
  147. selectList.clear();
  148. }
  149. @Override
  150. public void onNext(List<FilesSearch.DocumentFile> documentFiles) {
  151. if (documentFiles == null || documentFiles.isEmpty()) {
  152. return;
  153. }
  154. int wordCount = 0;
  155. int excelCount = 0;
  156. int pptCount = 0;
  157. int pdfCount = 0;
  158. for (FilesSearch.DocumentFile item : documentFiles) {
  159. detectedLastFileName.setValue(item.getName());
  160. if (item.getCategory() == FilesSearch.DocumentFile.WORD) {
  161. wordCount++;
  162. wordList.add(item);
  163. } else if (item.getCategory() == FilesSearch.DocumentFile.EXCEL) {
  164. excelCount++;
  165. excelList.add(item);
  166. } else if (item.getCategory() == FilesSearch.DocumentFile.PPT) {
  167. pptCount++;
  168. pptList.add(item);
  169. } else if (item.getCategory() == FilesSearch.DocumentFile.PDF) {
  170. pdfCount++;
  171. pdfList.add(item);
  172. }
  173. }
  174. if (wordCount > 0) {
  175. detectedWordList.setValue(wordList);
  176. }
  177. if (excelCount > 0) {
  178. detectedExcelList.setValue(excelList);
  179. }
  180. if (pptCount > 0) {
  181. detectedPPTList.setValue(pptList);
  182. }
  183. if (pdfCount > 0) {
  184. detectedPDFList.setValue(pdfList);
  185. }
  186. scrollTop.call();
  187. }
  188. @Override
  189. public void onError(Throwable t) {
  190. showScanDialogEvent.setValue(false);
  191. }
  192. @Override
  193. public void onComplete() {
  194. showScanDialogEvent.setValue(false);
  195. }
  196. });
  197. }
  198. public void cancelScan() {
  199. if (scanDisposable != null && !scanDisposable.isDisposed()) scanDisposable.dispose();
  200. showScanDialogEvent.setValue(false);
  201. }
  202. public void onCheckAllClick(boolean isCheck) {
  203. EventHelper.report(EventId.EVENT_3000006);
  204. int index = BoxingUtil.boxing(checkPosition.getValue());
  205. getCheckAll(index).setValue(isCheck);
  206. int id = tabTitle[index];
  207. List<FilesSearch.DocumentFile> list = null;
  208. if (id == R.string.word) {
  209. list = wordList;
  210. } else if (id == R.string.excel) {
  211. list = excelList;
  212. } else if (id == R.string.ppt) {
  213. list = pptList;
  214. } else if (id == R.string.pdf) {
  215. list = pdfList;
  216. }
  217. if (list == null || list.isEmpty()) {
  218. return;
  219. }
  220. for (FilesSearch.DocumentFile item : list) {
  221. if (item.isCheck() != isCheck) {
  222. if (isCheck) {
  223. selectList.add(item);
  224. } else {
  225. selectList.remove(item);
  226. }
  227. }
  228. item.setCheck(isCheck);
  229. }
  230. this.selectedList.setValue(selectList);
  231. }
  232. public MutableLiveData<Boolean> getCheckAll(int position) {
  233. return checkList.get(position);
  234. }
  235. public void onExportClick() {
  236. if (selectList == null || selectList.isEmpty()) {
  237. return;
  238. }
  239. showUnlockEvent.call();
  240. }
  241. public void doExport() {
  242. Single.just(selectList.size())
  243. .map(oldSize -> {
  244. Iterator<FilesSearch.DocumentFile> iterator = selectList.iterator();
  245. int errorCount = 0;
  246. Exception exception = null;
  247. while (iterator.hasNext()) {
  248. FilesSearch.DocumentFile item = iterator.next();
  249. try {
  250. MediaStoreHelper.saveToSharedStorage(MediaStoreHelper.TYPE_FILES, item.newInputStream(), FileUtil.getCreateFileName(MediaStoreHelper.TYPE_FILES, item.getName()));
  251. item.setCheck(false);
  252. iterator.remove();
  253. } catch (Exception throwable) {
  254. errorCount++;
  255. exception = throwable;
  256. BuglyHelper.postCatchedException(new Exception("文件导出:", throwable));
  257. }
  258. }
  259. if (errorCount == oldSize) {
  260. throw new Exception("导出失败" + (exception == null ? "" : ":" + exception.getMessage()));
  261. } else if (errorCount > 0) {
  262. throw new Exception("部分导出失败" + ":" + exception.getMessage());
  263. }
  264. return errorCount;
  265. })
  266. .compose(RxJavaUtil.SingleSchedule.io2Main())
  267. .subscribe(new SingleObserver<Integer>() {
  268. @Override
  269. public void onSubscribe(@NonNull Disposable d) {
  270. showLoadingEvent.setValue(true);
  271. addDisposable(d);
  272. }
  273. @Override
  274. public void onSuccess(@NonNull Integer integer) {
  275. showLoadingEvent.setValue(false);
  276. selectedList.setValue(selectList);
  277. ToastUtil.show(R.string.export_success, ToastUtil.LENGTH_SHORT);
  278. getCheckAll(BoxingUtil.boxing(checkPosition.getValue())).setValue(false);
  279. AtmobAdHelper.showInterstitial(AdFuncId.INTERSTITIAL_RECOVER_SUCCESS, null);
  280. EventHelper.report(EVENT_3000004);
  281. }
  282. @Override
  283. public void onError(@NonNull Throwable throwable) {
  284. showLoadingEvent.setValue(false);
  285. selectedList.setValue(selectList);
  286. ToastUtil.show(throwable.getMessage(), ToastUtil.LENGTH_SHORT);
  287. }
  288. });
  289. }
  290. public void itemClick(FilesSearch.DocumentFile documentFile) {
  291. if (documentFile == null) {
  292. return;
  293. }
  294. documentFile.setCheck(!documentFile.isCheck());
  295. if (documentFile.isCheck()) {
  296. selectList.add(documentFile);
  297. } else {
  298. selectList.remove(documentFile);
  299. }
  300. this.selectedList.setValue(selectList);
  301. }
  302. public void onTrialRecoverClick() {
  303. MemberActivity.start(ActivityUtil.getTopActivity(), MemberType.APP_FILE_RECOVER);
  304. }
  305. public void onViewTrialRecoverClick() {
  306. MemberActivity.start(ActivityUtil.getTopActivity(), MemberType.APP_FILE_RECOVER);
  307. }
  308. public void scrollPosition(int lastCompletelyItemPosition, int itemCount) {
  309. if (scanDisposable == null || !scanDisposable.isDisposed()) {
  310. return;
  311. }
  312. if (lastCompletelyItemPosition == itemCount - 1 && !BoxingUtil.boxing(showScanDialogEvent.getValue())) {
  313. showTrialFinishDialog.call();
  314. }
  315. }
  316. public void showTrialFinishDialog() {
  317. showTrialFinishDialog.call();
  318. }
  319. }