Browse Source

增加图片恢复导出功能

zk 1 year ago
parent
commit
bd7dc222a8

+ 3 - 0
app/src/main/AndroidManifest.xml

@@ -56,6 +56,9 @@
         <activity
             android:name=".module.imgrecover.ImageRecoverActivity"
             android:screenOrientation="portrait" />
+        <activity
+            android:name=".module.preview.PreviewActivity"
+            android:screenOrientation="portrait" />
 
     </application>
 

+ 31 - 0
app/src/main/java/com/datarecovery/master/dialog/CommonLoadingDialog.java

@@ -0,0 +1,31 @@
+package com.datarecovery.master.dialog;
+
+import static com.atmob.app.lib.base.BaseDialog.*;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+import com.atmob.app.lib.base.BaseDialog;
+import com.datarecovery.master.R;
+import com.datarecovery.master.databinding.DialogCommonLoadingBinding;
+
+@FullScreen(height = false)
+public class CommonLoadingDialog extends BaseDialog<DialogCommonLoadingBinding> {
+
+    public CommonLoadingDialog(@NonNull Context context) {
+        super(context, R.style.Theme_Common_Dialog);
+        setCancelable(false);
+    }
+
+    public CommonLoadingDialog setMessage(@StringRes int message) {
+        binding.commonLoadingText.setText(message);
+        return this;
+    }
+
+    @Override
+    protected boolean useQueue() {
+        return false;
+    }
+}

+ 9 - 3
app/src/main/java/com/datarecovery/master/module/imgrecover/ImageItemAdapter.java

@@ -75,9 +75,13 @@ public class ImageItemAdapter extends RecyclerView.Adapter<ImageItemAdapter.View
             this.binding = binding;
             binding.setLifecycleOwner(lifecycleOwner);
             binding.setCheckBoxClick(v -> {
-                ImageDeepDetector.ImageFile imageFile = binding.getFile();
                 if (onItemClick != null) {
-                    onItemClick.onClick(imageFile);
+                    onItemClick.onCheck(binding.getFile());
+                }
+            });
+            binding.getRoot().setOnClickListener(v -> {
+                if (onItemClick != null) {
+                    onItemClick.onItemClick(binding.getFile());
                 }
             });
         }
@@ -88,6 +92,8 @@ public class ImageItemAdapter extends RecyclerView.Adapter<ImageItemAdapter.View
     }
 
     public interface onItemClick {
-        void onClick(ImageDeepDetector.ImageFile imageFile);
+        void onCheck(ImageDeepDetector.ImageFile imageFile);
+
+        void onItemClick(ImageDeepDetector.ImageFile imageFile);
     }
 }

+ 24 - 1
app/src/main/java/com/datarecovery/master/module/imgrecover/ImageRecoverActivity.java

@@ -19,8 +19,10 @@ import com.datarecovery.master.R;
 import com.datarecovery.master.databinding.ActivityImageRecoverBinding;
 import com.datarecovery.master.databinding.ItemMainTabLayoutBinding;
 import com.datarecovery.master.databinding.ItemTabImageRecoverBinding;
+import com.datarecovery.master.dialog.CommonLoadingDialog;
 import com.datarecovery.master.dialog.CommonSureDialog;
 import com.datarecovery.master.dialog.ScanProgressDialog;
+import com.datarecovery.master.module.preview.PreviewActivity;
 import com.datarecovery.master.utils.BoxingUtil;
 import com.datarecovery.master.utils.GridLayoutItemDecoration;
 import com.datarecovery.master.utils.GridRecoverItemDecoration;
@@ -40,6 +42,7 @@ public class ImageRecoverActivity extends BaseActivity<ActivityImageRecoverBindi
     private final int[] tabTitle = {R.string.photo, R.string.wx, R.string.qq, R.string.other};
 
     private CommonSureDialog backDialog;
+    private CommonLoadingDialog loadingDialog;
     private ScanProgressDialog scanProgressDialog;
     private ImageItemAdapter photoAdapter;
     private ImageItemAdapter wxAdapter;
@@ -152,13 +155,18 @@ public class ImageRecoverActivity extends BaseActivity<ActivityImageRecoverBindi
     }
 
     @Override
-    public void onClick(ImageDeepDetector.ImageFile imageFile) {
+    public void onCheck(ImageDeepDetector.ImageFile imageFile) {
         if (imageFile == null) {
             return;
         }
         imageRecoverViewModel.setItemCheck(imageFile);
     }
 
+    @Override
+    public void onItemClick(ImageDeepDetector.ImageFile imageFile) {
+        imageRecoverViewModel.checkPreview(imageFile);
+    }
+
     private void initTabLayout() {
         binding.tabLayout.removeAllTabs();
         binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@@ -223,6 +231,8 @@ public class ImageRecoverActivity extends BaseActivity<ActivityImageRecoverBindi
         imageRecoverViewModel.getDetectedQQImg().observe(this, list -> qqAdapter.submit(list));
         imageRecoverViewModel.getDetectedOtherImg().observe(this, list -> otherAdapter.submit(list));
         imageRecoverViewModel.getDetectedFinish().observe(this, o -> scanProgressDialog.detectedFinish());
+        imageRecoverViewModel.getPreviewEvent().observe(this, uri -> PreviewActivity.start(this, PreviewActivity.TYPE_IMG, uri));
+        imageRecoverViewModel.getShowLoadingEvent().observe(this, this::showLoadingDialog);
     }
 
     private void showBackDialog() {
@@ -254,6 +264,19 @@ public class ImageRecoverActivity extends BaseActivity<ActivityImageRecoverBindi
         }
     }
 
+    public void showLoadingDialog(Boolean show) {
+        if (BoxingUtil.boxing(show)) {
+            if (loadingDialog == null) {
+                loadingDialog = new CommonLoadingDialog(this);
+            }
+            loadingDialog.show();
+        } else {
+            if (loadingDialog != null) {
+                loadingDialog.dismiss();
+            }
+        }
+    }
+
     @Override
     public void onBackPressed() {
         showBackDialog();

+ 50 - 0
app/src/main/java/com/datarecovery/master/module/imgrecover/ImageRecoverViewModel.java

@@ -1,5 +1,7 @@
 package com.datarecovery.master.module.imgrecover;
 
+import android.net.Uri;
+
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Transformations;
@@ -9,11 +11,14 @@ import com.atmob.app.lib.livedata.SingleLiveEvent;
 import com.atmob.common.runtime.ContextUtil;
 import com.datarecovery.master.R;
 import com.datarecovery.master.utils.ImageDeepDetector;
+import com.datarecovery.master.utils.MediaStoreHelper;
+import com.datarecovery.master.utils.ToastUtil;
 
 import org.reactivestreams.Subscription;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
@@ -22,6 +27,9 @@ import atmob.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
 import atmob.reactivex.rxjava3.annotations.NonNull;
 import atmob.reactivex.rxjava3.core.FlowableSubscriber;
 import atmob.reactivex.rxjava3.disposables.Disposable;
+import atmob.reactivex.rxjava3.functions.Action;
+import atmob.reactivex.rxjava3.functions.Consumer;
+import atmob.rxjava.utils.RxJavaUtil;
 import dagger.hilt.android.lifecycle.HiltViewModel;
 
 
@@ -40,9 +48,11 @@ public class ImageRecoverViewModel extends BaseViewModel {
     private LiveData<String> detectedQQTitle;
     private LiveData<String> detectedOtherTitle;
 
+    private final SingleLiveEvent<Uri> previewEvent = new SingleLiveEvent<>();
     private final SingleLiveEvent<?> detectedFinish = new SingleLiveEvent<>();
     private final SingleLiveEvent<?> finishEvent = new SingleLiveEvent<>();
     private final SingleLiveEvent<Boolean> showScanDialogEvent = new SingleLiveEvent<>();
+    private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
     private final MutableLiveData<String> barTitle = new MutableLiveData<>();
     private final MutableLiveData<Boolean> checkAll = new MutableLiveData<>();
     //总探测到的图片数量
@@ -60,6 +70,14 @@ public class ImageRecoverViewModel extends BaseViewModel {
         initLiveData();
     }
 
+    public LiveData<Boolean> getShowLoadingEvent() {
+        return showLoadingEvent;
+    }
+
+    public LiveData<Uri> getPreviewEvent() {
+        return previewEvent;
+    }
+
     public LiveData<?> getDetectedFinish() {
         return detectedFinish;
     }
@@ -257,4 +275,36 @@ public class ImageRecoverViewModel extends BaseViewModel {
         }
         selectedList.setValue(list);
     }
+
+    public void checkPreview(@NonNull ImageDeepDetector.ImageFile imageFile) {
+        //TODO 判断是否有会员
+        previewEvent.setValue(imageFile.getUri());
+    }
+
+    public void onExportClick() {
+        List<ImageDeepDetector.ImageFile> list = getList(selectedList);
+        if (list.size() == 0) {
+            return;
+        }
+        //TODO 判断是否有会员
+        showLoadingEvent.setValue(true);
+        RxJavaUtil.doInBackground(() -> {
+            for (ImageDeepDetector.ImageFile item : list) {
+                MediaStoreHelper.saveToSharedStorage(MediaStoreHelper.TYPE_IMAGE, item.newInputStream(), item.getName());
+                item.setCheck(false);
+            }
+            return true;
+        }, o -> {
+            checkAll.setValue(false);
+            showLoadingEvent.setValue(false);
+            ToastUtil.show(R.string.export_success, ToastUtil.LENGTH_SHORT);
+            List<ImageDeepDetector.ImageFile> sList = getList(selectedList);
+            sList.clear();
+            selectedList.setValue(sList);
+        }, throwable -> {
+            showLoadingEvent.setValue(false);
+            ToastUtil.show(R.string.export_fail, ToastUtil.LENGTH_SHORT);
+        });
+    }
+
 }

+ 10 - 2
app/src/main/java/com/datarecovery/master/module/preview/PreviewActivity.java

@@ -32,7 +32,7 @@ public class PreviewActivity extends BaseActivity<ActivityPreviewBinding> {
     @interface Type {
     }
 
-    private static void start(Context context, @Type int type, Uri uri) {
+    public static void start(Context context, @Type int type, Uri uri) {
         Intent intent = new Intent(context, PreviewActivity.class);
         intent.putExtra("type", type);
         intent.putExtra("uri", uri);
@@ -56,9 +56,13 @@ public class PreviewActivity extends BaseActivity<ActivityPreviewBinding> {
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        initView();
+        initIntentData();
+    }
+
+    private void initIntentData() {
         int type = getIntent().getIntExtra("type", 0);
         Uri uri = getIntent().getParcelableExtra("uri");
-
         previewViewModel.setPreviewData(type, uri);
 
         if (type == TYPE_VIDEO || type == TYPE_AUDIO) {
@@ -69,6 +73,10 @@ public class PreviewActivity extends BaseActivity<ActivityPreviewBinding> {
         }
     }
 
+    private void initView() {
+        addTopStatusBarHeight(binding.previewHeader);
+    }
+
     private void initSurfaceView() {
         SurfaceHolder holder = binding.previewVideo.getHolder();
         holder.addCallback(new SurfaceHolder.Callback() {

+ 15 - 1
app/src/main/java/com/datarecovery/master/module/preview/PreviewViewModel.java

@@ -6,6 +6,8 @@ import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
 import com.atmob.app.lib.base.BaseViewModel;
+import com.atmob.common.runtime.ContextUtil;
+import com.datarecovery.master.R;
 
 import javax.inject.Inject;
 
@@ -21,6 +23,7 @@ public class PreviewViewModel extends BaseViewModel {
 
     @Inject
     public PreviewViewModel() {
+
     }
 
     public LiveData<String> getTitle() {
@@ -39,8 +42,19 @@ public class PreviewViewModel extends BaseViewModel {
         return isPlaying;
     }
 
-    public void setPreviewData(int type, Uri uri) {
+    public void setPreviewData(@PreviewActivity.Type int type, Uri uri) {
         this.type.setValue(type);
         this.previewUri.setValue(uri);
+        switch (type) {
+            case PreviewActivity.TYPE_AUDIO:
+                title.setValue(ContextUtil.getContext().getString(R.string.preview_audio));
+                break;
+            case PreviewActivity.TYPE_IMG:
+                title.setValue(ContextUtil.getContext().getString(R.string.preview_img));
+                break;
+            case PreviewActivity.TYPE_VIDEO:
+                title.setValue(ContextUtil.getContext().getString(R.string.preview_video));
+                break;
+        }
     }
 }

BIN
app/src/main/res/drawable-xxhdpi/common_loading.webp


+ 7 - 0
app/src/main/res/drawable/bg_preview_img_bottom.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners
+        android:topLeftRadius="12dp"
+        android:topRightRadius="12dp" />
+    <solid android:color="@color/white" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/dialog_loading_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="20dp" />
+    <solid android:color="@color/black70" />
+</shape>

+ 12 - 0
app/src/main/res/drawable/progress_common_loading.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+            android:drawable="@drawable/common_loading"
+            android:fromDegrees="0"
+            android:pivotX="50.0%"
+            android:pivotY="50.0%"
+            android:toDegrees="720" />
+        <span style="white-space:pre" />
+    </item>
+</layer-list>

+ 1 - 0
app/src/main/res/layout/activity_image_recover.xml

@@ -73,6 +73,7 @@
             android:layout_height="0dp"
             android:background="@{imageRecoverViewModel.selectedList.size() > 0 ? @drawable/bg_common_btn : @drawable/bg_common_disable_btn}"
             android:gravity="center"
+            android:onClick="@{()->imageRecoverViewModel.onExportClick()}"
             android:text="@{imageRecoverViewModel.selectedCountTxt}"
             android:textColor="@color/white"
             android:textSize="16sp"

+ 114 - 3
app/src/main/res/layout/activity_preview.xml

@@ -47,7 +47,7 @@
             android:id="@+id/preview_image"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:scaleType="fitXY"
+            android:scaleType="fitCenter"
             app:imageUri="@{previewViewModel.previewUri}"
             app:isGone="@{previewViewModel.type != PreviewActivity.TYPE_IMG}"
             app:layout_constraintBottom_toBottomOf="@id/preview_background"
@@ -115,10 +115,121 @@
             app:layout_constraintRight_toRightOf="@id/preview_audio_background"
             app:layout_constraintTop_toTopOf="@id/preview_audio_play" />
 
-        <androidx.coordinatorlayout.widget.CoordinatorLayout
+        <androidx.constraintlayout.widget.ConstraintLayout
             android:id="@+id/preview_bottom"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            app:layout_constraintBottom_toBottomOf="parent" />
+            app:layout_constraintBottom_toBottomOf="parent">
+
+            <View
+                android:id="@+id/v_bottom"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:background="@color/white"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintDimensionRatio="360:72" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:background="@drawable/bg_common_btn"
+                android:gravity="center"
+                android:text="@string/export"
+                android:textColor="@color/white"
+                android:textSize="16sp"
+                android:textStyle="bold"
+                app:layout_constraintBottom_toBottomOf="@id/v_bottom"
+                app:layout_constraintDimensionRatio="328:44"
+                app:layout_constraintEnd_toEndOf="@+id/v_bottom"
+                app:layout_constraintStart_toStartOf="@id/v_bottom"
+                app:layout_constraintTop_toTopOf="@id/v_bottom"
+                app:layout_constraintWidth_percent="0.9111111111111111" />
+
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                app:isGone="@{previewViewModel.type != PreviewActivity.TYPE_IMG}"
+                app:layout_constraintBottom_toTopOf="@+id/v_bottom">
+
+                <View
+                    android:id="@+id/v_preview_img_bottom"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:background="@drawable/bg_preview_img_bottom"
+                    app:layout_constraintDimensionRatio="360:103"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <TextView
+                    android:id="@+id/tv_preview_img_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                    android:text="@string/preview_img_create_time"
+                    android:textColor="#A7A7A7"
+                    android:textSize="12sp"
+                    app:layout_constraintBottom_toBottomOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintStart_toStartOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintTop_toTopOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintVertical_bias="0.1627906976744186" />
+
+
+                <TextView
+                    android:id="@+id/tv_preview_file_type"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                    android:text="@string/preview_img_file_type"
+                    android:textColor="#A7A7A7"
+                    android:textSize="12sp"
+                    app:layout_constraintBottom_toBottomOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintStart_toStartOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintTop_toTopOf="@+id/v_preview_img_bottom" />
+
+                <TextView
+                    android:id="@+id/tv_preview_file_size"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/app_common_page_horizontal_padding"
+                    android:text="@string/preview_img_file_size"
+                    android:textColor="#A7A7A7"
+                    android:textSize="12sp"
+                    app:layout_constraintBottom_toBottomOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintStart_toStartOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintTop_toTopOf="@+id/v_preview_img_bottom"
+                    app:layout_constraintVertical_bias="0.8372093023255814" />
+
+                <TextView
+                    app:layout_constraintStart_toEndOf="@+id/tv_preview_img_name"
+                    app:layout_constraintBaseline_toBaselineOf="@+id/tv_preview_img_name"
+                    android:textColor="#404040"
+                    android:textSize="12sp"
+                    android:layout_marginStart="12dp"
+                    tools:text="2023-06-26  16:21"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    app:layout_constraintStart_toEndOf="@+id/tv_preview_file_type"
+                    app:layout_constraintBaseline_toBaselineOf="@+id/tv_preview_file_type"
+                    android:textColor="#404040"
+                    android:textSize="12sp"
+                    android:layout_marginStart="12dp"
+                    tools:text="PNG"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    app:layout_constraintStart_toEndOf="@+id/tv_preview_file_size"
+                    app:layout_constraintBaseline_toBaselineOf="@+id/tv_preview_file_size"
+                    android:textColor="#404040"
+                    android:textSize="12sp"
+                    android:layout_marginStart="12dp"
+                    tools:text="14.10KB"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+            </androidx.constraintlayout.widget.ConstraintLayout>
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
     </androidx.constraintlayout.widget.ConstraintLayout>
 </layout>

+ 47 - 0
app/src/main/res/layout/dialog_common_loading.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+
+    <View
+        android:id="@+id/common_loading_bg"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:background="@drawable/dialog_loading_bg"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintDimensionRatio="1:1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintWidth_percent="0.3333333333333333" />
+
+    <ProgressBar
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:indeterminate="true"
+        android:indeterminateDrawable="@drawable/progress_common_loading"
+        app:layout_constraintBottom_toBottomOf="@+id/common_loading_bg"
+        app:layout_constraintDimensionRatio="1:1"
+        app:layout_constraintEnd_toEndOf="@+id/common_loading_bg"
+        app:layout_constraintStart_toStartOf="@+id/common_loading_bg"
+        app:layout_constraintTop_toTopOf="@+id/common_loading_bg"
+        app:layout_constraintVertical_bias="0.3448275862068966"
+        app:layout_constraintWidth_percent="0.0916666666666667" />
+
+    <TextView
+        android:id="@+id/common_loading_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/loading_txt"
+        android:textColor="@color/white"
+        android:textSize="14sp"
+        app:layout_constraintBottom_toBottomOf="@+id/common_loading_bg"
+        app:layout_constraintEnd_toEndOf="@+id/common_loading_bg"
+        app:layout_constraintStart_toStartOf="@+id/common_loading_bg"
+        app:layout_constraintTop_toTopOf="@+id/common_loading_bg"
+        app:layout_constraintVertical_bias="0.696969696969697" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 9 - 0
app/src/main/res/values/strings.xml

@@ -98,4 +98,13 @@
     <string name="recover_img_label_text">%s %s</string>
     <string name="dialog_item">项</string>
     <string name="percentage">%s%%</string>
+    <string name="preview_audio">音频播放</string>
+    <string name="preview_img">图片预览</string>
+    <string name="preview_video">视频预览</string>
+    <string name="export_success">导出成功</string>
+    <string name="export_fail">导出失败</string>
+    <string name="loading_txt">加载中…</string>
+    <string name="preview_img_create_time">创建时间</string>
+    <string name="preview_img_file_type">文件类型</string>
+    <string name="preview_img_file_size">文件大小</string>
 </resources>