|
|
@@ -0,0 +1,349 @@
|
|
|
+package com.datarecovery.master.module.audiorecover;
|
|
|
+
|
|
|
+import androidx.lifecycle.LiveData;
|
|
|
+import androidx.lifecycle.MutableLiveData;
|
|
|
+import androidx.lifecycle.Transformations;
|
|
|
+
|
|
|
+import com.atmob.app.lib.base.BaseViewModel;
|
|
|
+import com.atmob.app.lib.livedata.SingleLiveEvent;
|
|
|
+import com.atmob.common.runtime.ContextUtil;
|
|
|
+import com.datarecovery.master.R;
|
|
|
+import com.datarecovery.master.utils.FileUtil;
|
|
|
+import com.datarecovery.master.utils.FilesSearch;
|
|
|
+import com.datarecovery.master.utils.MediaStoreHelper;
|
|
|
+import com.datarecovery.master.utils.ToastUtil;
|
|
|
+
|
|
|
+import org.reactivestreams.Subscriber;
|
|
|
+import org.reactivestreams.Subscription;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.List;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+import javax.inject.Inject;
|
|
|
+
|
|
|
+import atmob.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
|
+import atmob.reactivex.rxjava3.annotations.NonNull;
|
|
|
+import atmob.reactivex.rxjava3.disposables.Disposable;
|
|
|
+import atmob.rxjava.utils.RxJavaUtil;
|
|
|
+import dagger.hilt.android.lifecycle.HiltViewModel;
|
|
|
+
|
|
|
+
|
|
|
+@HiltViewModel
|
|
|
+public class AudioRecoverViewModel extends BaseViewModel {
|
|
|
+
|
|
|
+ private final long SCANNING_COUNTDOWN = 1000 * 60 * 6;
|
|
|
+ private final LiveData<String> selectedCountTxt;
|
|
|
+ private final MutableLiveData<Boolean> checkAll = new MutableLiveData<>(false);
|
|
|
+ private final List<FilesSearch.DocumentFile> originalDetectedList = new ArrayList<>();
|
|
|
+ private final MutableLiveData<List<FilesSearch.DocumentFile>> detectedVideoList = new MutableLiveData<>(new ArrayList<>());
|
|
|
+ private final MutableLiveData<List<FilesSearch.DocumentFile>> selectedList = new MutableLiveData<>(new ArrayList<>());
|
|
|
+ private final SingleLiveEvent<?> detectedFinish = new SingleLiveEvent<>();
|
|
|
+ private final SingleLiveEvent<?> showFilterPopup = new SingleLiveEvent<>();
|
|
|
+ private final SingleLiveEvent<Boolean> showScanDialogEvent = new SingleLiveEvent<>();
|
|
|
+ private final SingleLiveEvent<?> notifyAudioData = new SingleLiveEvent<>();
|
|
|
+ private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
|
|
|
+ private int totalCount = 0;
|
|
|
+ private final MutableLiveData<Integer> totalDetectedCount = new MutableLiveData<>();
|
|
|
+ private final MutableLiveData<Boolean> isDateFilterArrowUp = new MutableLiveData<>(false);
|
|
|
+ private final MutableLiveData<Boolean> isSizeSortArrowUp = new MutableLiveData<>(false);
|
|
|
+ private final MutableLiveData<Integer> dataFilterCondition = new MutableLiveData<>();
|
|
|
+
|
|
|
+ private Disposable scanDisposable;
|
|
|
+
|
|
|
+ private final int[] dateFilterArray = new int[]{
|
|
|
+ R.string.all,
|
|
|
+ R.string.within_a_week,
|
|
|
+ R.string.away_a_week,
|
|
|
+ R.string.a_month_ago,
|
|
|
+ R.string.a_year_ago
|
|
|
+ };
|
|
|
+
|
|
|
+ public LiveData<?> getNotifyAudioData() {
|
|
|
+ return notifyAudioData;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Inject
|
|
|
+ public AudioRecoverViewModel() {
|
|
|
+ selectedCountTxt = Transformations.map(selectedList, list -> {
|
|
|
+ if (list == null || list.isEmpty()) {
|
|
|
+ return ContextUtil.getContext().getString(R.string.export);
|
|
|
+ }
|
|
|
+ return ContextUtil.getContext().getString(R.string.export_count, list.size());
|
|
|
+ });
|
|
|
+ startAudioScanning();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public LiveData<Integer> getDataFilterCondition() {
|
|
|
+ return dataFilterCondition;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<Boolean> getIsDateFilterArrowUp() {
|
|
|
+ return isDateFilterArrowUp;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<Boolean> getIsSizeSortArrowUp() {
|
|
|
+ return isSizeSortArrowUp;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<?> getShowFilterPopup() {
|
|
|
+ return showFilterPopup;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int[] getDateFilterArray() {
|
|
|
+ return dateFilterArray;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<String> getSelectedCountTxt() {
|
|
|
+ return selectedCountTxt;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<?> getDetectedFinish() {
|
|
|
+ return detectedFinish;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<Boolean> getShowLoadingEvent() {
|
|
|
+ return showLoadingEvent;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<Integer> getTotalDetectedCount() {
|
|
|
+ return totalDetectedCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<Boolean> getCheckAll() {
|
|
|
+ return checkAll;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<List<FilesSearch.DocumentFile>> getDetectedVideoList() {
|
|
|
+ return detectedVideoList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<List<FilesSearch.DocumentFile>> getSelectedList() {
|
|
|
+ return selectedList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public LiveData<Boolean> getShowScanDialogEvent() {
|
|
|
+ return showScanDialogEvent;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void startAudioScanning() {
|
|
|
+ FilesSearch.search(ContextUtil.getContext(), FilesSearch.DocumentFile.AUDIO)
|
|
|
+ .take(SCANNING_COUNTDOWN, TimeUnit.MILLISECONDS)
|
|
|
+ .observeOn(AndroidSchedulers.mainThread())
|
|
|
+ .subscribe(new Subscriber<List<FilesSearch.DocumentFile>>() {
|
|
|
+ @Override
|
|
|
+ public void onSubscribe(Subscription s) {
|
|
|
+ s.request(Integer.MAX_VALUE);
|
|
|
+ scanDisposable = Disposable.fromSubscription(s);
|
|
|
+ addDisposable(scanDisposable);
|
|
|
+ showScanDialogEvent.setValue(true);
|
|
|
+ totalCount = 0;
|
|
|
+ totalDetectedCount.setValue(0);
|
|
|
+ getList(detectedVideoList).clear();
|
|
|
+ originalDetectedList.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onNext(List<FilesSearch.DocumentFile> documentFiles) {
|
|
|
+ if (documentFiles == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ totalCount += documentFiles.size();
|
|
|
+ totalDetectedCount.setValue(totalCount);
|
|
|
+ originalDetectedList.addAll(0, documentFiles);
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ list.addAll(0, documentFiles);
|
|
|
+ detectedVideoList.setValue(list);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(Throwable t) {
|
|
|
+ showScanDialogEvent.setValue(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onComplete() {
|
|
|
+ detectedFinish.call();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cancelScan() {
|
|
|
+ if (scanDisposable != null) scanDisposable.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<FilesSearch.DocumentFile> getList(LiveData<List<FilesSearch.DocumentFile>> liveData) {
|
|
|
+ List<FilesSearch.DocumentFile> selectList = liveData.getValue();
|
|
|
+ if (selectList == null) {
|
|
|
+ selectList = new ArrayList<>();
|
|
|
+ }
|
|
|
+ return selectList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void onCheckAllClick(boolean isCheck) {
|
|
|
+ if (!scanDisposable.isDisposed()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ checkAll.setValue(isCheck);
|
|
|
+ List<FilesSearch.DocumentFile> detectedList = getList(detectedVideoList);
|
|
|
+ for (FilesSearch.DocumentFile videoFile : detectedList) {
|
|
|
+ videoFile.setCheck(isCheck);
|
|
|
+ }
|
|
|
+ List<FilesSearch.DocumentFile> selectedList = getList(this.selectedList);
|
|
|
+ if (isCheck) {
|
|
|
+ selectedList.clear();
|
|
|
+ selectedList.addAll(detectedList);
|
|
|
+ } else {
|
|
|
+ selectedList.clear();
|
|
|
+ }
|
|
|
+ this.selectedList.setValue(selectedList);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void onExportClick() {
|
|
|
+ List<FilesSearch.DocumentFile> list = selectedList.getValue();
|
|
|
+ if (list == null || list.size() == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //TODO 判断是否有会员
|
|
|
+ showLoadingEvent.setValue(true);
|
|
|
+ RxJavaUtil.doInBackground(() -> {
|
|
|
+ for (FilesSearch.DocumentFile item : list) {
|
|
|
+ MediaStoreHelper.saveToSharedStorage(MediaStoreHelper.TYPE_AUDIO, item.newInputStream(), FileUtil.getCreateFileName(item.getName(), ""));
|
|
|
+ item.setCheck(false);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }, o -> {
|
|
|
+ checkAll.setValue(false);
|
|
|
+ showLoadingEvent.setValue(false);
|
|
|
+ ToastUtil.show(R.string.export_success, ToastUtil.LENGTH_SHORT);
|
|
|
+ list.clear();
|
|
|
+ selectedList.setValue(list);
|
|
|
+ }, throwable -> {
|
|
|
+ showLoadingEvent.setValue(false);
|
|
|
+ ToastUtil.show(R.string.export_fail, ToastUtil.LENGTH_SHORT);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setItemCheck(@NonNull FilesSearch.DocumentFile file) {
|
|
|
+ file.setCheck(!file.isCheck());
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(selectedList);
|
|
|
+ if (file.isCheck()) {
|
|
|
+ list.add(file);
|
|
|
+ } else {
|
|
|
+ list.remove(file);
|
|
|
+ }
|
|
|
+ selectedList.setValue(list);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void onDateFilterClick() {
|
|
|
+ showFilterPopup.call();
|
|
|
+ isDateFilterArrowUp.setValue(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setIsDateFilterArrowDown() {
|
|
|
+ isDateFilterArrowUp.setValue(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void onSizeSortClick(boolean isUp) {
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ Collections.sort(list, (o1, o2) -> {
|
|
|
+ if (o1.getSize() > o2.getSize()) {
|
|
|
+ return (isUp) ? 1 : -1;
|
|
|
+ } else if (o1.getSize() < o2.getSize()) {
|
|
|
+ return (isUp) ? -1 : 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ });
|
|
|
+ isSizeSortArrowUp.setValue(isUp);
|
|
|
+ notifyAudioData.call();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setFilter(int filterTxtId) {
|
|
|
+ if (filterTxtId == R.string.all) {
|
|
|
+ dataFilterCondition.setValue(null);
|
|
|
+ } else {
|
|
|
+ dataFilterCondition.setValue(filterTxtId);
|
|
|
+ }
|
|
|
+ if (filterTxtId == R.string.all) {
|
|
|
+ getAllList();
|
|
|
+ } else if (filterTxtId == R.string.within_a_week) {
|
|
|
+ getWithinWeekList();
|
|
|
+ } else if (filterTxtId == R.string.away_a_week) {
|
|
|
+ getAwayWeekList();
|
|
|
+ } else if (filterTxtId == R.string.a_month_ago) {
|
|
|
+ getMonthAgoList();
|
|
|
+ } else if (filterTxtId == R.string.a_year_ago) {
|
|
|
+ getYearAgoList();
|
|
|
+ }
|
|
|
+ notifyAudioData.call();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void getAllList() {
|
|
|
+ if (originalDetectedList.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ list.clear();
|
|
|
+ list.addAll(originalDetectedList);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<FilesSearch.DocumentFile> getAwayWeekList() {
|
|
|
+ if (originalDetectedList.isEmpty()) {
|
|
|
+ return originalDetectedList;
|
|
|
+ }
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ list.clear();
|
|
|
+ for (FilesSearch.DocumentFile file : originalDetectedList) {
|
|
|
+ if (file.getLastModified() < System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 7) {
|
|
|
+ list.add(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<FilesSearch.DocumentFile> getYearAgoList() {
|
|
|
+ if (originalDetectedList.isEmpty()) {
|
|
|
+ return originalDetectedList;
|
|
|
+ }
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ list.clear();
|
|
|
+ for (FilesSearch.DocumentFile file : originalDetectedList) {
|
|
|
+ if (file.getLastModified() < System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 365) {
|
|
|
+ list.add(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<FilesSearch.DocumentFile> getMonthAgoList() {
|
|
|
+ if (originalDetectedList.isEmpty()) {
|
|
|
+ return originalDetectedList;
|
|
|
+ }
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ list.clear();
|
|
|
+ for (FilesSearch.DocumentFile file : originalDetectedList) {
|
|
|
+ if (file.getLastModified() < System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30) {
|
|
|
+ list.add(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private List<FilesSearch.DocumentFile> getWithinWeekList() {
|
|
|
+ if (originalDetectedList.isEmpty()) {
|
|
|
+ return originalDetectedList;
|
|
|
+ }
|
|
|
+ List<FilesSearch.DocumentFile> list = getList(detectedVideoList);
|
|
|
+ list.clear();
|
|
|
+ for (FilesSearch.DocumentFile file : originalDetectedList) {
|
|
|
+ if (file.getLastModified() > System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 7) {
|
|
|
+ list.add(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|