mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 05:35:39 +03:00
Added dialog when sync is too heavy for device (unfinished)
This commit is contained in:
parent
3b49f56d15
commit
8e09c99f1f
3 changed files with 243 additions and 7 deletions
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,10 @@ package com.owncloud.android.ui.fragment;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
@ -34,6 +37,7 @@ import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -42,6 +46,7 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
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.EncryptionEvent;
|
||||||
import com.owncloud.android.ui.events.FavoriteEvent;
|
import com.owncloud.android.ui.events.FavoriteEvent;
|
||||||
import com.owncloud.android.ui.events.SearchEvent;
|
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.interfaces.OCFileListFragmentInterface;
|
||||||
import com.owncloud.android.ui.preview.PreviewImageFragment;
|
import com.owncloud.android.ui.preview.PreviewImageFragment;
|
||||||
import com.owncloud.android.ui.preview.PreviewMediaFragment;
|
import com.owncloud.android.ui.preview.PreviewMediaFragment;
|
||||||
|
@ -107,6 +113,7 @@ import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -1114,7 +1121,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
||||||
}
|
}
|
||||||
case R.id.action_download_file:
|
case R.id.action_download_file:
|
||||||
case R.id.action_sync_file: {
|
case R.id.action_sync_file: {
|
||||||
mContainerActivity.getFileOperationsHelper().syncFiles(checkedFiles);
|
this.syncAndCheckFiles(checkedFiles);
|
||||||
exitSelectionMode();
|
exitSelectionMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1720,6 +1727,40 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
||||||
&& event.getUnsetType() != null;
|
&& 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
|
@Override
|
||||||
public boolean isLoading() {
|
public boolean isLoading() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -38,9 +38,11 @@ import android.content.pm.ResolveInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.StatFs;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
|
@ -747,12 +749,6 @@ public class FileOperationsHelper {
|
||||||
sendShareFile(file, !file.canReshare());
|
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) {
|
public void sendCachedImage(OCFile file, String packageName, String activityName) {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
Context context = MainApp.getAppContext();
|
Context context = MainApp.getAppContext();
|
||||||
|
@ -1043,5 +1039,22 @@ public class FileOperationsHelper {
|
||||||
return new SimpleDateFormat("yyyy-MM-dd_HHmmss", Locale.US).format(new Date()) + ".jpg";
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue