浏览代码

Added dialog when sync is too heavy for device (unfinished)

Kilian Périsset 5 年之前
父节点
当前提交
8e09c99f1f

+ 182 - 0
src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java

@@ -0,0 +1,182 @@
+/*
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.dialog;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.ActionMode;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ThemeUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+/**
+ *  Dialog requiring confirmation before removing a collection of given OCFiles.
+ *
+ *  Triggers the removal according to the user response.
+ */
+public class SyncFileNotEnoughSpaceDialogFragment extends ConfirmationDialogFragment implements
+        ConfirmationDialogFragmentListener {
+
+    private ActionMode actionMode;
+
+
+    public static SyncFileNotEnoughSpaceDialogFragment newInstance(OCFile file, long availableDeviceSpace,
+                                                                   ActionMode actionMode) {
+        SyncFileNotEnoughSpaceDialogFragment dialogFragment = newInstance(file, availableDeviceSpace);
+        dialogFragment.setActionMode(actionMode);
+        return dialogFragment;
+    }
+
+
+    public static SyncFileNotEnoughSpaceDialogFragment newInstance(OCFile file, long availableDeviceSpace) {
+        SyncFileNotEnoughSpaceDialogFragment frag = new SyncFileNotEnoughSpaceDialogFragment();
+        Bundle args = new Bundle();
+
+
+
+        // ------------------
+        // <EXPORTED>
+        // ------------------
+
+
+/*        String properFileValue = DisplayUtils.bytesToHumanReadable(file.getFileLength());
+        String properDiskValue = DisplayUtils.bytesToHumanReadable(availableDeviceSpace);
+
+        String fileName = file.getFileName();
+
+        android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder();
+
+        // Replace strings by lang-string-xml values
+        builder.setTitle("Not enough space");
+        builder.setMessage(fileName + " is " + properFileValue + " but there is only " + properDiskValue + " " +
+                               "available on device.");
+
+        builder.setPositiveButton("Choose what to synchronize", null);
+        builder.setNeutralButton("Free up space", null);
+        builder.setNegativeButton("Cancel", null);
+
+        android.app.AlertDialog dialog = builder.create();
+        dialog.show();
+     */
+
+        // ------------------
+        // </EXPORTED>
+        // ------------------
+
+        int messageStringId;
+
+
+        boolean containsFolder = false;
+        boolean containsDown = false;
+
+        int localRemoveButton = (containsFolder || containsDown) ? R.string.confirmation_remove_local : -1;
+
+        // Here,
+        /*
+            - Title : Not enough space
+            - Base message  : {0} is {1} but there is only {2} available on device.
+            - Button top - positive : Choose what to sync.
+            - Button mid - neutral : Free up space
+            - Button bot - negative : Cancel
+            - {0} : File name (file.getFileName)
+            - {1} : File size
+            - {2} : Device free space
+         */
+
+        // args.putInt(ARG_MESSAGE_RESOURCE_ID, messageStringId);
+        args.putInt(ARG_POSITIVE_BTN_RES, R.string.file_delete);
+        args.putInt(ARG_NEUTRAL_BTN_RES, R.string.file_keep);
+        args.putInt(ARG_NEGATIVE_BTN_RES, localRemoveButton);
+        frag.setArguments(args);
+
+        return frag;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        int color = ThemeUtils.primaryAccentColor(getActivity());
+
+        AlertDialog alertDialog = (AlertDialog) getDialog();
+
+        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(color);
+        alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(color);
+        alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(color);
+    }
+
+    @NonNull
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Dialog dialog = super.onCreateDialog(savedInstanceState);
+        // mTargetFiles = getArguments().getParcelableArrayList(ARG_TARGET_FILES);
+
+        setOnConfirmationListener(this);
+
+        return dialog;
+    }
+
+    /**
+     * Performs the removal of the target file, both locally and in the server and
+     * finishes the supplied ActionMode if one was given.
+     */
+    @Override
+    public void onConfirmation(String callerTag) {
+        // ONLY IF FOLDER -> GO TO DESTINATION
+    }
+
+    /**
+     * Performs the removal of the local copy of the target file
+     */
+    @Override
+    public void onCancel(String callerTag) {
+        // CANCEL -> CLOSE
+    }
+
+    @Override
+    public void onNeutral(String callerTag) {
+        // WIPE SPACE
+    }
+
+    private void setActionMode(ActionMode actionMode) {
+        this.actionMode = actionMode;
+    }
+
+    /**
+     * This is used when finishing an actionMode,
+     * for example if we want to exit the selection mode
+     * after deleting the target files.
+     */
+    private void finishActionMode() {
+        if (actionMode != null) {
+            actionMode.finish();
+        }
+    }
+}

+ 42 - 1
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -26,7 +26,10 @@ package com.owncloud.android.ui.fragment;
 
 import android.accounts.Account;
 import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -34,6 +37,7 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.view.ActionMode;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -42,6 +46,7 @@ import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
+import android.widget.Button;
 import android.widget.PopupMenu;
 
 import com.google.android.material.snackbar.Snackbar;
@@ -89,6 +94,7 @@ import com.owncloud.android.ui.events.DummyDrawerEvent;
 import com.owncloud.android.ui.events.EncryptionEvent;
 import com.owncloud.android.ui.events.FavoriteEvent;
 import com.owncloud.android.ui.events.SearchEvent;
+import com.owncloud.android.ui.helpers.FileOperationsHelper;
 import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.ui.preview.PreviewMediaFragment;
@@ -107,6 +113,7 @@ import org.parceler.Parcels;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -1114,7 +1121,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
             }
             case R.id.action_download_file:
             case R.id.action_sync_file: {
-                mContainerActivity.getFileOperationsHelper().syncFiles(checkedFiles);
+                this.syncAndCheckFiles(checkedFiles);
                 exitSelectionMode();
                 return true;
             }
@@ -1720,6 +1727,40 @@ public class OCFileListFragment extends ExtendedListFragment implements
             && event.getUnsetType() != null;
     }
 
+    private void syncAndCheckFiles(Collection<OCFile> files) {
+        for (OCFile file : files) {
+            Pair<Boolean, Long> fileSyncResult= FileOperationsHelper.isSpaceEnough(file);
+            if (fileSyncResult.first) {
+                mContainerActivity.getFileOperationsHelper().syncFile(file);
+            } else {
+                showSpaceErrorDialog(file, fileSyncResult.second);
+            }
+
+        }
+    }
+
+    private void showSpaceErrorDialog(OCFile file, long availableDeviceSpace) {
+
+        String properFileValue = DisplayUtils.bytesToHumanReadable(file.getFileLength());
+        String properDiskValue = DisplayUtils.bytesToHumanReadable(availableDeviceSpace);
+
+        String fileName = file.getFileName();
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+        // Replace strings by lang-string-xml values
+        builder.setTitle("Not enough space");
+        builder.setMessage(fileName + " is " + properFileValue + " but there is only " + properDiskValue + " " +
+                               "available on device.");
+
+        builder.setPositiveButton("Choose what to synchronize", null);
+        builder.setNeutralButton("Free up space", null);
+        builder.setNegativeButton("Cancel", null);
+
+        AlertDialog dialog = builder.create();
+        dialog.show();
+    }
+
     @Override
     public boolean isLoading() {
         return false;

+ 19 - 6
src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

@@ -38,9 +38,11 @@ import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Environment;
+import android.os.StatFs;
 import android.provider.MediaStore;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.view.View;
 import android.webkit.MimeTypeMap;
 
@@ -747,12 +749,6 @@ public class FileOperationsHelper {
         sendShareFile(file, !file.canReshare());
     }
 
-    public void syncFiles(Collection<OCFile> files) {
-        for (OCFile file : files) {
-            syncFile(file);
-        }
-    }
-
     public void sendCachedImage(OCFile file, String packageName, String activityName) {
         if (file != null) {
             Context context = MainApp.getAppContext();
@@ -1043,5 +1039,22 @@ public class FileOperationsHelper {
         return new SimpleDateFormat("yyyy-MM-dd_HHmmss", Locale.US).format(new Date()) + ".jpg";
     }
 
+    public static Pair<Boolean, Long> isSpaceEnough(OCFile file) {
+        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
+        long availableBytesOnDevice;
+        if (android.os.Build.VERSION.SDK_INT >=
+            android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            availableBytesOnDevice = stat.getBlockSizeLong() * stat.getAvailableBlocksLong();
+        }
+        else {
+            availableBytesOnDevice = (long) stat.getBlockSize() * (long) stat.getAvailableBlocks();
+        }
+
+        boolean isSpaceEnough = file.getFileLength() < availableBytesOnDevice;
+
+        return new Pair<>(isSpaceEnough, availableBytesOnDevice);
+
+    }
+
 
 }