Add trashbin support
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
fd9e468e93
commit
f8801115f2
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16">
|
||||
<path
|
||||
d="m9.025 1.08c-3.95 0-6.535 3.447-6.364 6.72h-2.161l3.904 3.92 4.08-3.874h-2.147c-0.237-1.7 1.163-3.114 2.689-3.092 1.595 0.024 2.8 1.23 2.8 2.734 0.09 1.594-1.63 3.428-3.966 2.53 0 1.23 0.003 2.545 0 3.765 4.19 0.83 7.64-2.51 7.64-6.25 0-3.563-2.92-6.453-6.475-6.453z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 396 B |
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
viewbox="0 0 16 16"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg4"
|
||||
sodipodi:docname="ic_delete.svg"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8"/>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="835"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="-3.8305085"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4"/>
|
||||
<path
|
||||
d="M6.5 1L6 2H3c-.554 0-1 .446-1 1v1h12V3c0-.554-.446-1-1-1h-3l-.5-1zM3 5l.875 9c.06.55.573 1 1.125 1h6c.552 0 1.064-.45 1.125-1L13 5z"
|
||||
id="path2"
|
||||
style="fill:#c4c4c4;fill-opacity:1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -109,7 +109,7 @@ public class OCFileUnitTest {
|
|||
assertThat(fileReadFromParcel.getFileId(), is(ID));
|
||||
assertThat(fileReadFromParcel.getParentId(), is(PARENT_ID));
|
||||
assertThat(fileReadFromParcel.getStoragePath(), is(STORAGE_PATH));
|
||||
assertThat(fileReadFromParcel.getMimetype(), is(MIME_TYPE));
|
||||
assertThat(fileReadFromParcel.getMimeType(), is(MIME_TYPE));
|
||||
assertThat(fileReadFromParcel.getFileLength(), is(FILE_LENGTH));
|
||||
assertThat(fileReadFromParcel.getCreationTimestamp(), is(CREATION_TIMESTAMP));
|
||||
assertThat(fileReadFromParcel.getModificationTimestamp(), is(MODIFICATION_TIMESTAMP));
|
||||
|
|
|
@ -250,6 +250,9 @@
|
|||
|
||||
<activity android:name=".ui.errorhandling.ErrorShowActivity" />
|
||||
<activity android:name=".ui.activity.UploadListActivity" />
|
||||
<activity
|
||||
android:name=".ui.trashbin.TrashbinActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"/>
|
||||
<activity android:name=".ui.activity.WhatsNewActivity"
|
||||
android:theme="@style/Theme.ownCloud.noActionBar.Login" />
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ public class FileDataStorageManager {
|
|||
);
|
||||
cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
|
||||
cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
|
||||
cv.put(ProviderTableMeta.FILE_ENCRYPTED_NAME, file.getEncryptedFileName());
|
||||
cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
|
||||
|
@ -430,7 +430,7 @@ public class FileDataStorageManager {
|
|||
);
|
||||
cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimeType());
|
||||
cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
|
||||
cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
|
||||
cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
|
||||
|
@ -455,7 +455,7 @@ public class FileDataStorageManager {
|
|||
cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
|
||||
cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
|
||||
cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
|
||||
cv.put(ProviderTableMeta.FILE_ENCRYPTED_NAME, file.getEncryptedFileName());
|
||||
cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
|
||||
|
@ -1367,7 +1367,7 @@ public class FileDataStorageManager {
|
|||
);
|
||||
cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
|
||||
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
|
||||
cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
|
||||
cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
|
||||
cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
|
||||
|
|
|
@ -35,13 +35,14 @@ import com.owncloud.android.R;
|
|||
import com.owncloud.android.lib.common.network.WebdavEntry;
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ServerFileInterface;
|
||||
import com.owncloud.android.utils.MimeType;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import third_parties.daveKoeller.AlphanumComparator;
|
||||
|
||||
public class OCFile implements Parcelable, Comparable<OCFile> {
|
||||
public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterface {
|
||||
|
||||
public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
|
||||
|
||||
|
@ -466,7 +467,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
|
|||
Log_OC.d(TAG, "OCFile name changing from " + mRemotePath);
|
||||
if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) &&
|
||||
!mRemotePath.equals(ROOT_PATH)) {
|
||||
String parent = (new File(getRemotePath())).getParent();
|
||||
String parent = (new File(this.getRemotePath())).getParent();
|
||||
parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
|
||||
mRemotePath = parent + name;
|
||||
if (isFolder()) {
|
||||
|
@ -485,11 +486,12 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Can be used to get the Mimetype
|
||||
* Can be used to get the MimeType
|
||||
*
|
||||
* @return the Mimetype as a String
|
||||
* @return the MimeType as a String
|
||||
*/
|
||||
public String getMimetype() {
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return mMimeType;
|
||||
}
|
||||
|
||||
|
@ -585,7 +587,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
|
|||
* @return remote path
|
||||
*/
|
||||
public String getParentRemotePath() {
|
||||
String parentPath = new File(getRemotePath()).getParent();
|
||||
String parentPath = new File(this.getRemotePath()).getParent();
|
||||
return (parentPath.endsWith("/")) ? parentPath : (parentPath + "/");
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ import com.owncloud.android.lib.common.OwnCloudClient;
|
|||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ServerFileInterface;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
||||
import com.owncloud.android.ui.TextDrawable;
|
||||
import com.owncloud.android.ui.adapter.DiskLruImageCache;
|
||||
|
@ -272,7 +274,7 @@ public class ThumbnailsCacheManager {
|
|||
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
if (file.getMimeType().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
bitmap = handlePNG(bitmap, pxW, pxH);
|
||||
}
|
||||
|
||||
|
@ -304,7 +306,7 @@ public class ThumbnailsCacheManager {
|
|||
}
|
||||
|
||||
// Handle PNG
|
||||
if (thumbnail != null && file.getMimetype().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
if (thumbnail != null && file.getMimeType().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
thumbnail = handlePNG(thumbnail, thumbnail.getWidth(), thumbnail.getHeight());
|
||||
}
|
||||
|
||||
|
@ -446,10 +448,10 @@ public class ThumbnailsCacheManager {
|
|||
mFile = object.getFile();
|
||||
mImageKey = object.getImageKey();
|
||||
|
||||
if (mFile instanceof OCFile) {
|
||||
if (mFile instanceof ServerFileInterface) {
|
||||
thumbnail = doThumbnailFromOCFileInBackground();
|
||||
|
||||
if (MimeTypeUtil.isVideo((OCFile) mFile) && thumbnail != null) {
|
||||
if (MimeTypeUtil.isVideo((ServerFileInterface) mFile) && thumbnail != null) {
|
||||
thumbnail = addVideoOverlay(thumbnail);
|
||||
}
|
||||
} else if (mFile instanceof File) {
|
||||
|
@ -484,6 +486,8 @@ public class ThumbnailsCacheManager {
|
|||
tagId = String.valueOf(((OCFile)mFile).getFileId());
|
||||
} else if (mFile instanceof File) {
|
||||
tagId = String.valueOf(mFile.hashCode());
|
||||
} else if (mFile instanceof TrashbinFile) {
|
||||
tagId = String.valueOf(((TrashbinFile) mFile).getRemoteId());
|
||||
}
|
||||
if (String.valueOf(imageView.getTag()).equals(tagId)) {
|
||||
imageView.setImageBitmap(bitmap);
|
||||
|
@ -498,40 +502,44 @@ public class ThumbnailsCacheManager {
|
|||
|
||||
private Bitmap doThumbnailFromOCFileInBackground() {
|
||||
Bitmap thumbnail;
|
||||
OCFile file = (OCFile) mFile;
|
||||
ServerFileInterface file = (ServerFileInterface) mFile;
|
||||
String imageKey = PREFIX_THUMBNAIL + String.valueOf(file.getRemoteId());
|
||||
|
||||
// Check disk cache in background thread
|
||||
thumbnail = getBitmapFromDiskCache(imageKey);
|
||||
|
||||
// Not found in disk cache
|
||||
if (thumbnail == null || file.needsUpdateThumbnail()) {
|
||||
if (thumbnail == null || (file instanceof OCFile && ((OCFile) file).needsUpdateThumbnail())) {
|
||||
int pxW;
|
||||
int pxH;
|
||||
pxW = pxH = getThumbnailDimension();
|
||||
|
||||
if (file.isDown()) {
|
||||
Bitmap bitmap;
|
||||
if (MimeTypeUtil.isVideo(file)) {
|
||||
bitmap = ThumbnailUtils.createVideoThumbnail(file.getStoragePath(),
|
||||
MediaStore.Images.Thumbnails.MINI_KIND);
|
||||
} else {
|
||||
bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getStoragePath(), pxW, pxH);
|
||||
}
|
||||
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
bitmap = handlePNG(bitmap, pxW, pxH);
|
||||
if (file instanceof OCFile) {
|
||||
OCFile ocFile = (OCFile) file;
|
||||
if (ocFile.isDown()) {
|
||||
Bitmap bitmap;
|
||||
if (MimeTypeUtil.isVideo(ocFile)) {
|
||||
bitmap = ThumbnailUtils.createVideoThumbnail(ocFile.getStoragePath(),
|
||||
MediaStore.Images.Thumbnails.MINI_KIND);
|
||||
} else {
|
||||
bitmap = BitmapUtils.decodeSampledBitmapFromFile(ocFile.getStoragePath(), pxW, pxH);
|
||||
}
|
||||
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH);
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (ocFile.getMimeType().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
bitmap = handlePNG(bitmap, pxW, pxH);
|
||||
}
|
||||
|
||||
file.setNeedsUpdateThumbnail(false);
|
||||
mStorageManager.saveFile(file);
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, ocFile.getStoragePath(), pxW, pxH);
|
||||
|
||||
ocFile.setNeedsUpdateThumbnail(false);
|
||||
mStorageManager.saveFile(ocFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (thumbnail == null) {
|
||||
// check if resized version is available
|
||||
String resizedImageKey = PREFIX_RESIZED_IMAGE + String.valueOf(file.getRemoteId());
|
||||
Bitmap resizedImage = getBitmapFromDiskCache(resizedImageKey);
|
||||
|
@ -544,8 +552,15 @@ public class ThumbnailsCacheManager {
|
|||
getMethod = null;
|
||||
try {
|
||||
// thumbnail
|
||||
String uri = mClient.getBaseUri() + "/index.php/apps/files/api/v1/thumbnail/" +
|
||||
pxW + "/" + pxH + Uri.encode(file.getRemotePath(), "/");
|
||||
String uri;
|
||||
if (file instanceof OCFile) {
|
||||
uri = mClient.getBaseUri() + "/index.php/apps/files/api/v1/thumbnail/" +
|
||||
pxW + "/" + pxH + Uri.encode(file.getRemotePath(), "/");
|
||||
} else {
|
||||
uri = mClient.getBaseUri() + "/index.php/apps/files_trashbin/ajax/preview.php?x="
|
||||
+ pxW + "&y=" + pxH + "&file=" + Uri.encode(file.getRemotePath());
|
||||
}
|
||||
|
||||
Log_OC.d(TAG, "generate thumbnail: " + file.getFileName() +
|
||||
" URI: " + uri);
|
||||
getMethod = new GetMethod(uri);
|
||||
|
@ -565,7 +580,7 @@ public class ThumbnailsCacheManager {
|
|||
}
|
||||
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
if (file.getMimeType().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
thumbnail = handlePNG(thumbnail, pxW, pxH);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -1154,7 +1169,7 @@ public class ThumbnailsCacheManager {
|
|||
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
if (file.getMimeType().equalsIgnoreCase(PNG_MIMETYPE)) {
|
||||
bitmap = handlePNG(bitmap, pxW, pxH);
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ public class DownloadFileOperation extends RemoteOperation {
|
|||
}
|
||||
|
||||
public String getMimeType() {
|
||||
String mimeType = mFile.getMimetype();
|
||||
String mimeType = mFile.getMimeType();
|
||||
if (mimeType == null || mimeType.length() <= 0) {
|
||||
try {
|
||||
mimeType = MimeTypeMap.getSingleton()
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.operations;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Empty trashbin.
|
||||
*/
|
||||
public class EmptyTrashbinFileOperation extends SyncOperation {
|
||||
|
||||
private static final String TAG = EmptyTrashbinFileOperation.class.getSimpleName();
|
||||
private static final int RESTORE_READ_TIMEOUT = 30000;
|
||||
private static final int RESTORE_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param userId to access correct trashbin
|
||||
*/
|
||||
public EmptyTrashbinFileOperation(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote Nextcloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
|
||||
RemoteOperationResult result;
|
||||
try {
|
||||
DeleteMethod delete = new DeleteMethod(client.getNewWebdavUri(false) + "/trashbin/" + userId + "/trash");
|
||||
int status = client.executeMethod(delete, RESTORE_READ_TIMEOUT, RESTORE_CONNECTION_TIMEOUT);
|
||||
|
||||
result = new RemoteOperationResult(isSuccess(status), delete);
|
||||
|
||||
client.exhaustResponse(delete.getResponseBodyAsStream());
|
||||
} catch (IOException e) {
|
||||
result = new RemoteOperationResult(e);
|
||||
Log.e(TAG, "Empty trashbin failed: " + result.getLogMessage(), e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return status == HttpStatus.SC_NO_CONTENT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.operations;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Restore a {@link com.owncloud.android.lib.resources.files.TrashbinFile}.
|
||||
*/
|
||||
public class RestoreTrashbinFileOperation extends SyncOperation {
|
||||
|
||||
private static final String TAG = RestoreTrashbinFileOperation.class.getSimpleName();
|
||||
private static final int RESTORE_READ_TIMEOUT = 30000;
|
||||
private static final int RESTORE_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String sourcePath;
|
||||
private String fileName;
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sourcePath Remote path of the {@link com.owncloud.android.lib.resources.files.TrashbinFile} to restore
|
||||
* @param fileName original filename
|
||||
* @param userId userId to access correct trashbin
|
||||
*/
|
||||
public RestoreTrashbinFileOperation(String sourcePath, String fileName, String userId) {
|
||||
this.sourcePath = sourcePath;
|
||||
this.fileName = fileName;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
|
||||
RemoteOperationResult result;
|
||||
try {
|
||||
String source = client.getNewWebdavUri(false) + WebdavUtils.encodePath(sourcePath);
|
||||
String target = client.getNewWebdavUri(false) + "/trashbin/" + userId + "/restore/" + fileName;
|
||||
|
||||
MoveMethod move = new MoveMethod(source, target, true);
|
||||
int status = client.executeMethod(move, RESTORE_READ_TIMEOUT, RESTORE_CONNECTION_TIMEOUT);
|
||||
|
||||
result = new RemoteOperationResult(isSuccess(status), move);
|
||||
|
||||
client.exhaustResponse(move.getResponseBodyAsStream());
|
||||
} catch (IOException e) {
|
||||
result = new RemoteOperationResult(e);
|
||||
Log.e(TAG, "Restore trashbin file " + sourcePath + " failed: " + result.getLogMessage(), e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
|
||||
}
|
||||
}
|
|
@ -268,7 +268,7 @@ public class UploadFileOperation extends SyncOperation {
|
|||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mFile.getMimetype();
|
||||
return mFile.getMimeType();
|
||||
}
|
||||
|
||||
public int getLocalBehaviour() {
|
||||
|
@ -581,11 +581,11 @@ public class UploadFileOperation extends SyncOperation {
|
|||
/// perform the upload
|
||||
if (mChunked && (size > ChunkedUploadRemoteFileOperation.CHUNK_SIZE)) {
|
||||
mUploadOperation = new ChunkedUploadRemoteFileOperation(mContext, encryptedTempFile.getAbsolutePath(),
|
||||
mFile.getParentRemotePath() + encryptedFileName, mFile.getMimetype(),
|
||||
mFile.getParentRemotePath() + encryptedFileName, mFile.getMimeType(),
|
||||
mFile.getEtagInConflict(), timeStamp);
|
||||
} else {
|
||||
mUploadOperation = new UploadRemoteFileOperation(encryptedTempFile.getAbsolutePath(),
|
||||
mFile.getParentRemotePath() + encryptedFileName, mFile.getMimetype(),
|
||||
mFile.getParentRemotePath() + encryptedFileName, mFile.getMimeType(),
|
||||
mFile.getEtagInConflict(), timeStamp);
|
||||
}
|
||||
|
||||
|
@ -611,7 +611,7 @@ public class UploadFileOperation extends SyncOperation {
|
|||
DecryptedFolderMetadata.DecryptedFile decryptedFile = new DecryptedFolderMetadata.DecryptedFile();
|
||||
DecryptedFolderMetadata.Data data = new DecryptedFolderMetadata.Data();
|
||||
data.setFilename(mFile.getFileName());
|
||||
data.setMimetype(mFile.getMimetype());
|
||||
data.setMimetype(mFile.getMimeType());
|
||||
data.setKey(EncryptionUtils.encodeBytesToBase64String(key));
|
||||
|
||||
decryptedFile.setEncrypted(data);
|
||||
|
@ -822,10 +822,10 @@ public class UploadFileOperation extends SyncOperation {
|
|||
// perform the upload
|
||||
if (mChunked && (size > ChunkedUploadRemoteFileOperation.CHUNK_SIZE)) {
|
||||
mUploadOperation = new ChunkedUploadRemoteFileOperation(mContext, mFile.getStoragePath(),
|
||||
mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp);
|
||||
mFile.getRemotePath(), mFile.getMimeType(), mFile.getEtagInConflict(), timeStamp);
|
||||
} else {
|
||||
mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(),
|
||||
mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp);
|
||||
mFile.getRemotePath(), mFile.getMimeType(), mFile.getEtagInConflict(), timeStamp);
|
||||
}
|
||||
|
||||
Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
|
||||
|
@ -1055,7 +1055,7 @@ public class UploadFileOperation extends SyncOperation {
|
|||
OCFile newFile = new OCFile(newRemotePath);
|
||||
newFile.setCreationTimestamp(mFile.getCreationTimestamp());
|
||||
newFile.setFileLength(mFile.getFileLength());
|
||||
newFile.setMimetype(mFile.getMimetype());
|
||||
newFile.setMimetype(mFile.getMimeType());
|
||||
newFile.setModificationTimestamp(mFile.getModificationTimestamp());
|
||||
newFile.setModificationTimestampAtLastSyncForData(
|
||||
mFile.getModificationTimestampAtLastSyncForData()
|
||||
|
|
|
@ -105,7 +105,7 @@ public class DiskLruImageCacheFileProvider extends ContentProvider {
|
|||
@Override
|
||||
public String getType(@NonNull Uri uri) {
|
||||
OCFile ocFile = getFile(uri);
|
||||
return ocFile.getMimetype();
|
||||
return ocFile.getMimeType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -63,6 +63,7 @@ import com.owncloud.android.authentication.AccountUtils;
|
|||
import com.owncloud.android.authentication.PassCodeManager;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.ExternalLinksProvider;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.ExternalLink;
|
||||
import com.owncloud.android.lib.common.ExternalLinkType;
|
||||
|
@ -86,6 +87,7 @@ import com.owncloud.android.ui.events.ChangeMenuEvent;
|
|||
import com.owncloud.android.ui.events.DummyDrawerEvent;
|
||||
import com.owncloud.android.ui.events.MenuItemClickEvent;
|
||||
import com.owncloud.android.ui.events.SearchEvent;
|
||||
import com.owncloud.android.ui.trashbin.TrashbinActivity;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.FilesSyncHelper;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
@ -349,6 +351,14 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
|
|||
navigationView.getMenu().removeItem(R.id.nav_videos);
|
||||
}
|
||||
|
||||
if (getAccount() != null) {
|
||||
FileDataStorageManager storageManager = new FileDataStorageManager(getAccount(), getContentResolver());
|
||||
OCCapability capability = storageManager.getCapability(getAccount().name);
|
||||
if (capability.getFilesUndelete().isFalse() || capability.getFilesUndelete().isUnknown()) {
|
||||
navigationView.getMenu().removeItem(R.id.nav_trashbin);
|
||||
}
|
||||
}
|
||||
|
||||
if (getResources().getBoolean(R.bool.use_home) && navigationView.getMenu().findItem(R.id.nav_all_files) !=
|
||||
null) {
|
||||
navigationView.getMenu().findItem(R.id.nav_all_files).setTitle(getResources().
|
||||
|
@ -445,6 +455,11 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
|
|||
uploadListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(uploadListIntent);
|
||||
break;
|
||||
case R.id.nav_trashbin:
|
||||
Intent trashbinIntent = new Intent(getApplicationContext(), TrashbinActivity.class);
|
||||
trashbinIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(trashbinIntent);
|
||||
break;
|
||||
case R.id.nav_activity:
|
||||
Intent activityIntent = new Intent(getApplicationContext(), ActivitiesActivity.class);
|
||||
activityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
|
|
@ -508,7 +508,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
updateActionBarTitleAndHomeButton(file);
|
||||
} else {
|
||||
cleanSecondFragment();
|
||||
if (file.isDown() && MimeTypeUtil.isVCard(file.getMimetype())) {
|
||||
if (file.isDown() && MimeTypeUtil.isVCard(file.getMimeType())) {
|
||||
startContactListFragment(file);
|
||||
} else if (file.isDown() && PreviewTextFragment.canBePreviewed(file)) {
|
||||
startTextPreview(file, false);
|
||||
|
@ -738,7 +738,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) {
|
||||
startMediaPreview(mWaitingToPreview, 0, true, true);
|
||||
detailsFragmentChanged = true;
|
||||
} else if (MimeTypeUtil.isVCard(mWaitingToPreview.getMimetype())) {
|
||||
} else if (MimeTypeUtil.isVCard(mWaitingToPreview.getMimeType())) {
|
||||
startContactListFragment(mWaitingToPreview);
|
||||
detailsFragmentChanged = true;
|
||||
} else if (PreviewTextFragment.canBePreviewed(mWaitingToPreview)) {
|
||||
|
@ -2235,7 +2235,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
private void sendDownloadedFile(String packageName, String activityName) {
|
||||
if (mWaitingToSend != null) {
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.setType(mWaitingToSend.getMimetype());
|
||||
sendIntent.setType(mWaitingToSend.getMimeType());
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, mWaitingToSend.getExposedFileUri(this));
|
||||
sendIntent.putExtra(Intent.ACTION_SEND, true);
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
.error(placeholder).into(fileIcon); // using custom fetcher
|
||||
|
||||
} else {
|
||||
fileIcon.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(), context));
|
||||
fileIcon.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), context));
|
||||
}
|
||||
} else {
|
||||
// Folder
|
||||
|
|
|
@ -398,11 +398,11 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
}
|
||||
}
|
||||
|
||||
if (file.getMimetype().equalsIgnoreCase("image/png")) {
|
||||
if (file.getMimeType().equalsIgnoreCase("image/png")) {
|
||||
thumbnailView.setBackgroundColor(mContext.getResources().getColor(R.color.background_color));
|
||||
}
|
||||
} else {
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(),
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(),
|
||||
mAccount, mContext));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.db.PreferenceManager;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
import com.owncloud.android.ui.interfaces.TrashbinActivityInterface;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.FileSortOrder;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
/**
|
||||
* Adapter for the trashbin view
|
||||
*/
|
||||
|
||||
public class TrashbinListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int TRASHBIN_ITEM = 100;
|
||||
private static final int TRASHBIN_FOOTER = 101;
|
||||
private static final String TAG = TrashbinListAdapter.class.getSimpleName();
|
||||
|
||||
private TrashbinActivityInterface trashbinActivityInterface;
|
||||
private List<TrashbinFile> files;
|
||||
private Context context;
|
||||
private Account account;
|
||||
private FileDataStorageManager storageManager;
|
||||
|
||||
private ArrayList<ThumbnailsCacheManager.ThumbnailGenerationTask> asyncTasks = new ArrayList<>();
|
||||
|
||||
public TrashbinListAdapter(TrashbinActivityInterface trashbinActivityInterface,
|
||||
FileDataStorageManager storageManager, Context context) {
|
||||
this.files = new ArrayList<>();
|
||||
this.trashbinActivityInterface = trashbinActivityInterface;
|
||||
this.account = AccountUtils.getCurrentOwnCloudAccount(context);
|
||||
this.storageManager = storageManager;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setTrashbinFiles(List<Object> trashbinFiles, boolean clear) {
|
||||
if (clear) {
|
||||
files.clear();
|
||||
}
|
||||
|
||||
for (Object file : trashbinFiles) {
|
||||
files.add((TrashbinFile) file);
|
||||
}
|
||||
|
||||
files = PreferenceManager.getSortOrder(context, null).sortTrashbinFiles(files);
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
if (viewType == TRASHBIN_ITEM) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.trashbin_item, parent, false);
|
||||
return new TrashbinFileViewHolder(v);
|
||||
} else {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_footer, parent, false);
|
||||
return new TrashbinFooterViewHolder(v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||
if (holder instanceof TrashbinFileViewHolder) {
|
||||
final TrashbinFileViewHolder trashbinFileViewHolder = (TrashbinFileViewHolder) holder;
|
||||
TrashbinFile file = files.get(position);
|
||||
|
||||
// layout
|
||||
trashbinFileViewHolder.itemLayout.setOnClickListener(v -> trashbinActivityInterface.onItemClicked(file));
|
||||
|
||||
// thumbnail
|
||||
trashbinFileViewHolder.thumbnail.setTag(file.getRemoteId());
|
||||
setThumbnail(file, trashbinFileViewHolder.thumbnail);
|
||||
|
||||
// fileName
|
||||
trashbinFileViewHolder.fileName.setText(file.getFileName());
|
||||
|
||||
// fileSize
|
||||
trashbinFileViewHolder.fileSize.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
|
||||
|
||||
// originalLocation
|
||||
String location;
|
||||
int lastIndex = file.getOriginalLocation().lastIndexOf('/');
|
||||
if (lastIndex != -1) {
|
||||
location = "/" + file.getOriginalLocation().substring(0, lastIndex) + "/";
|
||||
} else {
|
||||
location = "/";
|
||||
}
|
||||
trashbinFileViewHolder.originalLocation.setText(location);
|
||||
|
||||
// deletion time
|
||||
trashbinFileViewHolder.deletionTimestamp.setText(DisplayUtils.getRelativeTimestamp(context,
|
||||
file.getDeletionTimestamp() * 1000));
|
||||
|
||||
// checkbox
|
||||
trashbinFileViewHolder.checkbox.setVisibility(View.GONE);
|
||||
|
||||
// overflow menu
|
||||
trashbinFileViewHolder.overflowMenu.setOnClickListener(v ->
|
||||
trashbinActivityInterface.onOverflowIconClicked(file, v));
|
||||
|
||||
// restore button
|
||||
trashbinFileViewHolder.restoreButton.setOnClickListener(v ->
|
||||
trashbinActivityInterface.onRestoreIconClicked(file, v));
|
||||
|
||||
} else {
|
||||
TrashbinFooterViewHolder trashbinFooterViewHolder = (TrashbinFooterViewHolder) holder;
|
||||
trashbinFooterViewHolder.title.setText(getFooterText());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFile(TrashbinFile file) {
|
||||
int index = files.indexOf(file);
|
||||
|
||||
if (index != -1) {
|
||||
files.remove(index);
|
||||
notifyItemRemoved(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllFiles() {
|
||||
files.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private String getFooterText() {
|
||||
int filesCount = 0;
|
||||
int foldersCount = 0;
|
||||
int count = files.size();
|
||||
TrashbinFile file;
|
||||
for (int i = 0; i < count; i++) {
|
||||
file = files.get(i);
|
||||
if (file.isFolder()) {
|
||||
foldersCount++;
|
||||
} else {
|
||||
if (!file.isHidden()) {
|
||||
filesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return generateFooterText(filesCount, foldersCount);
|
||||
}
|
||||
|
||||
private String generateFooterText(int filesCount, int foldersCount) {
|
||||
String output;
|
||||
Resources resources = context.getResources();
|
||||
|
||||
if (filesCount + foldersCount <= 0) {
|
||||
output = "";
|
||||
} else if (foldersCount <= 0) {
|
||||
output = resources.getQuantityString(R.plurals.file_list__footer__file, filesCount, filesCount);
|
||||
} else if (filesCount <= 0) {
|
||||
output = resources.getQuantityString(R.plurals.file_list__footer__folder, foldersCount, foldersCount);
|
||||
} else {
|
||||
output = resources.getQuantityString(R.plurals.file_list__footer__file, filesCount, filesCount) + ", " +
|
||||
resources.getQuantityString(R.plurals.file_list__footer__folder, foldersCount, foldersCount);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private void setThumbnail(TrashbinFile file, ImageView thumbnailView) {
|
||||
if (file.isFolder()) {
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil.getDefaultFolderIcon(context));
|
||||
} else {
|
||||
if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) {
|
||||
// Thumbnail in cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
ThumbnailsCacheManager.PREFIX_THUMBNAIL + String.valueOf(file.getRemoteId())
|
||||
);
|
||||
|
||||
if (thumbnail != null) {
|
||||
if (MimeTypeUtil.isVideo(file)) {
|
||||
Bitmap withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail);
|
||||
thumbnailView.setImageBitmap(withOverlay);
|
||||
} else {
|
||||
thumbnailView.setImageBitmap(thumbnail);
|
||||
}
|
||||
} else {
|
||||
// generate new thumbnail
|
||||
if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) {
|
||||
try {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(thumbnailView, storageManager,
|
||||
account, asyncTasks);
|
||||
|
||||
final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncThumbnailDrawable(context.getResources(),
|
||||
thumbnail, task);
|
||||
thumbnailView.setImageDrawable(asyncDrawable);
|
||||
asyncTasks.add(task);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file,
|
||||
file.getRemoteId()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file.getMimeType().equalsIgnoreCase("image/png")) {
|
||||
thumbnailView.setBackgroundColor(context.getResources().getColor(R.color.background_color));
|
||||
}
|
||||
} else {
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(),
|
||||
account, context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (position == files.size()) {
|
||||
return TRASHBIN_FOOTER;
|
||||
} else {
|
||||
return TRASHBIN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return files.size() + 1;
|
||||
}
|
||||
|
||||
public void cancelAllPendingTasks() {
|
||||
for (ThumbnailsCacheManager.ThumbnailGenerationTask task : asyncTasks) {
|
||||
if (task != null) {
|
||||
task.cancel(true);
|
||||
if (task.getGetMethod() != null) {
|
||||
Log_OC.d(TAG, "cancel: abort get method directly");
|
||||
task.getGetMethod().abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asyncTasks.clear();
|
||||
}
|
||||
|
||||
public void setSortOrder(FileSortOrder sortOrder) {
|
||||
PreferenceManager.setSortOrder(context, null, sortOrder);
|
||||
files = sortOrder.sortTrashbinFiles(files);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public class TrashbinFileViewHolder extends RecyclerView.ViewHolder {
|
||||
@BindView(R.id.thumbnail)
|
||||
public ImageView thumbnail;
|
||||
@BindView(R.id.Filename)
|
||||
public TextView fileName;
|
||||
@BindView(R.id.fileSize)
|
||||
public TextView fileSize;
|
||||
@BindView(R.id.deletionTimestamp)
|
||||
public TextView deletionTimestamp;
|
||||
@BindView(R.id.originalLocation)
|
||||
public TextView originalLocation;
|
||||
@BindView(R.id.restore)
|
||||
public ImageView restoreButton;
|
||||
@BindView(R.id.customCheckbox)
|
||||
public ImageView checkbox;
|
||||
@BindView(R.id.overflowMenu)
|
||||
public ImageView overflowMenu;
|
||||
@BindView(R.id.ListItemLayout)
|
||||
public LinearLayout itemLayout;
|
||||
|
||||
private TrashbinFileViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
// todo action mode
|
||||
}
|
||||
}
|
||||
|
||||
public class TrashbinFooterViewHolder extends RecyclerView.ViewHolder {
|
||||
@BindView(R.id.footerText)
|
||||
public TextView title;
|
||||
|
||||
private TrashbinFooterViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -128,7 +128,7 @@ public class UploaderAdapter extends SimpleAdapter {
|
|||
}
|
||||
} else {
|
||||
fileIcon.setImageDrawable(
|
||||
MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(), mAccount, mContext)
|
||||
MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), mAccount, mContext)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ public class SendShareDialog extends BottomSheetDialogFragment {
|
|||
@NonNull
|
||||
private Intent createSendIntent() {
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.setType(file.getMimetype());
|
||||
sendIntent.setType(file.getMimeType());
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, file.getExposedFileUri(getActivity()));
|
||||
sendIntent.putExtra(Intent.ACTION_SEND, true);
|
||||
return sendIntent;
|
||||
|
|
|
@ -191,7 +191,7 @@ public class ShareFileFragment extends Fragment implements ShareUserListAdapter.
|
|||
// Image
|
||||
ImageView icon = view.findViewById(R.id.shareFileIcon);
|
||||
icon.setImageDrawable(
|
||||
MimeTypeUtil.getFileTypeIcon(mFile.getMimetype(), mFile.getFileName(), mAccount, getContext())
|
||||
MimeTypeUtil.getFileTypeIcon(mFile.getMimeType(), mFile.getFileName(), mAccount, getContext())
|
||||
);
|
||||
if (MimeTypeUtil.isImage(mFile)) {
|
||||
String remoteId = String.valueOf(mFile.getRemoteId());
|
||||
|
|
|
@ -335,6 +335,52 @@ public class FileOperationsHelper {
|
|||
|
||||
openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
return openFileWithIntent;
|
||||
|
||||
|
||||
String storagePath = file.getStoragePath();
|
||||
|
||||
String[] officeExtensions = MainApp.getAppContext().getResources().getStringArray(R.array
|
||||
.ms_office_extensions);
|
||||
|
||||
Uri fileUri;
|
||||
|
||||
if (file.getFileName().contains(".") &&
|
||||
Arrays.asList(officeExtensions).contains(file.getFileName().substring(file.getFileName().
|
||||
lastIndexOf(".") + 1, file.getFileName().length())) &&
|
||||
!file.getStoragePath().startsWith(MainApp.getAppContext().getFilesDir().getAbsolutePath())) {
|
||||
fileUri = file.getLegacyExposedFileUri(mFileActivity);
|
||||
} else {
|
||||
fileUri = file.getExposedFileUri(mFileActivity);
|
||||
}
|
||||
|
||||
Intent openFileWithIntent = null;
|
||||
int lastIndexOfDot = storagePath.lastIndexOf('.');
|
||||
if (lastIndexOfDot >= 0) {
|
||||
String fileExt = storagePath.substring(lastIndexOfDot + 1);
|
||||
String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExt);
|
||||
if (guessedMimeType != null) {
|
||||
openFileWithIntent = new Intent(Intent.ACTION_VIEW);
|
||||
openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
openFileWithIntent.setDataAndType(
|
||||
fileUri,
|
||||
guessedMimeType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (openFileWithIntent == null) {
|
||||
openFileWithIntent = createIntentFromFile(storagePath);
|
||||
}
|
||||
|
||||
if (openFileWithIntent == null) {
|
||||
openFileWithIntent = new Intent(Intent.ACTION_VIEW);
|
||||
openFileWithIntent.setDataAndType(
|
||||
fileUri,
|
||||
file.getMimeType()
|
||||
);
|
||||
}
|
||||
|
||||
openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
}
|
||||
|
||||
private Uri getFileUri(OCFile file, String[] officeExtensions) {
|
||||
|
@ -709,7 +755,7 @@ public class FileOperationsHelper {
|
|||
Context context = MainApp.getAppContext();
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
// set MimeType
|
||||
sendIntent.setType(file.getMimetype());
|
||||
sendIntent.setType(file.getMimeType());
|
||||
sendIntent.setComponent(new ComponentName(packageName, activityName));
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" +
|
||||
context.getResources().getString(R.string.image_cache_provider_authority) +
|
||||
|
@ -746,11 +792,11 @@ public class FileOperationsHelper {
|
|||
file.getRemotePath());
|
||||
}
|
||||
|
||||
intent.setDataAndType(uri, file.getMimetype());
|
||||
intent.setDataAndType(uri, file.getMimeType());
|
||||
mFileActivity.startActivityForResult(Intent.createChooser(intent,
|
||||
mFileActivity.getString(R.string.set_as)), 200);
|
||||
|
||||
intent.setDataAndType(uri, file.getMimetype());
|
||||
intent.setDataAndType(uri, file.getMimeType());
|
||||
} catch (ActivityNotFoundException exception) {
|
||||
DisplayUtils.showSnackMessage(view, R.string.picture_set_as_no_app);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
* Copyright (C) 2017 Nextcloud GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.interfaces;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
import com.owncloud.android.ui.adapter.OCFileListAdapter;
|
||||
|
||||
/**
|
||||
* Interface for communication between {@link com.owncloud.android.ui.fragment.OCFileListFragment}
|
||||
* and {@link OCFileListAdapter}
|
||||
*/
|
||||
|
||||
public interface TrashbinActivityInterface {
|
||||
void onOverflowIconClicked(TrashbinFile file, View view);
|
||||
|
||||
void onItemClicked(TrashbinFile file);
|
||||
|
||||
void onRestoreIconClicked(TrashbinFile file, View view);
|
||||
}
|
|
@ -467,7 +467,7 @@ public class PreviewImageFragment extends FileFragment {
|
|||
int minHeight = screenSize.y;
|
||||
for (int i = 0; i < maxDownScale && bitmapResult == null && drawableResult == null; i++) {
|
||||
|
||||
if (ocFile.getMimetype().equalsIgnoreCase(MIME_TYPE_SVG)) {
|
||||
if (ocFile.getMimeType().equalsIgnoreCase(MIME_TYPE_SVG)) {
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -504,7 +504,7 @@ public class PreviewImageFragment extends FileFragment {
|
|||
Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
|
||||
break;
|
||||
} else {
|
||||
if (ocFile.getMimetype().equalsIgnoreCase("image/jpeg")) {
|
||||
if (ocFile.getMimeType().equalsIgnoreCase("image/jpeg")) {
|
||||
// Rotate image, obeying exif tag.
|
||||
bitmapResult = BitmapUtils.rotateImage(bitmapResult, storagePath);
|
||||
}
|
||||
|
@ -570,9 +570,9 @@ public class PreviewImageFragment extends FileFragment {
|
|||
Log_OC.d(TAG, "Showing image with resolution " + bitmap.getWidth() + "x" +
|
||||
bitmap.getHeight());
|
||||
|
||||
if (result.ocFile.getMimetype().equalsIgnoreCase(MIME_TYPE_PNG) ||
|
||||
result.ocFile.getMimetype().equalsIgnoreCase(MIME_TYPE_SVG) ||
|
||||
result.ocFile.getMimetype().equalsIgnoreCase(MIME_TYPE_GIF)) {
|
||||
if (result.ocFile.getMimeType().equalsIgnoreCase(MIME_TYPE_PNG) ||
|
||||
result.ocFile.getMimeType().equalsIgnoreCase(MIME_TYPE_SVG) ||
|
||||
result.ocFile.getMimeType().equalsIgnoreCase(MIME_TYPE_GIF)) {
|
||||
if (getResources() != null) {
|
||||
imageView.setImageDrawable(generateCheckerboardLayeredDrawable(result, bitmap));
|
||||
} else {
|
||||
|
@ -728,8 +728,8 @@ public class PreviewImageFragment extends FileFragment {
|
|||
|
||||
private void toggleImageBackground() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && getFile() != null
|
||||
&& (getFile().getMimetype().equalsIgnoreCase(MIME_TYPE_PNG) ||
|
||||
getFile().getMimetype().equalsIgnoreCase(MIME_TYPE_SVG)) && getActivity() != null
|
||||
&& (getFile().getMimeType().equalsIgnoreCase(MIME_TYPE_PNG) ||
|
||||
getFile().getMimeType().equalsIgnoreCase(MIME_TYPE_SVG)) && getActivity() != null
|
||||
&& getActivity() instanceof PreviewImageActivity && getResources() != null) {
|
||||
PreviewImageActivity previewImageActivity = (PreviewImageActivity) getActivity();
|
||||
|
||||
|
|
|
@ -403,7 +403,7 @@ public class PreviewTextFragment extends FileFragment {
|
|||
unsupportedTypes.add("text/vnd.wap.wml");
|
||||
unsupportedTypes.add("text/vnd.wap.wmlscript");
|
||||
return (file != null && file.isDown() && MimeTypeUtil.isText(file) &&
|
||||
!unsupportedTypes.contains(file.getMimetype()) &&
|
||||
!unsupportedTypes.contains(file.getMimeType()) &&
|
||||
!unsupportedTypes.contains(MimeTypeUtil.getMimeTypeFromPath(file.getRemotePath()))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.trashbin;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ReadRemoteTrashbinFolderOperation;
|
||||
import com.owncloud.android.lib.resources.files.RemoveTrashbinFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
import com.owncloud.android.operations.EmptyTrashbinFileOperation;
|
||||
import com.owncloud.android.operations.RestoreTrashbinFileOperation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RemoteTrashbinRepository implements TrashbinRepository {
|
||||
|
||||
private static final String TAG = RemoteTrashbinRepository.class.getSimpleName();
|
||||
|
||||
private String userId;
|
||||
private OwnCloudClient client;
|
||||
|
||||
public RemoteTrashbinRepository(Context context) {
|
||||
AccountManager accountManager = AccountManager.get(context);
|
||||
Account account = AccountUtils.getCurrentOwnCloudAccount(context);
|
||||
|
||||
try {
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
|
||||
client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context);
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(TAG, e.getMessage());
|
||||
}
|
||||
|
||||
userId = accountManager.getUserData(account,
|
||||
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
|
||||
}
|
||||
|
||||
public void removeTrashbinFile(TrashbinFile file, OperationCallback callback) {
|
||||
new RemoveTrashbinFileTask(client, file, callback).execute();
|
||||
}
|
||||
|
||||
private static class RemoveTrashbinFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private OwnCloudClient client;
|
||||
private TrashbinFile file;
|
||||
private OperationCallback callback;
|
||||
|
||||
private RemoveTrashbinFileTask(OwnCloudClient client, TrashbinFile file, OperationCallback callback) {
|
||||
this.client = client;
|
||||
this.file = file;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
RemoveTrashbinFileOperation removeTrashbinFileOperation = new RemoveTrashbinFileOperation(
|
||||
file.getFullRemotePath());
|
||||
RemoteOperationResult result = removeTrashbinFileOperation.execute(client);
|
||||
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
callback.onResult(success);
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyTrashbin(OperationCallback callback) {
|
||||
new EmptyTrashbinTask(client, userId, callback).execute();
|
||||
}
|
||||
|
||||
private static class EmptyTrashbinTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private OwnCloudClient client;
|
||||
private String userId;
|
||||
private OperationCallback callback;
|
||||
|
||||
private EmptyTrashbinTask(OwnCloudClient client, String userId, OperationCallback callback) {
|
||||
this.client = client;
|
||||
this.userId = userId;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
EmptyTrashbinFileOperation emptyTrashbinFileOperation = new EmptyTrashbinFileOperation(userId);
|
||||
RemoteOperationResult result = emptyTrashbinFileOperation.execute(client);
|
||||
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
callback.onResult(success);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFile(TrashbinFile file, OperationCallback callback) {
|
||||
new RestoreTrashbinFileTask(file, userId, client, callback).execute();
|
||||
}
|
||||
|
||||
private static class RestoreTrashbinFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private TrashbinFile file;
|
||||
private String userId;
|
||||
private OwnCloudClient client;
|
||||
private TrashbinRepository.OperationCallback callback;
|
||||
|
||||
private RestoreTrashbinFileTask(TrashbinFile file, String userId, OwnCloudClient client,
|
||||
TrashbinRepository.OperationCallback callback) {
|
||||
this.file = file;
|
||||
this.userId = userId;
|
||||
this.client = client;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
|
||||
RestoreTrashbinFileOperation restoreTrashbinFileOperation = new RestoreTrashbinFileOperation(
|
||||
file.getFullRemotePath(), file.getFileName(), userId);
|
||||
|
||||
RemoteOperationResult result = restoreTrashbinFileOperation.execute(client);
|
||||
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
callback.onResult(success);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getFolder(String remotePath, @NonNull LoadFolderCallback callback) {
|
||||
new ReadRemoteTrashbinFolderTask(remotePath, userId, client, callback).execute();
|
||||
}
|
||||
|
||||
private static class ReadRemoteTrashbinFolderTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private String remotePath;
|
||||
private String userId;
|
||||
private OwnCloudClient client;
|
||||
private List<Object> trashbinFiles;
|
||||
private LoadFolderCallback callback;
|
||||
|
||||
private ReadRemoteTrashbinFolderTask(String remotePath, String userId, OwnCloudClient client,
|
||||
LoadFolderCallback callback) {
|
||||
this.remotePath = remotePath;
|
||||
this.userId = userId;
|
||||
this.client = client;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
ReadRemoteTrashbinFolderOperation readRemoteTrashbinFolderOperation =
|
||||
new ReadRemoteTrashbinFolderOperation(remotePath, userId);
|
||||
|
||||
RemoteOperationResult result = readRemoteTrashbinFolderOperation.execute(client);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
trashbinFiles = result.getData();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
super.onPostExecute(success);
|
||||
|
||||
if (success) {
|
||||
callback.onSuccess(trashbinFiles);
|
||||
} else {
|
||||
callback.onError(R.string.trashbin_loading_failed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.trashbin;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
import com.owncloud.android.ui.EmptyRecyclerView;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.adapter.TrashbinListAdapter;
|
||||
import com.owncloud.android.ui.dialog.SortingOrderDialogFragment;
|
||||
import com.owncloud.android.ui.interfaces.TrashbinActivityInterface;
|
||||
import com.owncloud.android.utils.FileSortOrder;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindString;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
import static com.owncloud.android.db.PreferenceManager.getSortOrder;
|
||||
|
||||
/**
|
||||
* Presenting trashbin data, received from presenter
|
||||
*/
|
||||
public class TrashbinActivity extends FileActivity implements TrashbinActivityInterface,
|
||||
SortingOrderDialogFragment.OnSortingOrderListener, TrashbinContract.View {
|
||||
|
||||
@BindView(R.id.empty_list_view_text)
|
||||
public TextView emptyContentMessage;
|
||||
|
||||
@BindView(R.id.empty_list_view_headline)
|
||||
public TextView emptyContentHeadline;
|
||||
|
||||
@BindView(R.id.empty_list_icon)
|
||||
public ImageView emptyContentIcon;
|
||||
|
||||
@BindView(android.R.id.list)
|
||||
public EmptyRecyclerView recyclerView;
|
||||
|
||||
@BindView(R.id.swipe_containing_list)
|
||||
public SwipeRefreshLayout swipeListRefreshLayout;
|
||||
|
||||
@BindString(R.string.trashbin_empty_headline)
|
||||
public String noResultsHeadline;
|
||||
|
||||
@BindString(R.string.trashbin_empty_message)
|
||||
public String noResultsMessage;
|
||||
|
||||
private Unbinder unbinder;
|
||||
private TrashbinListAdapter trashbinListAdapter;
|
||||
private TrashbinPresenter trashbinPresenter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
trashbinPresenter = new TrashbinPresenter(new RemoteTrashbinRepository(this), this);
|
||||
|
||||
setContentView(R.layout.trashbin_activity);
|
||||
unbinder = ButterKnife.bind(this);
|
||||
|
||||
// setup toolbar
|
||||
setupToolbar();
|
||||
|
||||
// setup drawer
|
||||
setupDrawer(R.id.nav_trashbin);
|
||||
|
||||
ThemeUtils.setColoredTitle(getSupportActionBar(), R.string.trashbin_activity_title, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
setupContent();
|
||||
}
|
||||
|
||||
private void setupContent() {
|
||||
recyclerView = findViewById(android.R.id.list);
|
||||
recyclerView.setEmptyView(findViewById(R.id.empty_list_view));
|
||||
findViewById(R.id.empty_list_progress).setVisibility(View.GONE);
|
||||
emptyContentIcon.setImageResource(R.drawable.ic_delete);
|
||||
emptyContentIcon.setVisibility(View.VISIBLE);
|
||||
emptyContentHeadline.setText(noResultsHeadline);
|
||||
emptyContentMessage.setText(noResultsMessage);
|
||||
emptyContentMessage.setVisibility(View.VISIBLE);
|
||||
|
||||
trashbinListAdapter = new TrashbinListAdapter(this, getStorageManager(), this);
|
||||
recyclerView.setAdapter(trashbinListAdapter);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setHasFooter(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
swipeListRefreshLayout.setOnRefreshListener(this::loadFolder);
|
||||
|
||||
loadFolder();
|
||||
}
|
||||
|
||||
private void loadFolder() {
|
||||
swipeListRefreshLayout.setRefreshing(true);
|
||||
trashbinPresenter.loadFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showFiles(boolean onDeviceOnly) {
|
||||
super.showFiles(onDeviceOnly);
|
||||
Intent i = new Intent(getApplicationContext(), FileDisplayActivity.class);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
if (isDrawerOpen()) {
|
||||
closeDrawer();
|
||||
} else if (trashbinPresenter.isRoot()) {
|
||||
onBackPressed();
|
||||
} else {
|
||||
openDrawer();
|
||||
}
|
||||
break;
|
||||
case R.id.action_sort: {
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.addToBackStack(null);
|
||||
|
||||
SortingOrderDialogFragment mSortingOrderDialogFragment = SortingOrderDialogFragment.newInstance(
|
||||
getSortOrder(this, null));
|
||||
mSortingOrderDialogFragment.show(ft, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT);
|
||||
|
||||
break;
|
||||
}
|
||||
case R.id.action_empty_trashbin:
|
||||
trashbinPresenter.emptyTrashbin();
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbinder.unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOverflowIconClicked(TrashbinFile file, View view) {
|
||||
PopupMenu popup = new PopupMenu(this, view);
|
||||
popup.inflate(R.menu.trashbin_actions_menu);
|
||||
|
||||
popup.setOnMenuItemClickListener(item -> {
|
||||
trashbinPresenter.removeTrashbinFile(file);
|
||||
|
||||
return true;
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClicked(TrashbinFile file) {
|
||||
if (file.isFolder()) {
|
||||
trashbinPresenter.enterFolder(file.getRemotePath());
|
||||
|
||||
mDrawerToggle.setDrawerIndicatorEnabled(false);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
if (toolbar != null && toolbar.getNavigationIcon() != null) {
|
||||
ThemeUtils.tintDrawable(toolbar.getNavigationIcon(), ThemeUtils.fontColor(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreIconClicked(TrashbinFile file, View view) {
|
||||
trashbinPresenter.restoreTrashbinFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.trashbin_options_menu, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
trashbinListAdapter.cancelAllPendingTasks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
trashbinPresenter.navigateUp();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
public void setDrawerIndicatorEnabled(boolean bool) {
|
||||
mDrawerToggle.setDrawerIndicatorEnabled(bool);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSortingOrderChosen(FileSortOrder sortOrder) {
|
||||
trashbinListAdapter.setSortOrder(sortOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showTrashbinFolder(List<Object> trashbinFiles) {
|
||||
trashbinListAdapter.setTrashbinFiles(trashbinFiles, true);
|
||||
swipeListRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFile(TrashbinFile file) {
|
||||
trashbinListAdapter.removeFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllFiles() {
|
||||
trashbinListAdapter.removeAllFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(int message) {
|
||||
swipeListRefreshLayout.setRefreshing(false);
|
||||
Snackbar.make(recyclerView, getString(message), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(int message, TrashbinFile file) {
|
||||
swipeListRefreshLayout.setRefreshing(false);
|
||||
Snackbar.make(recyclerView, String.format(getString(message), file.getFileName()), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.trashbin;
|
||||
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Contract between view (TrashbinActivity) and presenter (TrashbinPresenter)
|
||||
*/
|
||||
public interface TrashbinContract {
|
||||
|
||||
interface View {
|
||||
void showTrashbinFolder(List<Object> trashbinFiles);
|
||||
|
||||
void showError(int message, TrashbinFile file);
|
||||
|
||||
void showError(int message);
|
||||
|
||||
void removeFile(TrashbinFile file);
|
||||
|
||||
void removeAllFiles();
|
||||
|
||||
void close();
|
||||
|
||||
void setDrawerIndicatorEnabled(boolean bool);
|
||||
}
|
||||
|
||||
interface Presenter {
|
||||
|
||||
boolean isRoot();
|
||||
|
||||
void loadFolder();
|
||||
|
||||
void navigateUp();
|
||||
|
||||
void enterFolder(String folder);
|
||||
|
||||
void restoreTrashbinFile(TrashbinFile file);
|
||||
|
||||
void removeTrashbinFile(TrashbinFile file);
|
||||
|
||||
void emptyTrashbin();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.trashbin;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Coordinates between model and view: querying model, updating view, react to UI input
|
||||
*/
|
||||
public class TrashbinPresenter implements TrashbinContract.Presenter {
|
||||
|
||||
private TrashbinContract.View trashbinView;
|
||||
private TrashbinRepository trashbinRepository;
|
||||
private String currentPath = "/";
|
||||
|
||||
public TrashbinPresenter(TrashbinRepository trashbinRepository, TrashbinContract.View trashbinView) {
|
||||
this.trashbinRepository = trashbinRepository;
|
||||
this.trashbinView = trashbinView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterFolder(String folder) {
|
||||
currentPath = folder;
|
||||
loadFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRoot() {
|
||||
return !"/".equals(currentPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateUp() {
|
||||
if ("/".equals(currentPath)) {
|
||||
trashbinView.close();
|
||||
} else {
|
||||
currentPath = new File(currentPath).getParent();
|
||||
|
||||
loadFolder();
|
||||
}
|
||||
|
||||
trashbinView.setDrawerIndicatorEnabled("/".equals(currentPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFolder() {
|
||||
trashbinRepository.getFolder(currentPath, new TrashbinRepository.LoadFolderCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<Object> files) {
|
||||
trashbinView.showTrashbinFolder(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int error) {
|
||||
trashbinView.showError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreTrashbinFile(TrashbinFile file) {
|
||||
trashbinRepository.restoreFile(file, success -> {
|
||||
if (success) {
|
||||
trashbinView.removeFile(file);
|
||||
} else {
|
||||
trashbinView.showError(R.string.trashbin_file_not_restored, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTrashbinFile(TrashbinFile file) {
|
||||
trashbinRepository.removeTrashbinFile(file, success -> {
|
||||
if (success) {
|
||||
trashbinView.removeFile(file);
|
||||
} else {
|
||||
trashbinView.showError(R.string.trashbin_file_not_deleted, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emptyTrashbin() {
|
||||
trashbinRepository.emptyTrashbin(success -> {
|
||||
if (success) {
|
||||
trashbinView.removeAllFiles();
|
||||
} else {
|
||||
trashbinView.showError(R.string.trashbin_not_emptied);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2018 Tobias Kaminsky
|
||||
* Copyright (C) 2018 Nextcloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.trashbin;
|
||||
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Contract between presenter and model
|
||||
*/
|
||||
public interface TrashbinRepository {
|
||||
interface LoadFolderCallback {
|
||||
void onSuccess(List<Object> files);
|
||||
|
||||
void onError(int error);
|
||||
}
|
||||
|
||||
interface OperationCallback {
|
||||
void onResult(boolean success);
|
||||
}
|
||||
|
||||
void getFolder(String remotePath, LoadFolderCallback callback);
|
||||
|
||||
void restoreFile(TrashbinFile file, OperationCallback callback);
|
||||
|
||||
void emptyTrashbin(OperationCallback callback);
|
||||
|
||||
void removeTrashbinFile(TrashbinFile file, OperationCallback callback);
|
||||
}
|
|
@ -310,7 +310,7 @@ public class DisplayUtils {
|
|||
* calculates the relative time string based on the given modification timestamp.
|
||||
*
|
||||
* @param context the app's context
|
||||
* @param modificationTimestamp the UNIX timestamp of the file modification time.
|
||||
* @param modificationTimestamp the UNIX timestamp of the file modification time in milliseconds.
|
||||
* @return a relative time string
|
||||
*/
|
||||
public static CharSequence getRelativeTimestamp(Context context, long modificationTimestamp) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package com.owncloud.android.utils;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
|
@ -67,6 +68,10 @@ public class FileSortOrder {
|
|||
return files;
|
||||
}
|
||||
|
||||
public List<TrashbinFile> sortTrashbinFiles(List<TrashbinFile> files) {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Favourites.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package com.owncloud.android.utils;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
|
@ -49,6 +50,25 @@ public class FileSortOrderByDate extends FileSortOrder {
|
|||
return super.sortCloudFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Date.
|
||||
*
|
||||
* @param files list of files to sort
|
||||
*/
|
||||
public List<TrashbinFile> sortTrashbinFiles(List<TrashbinFile> files) {
|
||||
final int multiplier = mAscending ? 1 : -1;
|
||||
|
||||
Collections.sort(files, new Comparator<TrashbinFile>() {
|
||||
@SuppressFBWarnings(value = "Bx", justification = "Would require stepping up API level")
|
||||
public int compare(TrashbinFile o1, TrashbinFile o2) {
|
||||
Long obj1 = o1.getDeletionTimestamp();
|
||||
return multiplier * obj1.compareTo(o2.getDeletionTimestamp());
|
||||
}
|
||||
});
|
||||
|
||||
return super.sortTrashbinFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Date.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package com.owncloud.android.utils;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
|
@ -62,6 +63,31 @@ public class FileSortOrderByName extends FileSortOrder {
|
|||
return super.sortCloudFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Name.
|
||||
*
|
||||
* @param files files to sort
|
||||
*/
|
||||
@SuppressFBWarnings(value = "Bx")
|
||||
public List<TrashbinFile> sortTrashbinFiles(List<TrashbinFile> files) {
|
||||
final int multiplier = mAscending ? 1 : -1;
|
||||
|
||||
Collections.sort(files, new Comparator<TrashbinFile>() {
|
||||
public int compare(TrashbinFile o1, TrashbinFile o2) {
|
||||
if (o1.isFolder() && o2.isFolder()) {
|
||||
return multiplier * new AlphanumComparator().compare(o1, o2);
|
||||
} else if (o1.isFolder()) {
|
||||
return -1;
|
||||
} else if (o2.isFolder()) {
|
||||
return 1;
|
||||
}
|
||||
return multiplier * new AlphanumComparator().compare(o1, o2);
|
||||
}
|
||||
});
|
||||
|
||||
return super.sortTrashbinFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Name.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package com.owncloud.android.utils;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.resources.files.TrashbinFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
|
@ -62,6 +63,35 @@ public class FileSortOrderBySize extends FileSortOrder {
|
|||
return super.sortCloudFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Size.
|
||||
*
|
||||
* @param files list of files to sort
|
||||
*/
|
||||
public List<TrashbinFile> sortTrashbinFiles(List<TrashbinFile> files) {
|
||||
final int multiplier = mAscending ? 1 : -1;
|
||||
|
||||
Collections.sort(files, new Comparator<TrashbinFile>() {
|
||||
@SuppressFBWarnings(value = "Bx")
|
||||
public int compare(TrashbinFile o1, TrashbinFile o2) {
|
||||
if (o1.isFolder() && o2.isFolder()) {
|
||||
Long obj1 = o1.getFileLength();
|
||||
return multiplier * obj1.compareTo(o2.getFileLength());
|
||||
} else if (o1.isFolder()) {
|
||||
return -1;
|
||||
|
||||
} else if (o2.isFolder()) {
|
||||
return 1;
|
||||
} else {
|
||||
Long obj1 = o1.getFileLength();
|
||||
return multiplier * obj1.compareTo(o2.getFileLength());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return super.sortTrashbinFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts list by Size.
|
||||
*
|
||||
|
|
|
@ -187,7 +187,7 @@ public class FileStorageUtils {
|
|||
RemoteFile file = new RemoteFile(ocFile.getRemotePath());
|
||||
file.setCreationTimestamp(ocFile.getCreationTimestamp());
|
||||
file.setLength(ocFile.getFileLength());
|
||||
file.setMimeType(ocFile.getMimetype());
|
||||
file.setMimeType(ocFile.getMimeType());
|
||||
file.setModifiedTimestamp(ocFile.getModificationTimestamp());
|
||||
file.setEtag(ocFile.getEtag());
|
||||
file.setPermissions(ocFile.getPermissions());
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.webkit.MimeTypeMap;
|
|||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.network.WebdavEntry;
|
||||
import com.owncloud.android.lib.resources.files.ServerFileInterface;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
@ -248,7 +249,7 @@ public class MimeTypeUtil {
|
|||
}
|
||||
|
||||
public static boolean isSVG(OCFile file) {
|
||||
return "image/svg+xml".equalsIgnoreCase(file.getMimetype());
|
||||
return "image/svg+xml".equalsIgnoreCase(file.getMimeType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,23 +257,23 @@ public class MimeTypeUtil {
|
|||
* @return 'True' if the file contains audio
|
||||
*/
|
||||
public static boolean isAudio(OCFile file) {
|
||||
return MimeTypeUtil.isAudio(file.getMimetype());
|
||||
return MimeTypeUtil.isAudio(file.getMimeType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file the file to be analyzed
|
||||
* @return 'True' if the file contains video
|
||||
*/
|
||||
public static boolean isVideo(OCFile file) {
|
||||
return MimeTypeUtil.isVideo(file.getMimetype());
|
||||
public static boolean isVideo(ServerFileInterface file) {
|
||||
return MimeTypeUtil.isVideo(file.getMimeType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file the file to be analyzed
|
||||
* @return 'True' if the file contains an image
|
||||
*/
|
||||
public static boolean isImage(OCFile file) {
|
||||
return (MimeTypeUtil.isImage(file.getMimetype())
|
||||
public static boolean isImage(ServerFileInterface file) {
|
||||
return (MimeTypeUtil.isImage(file.getMimeType())
|
||||
|| MimeTypeUtil.isImage(getMimeTypeFromPath(file.getRemotePath())));
|
||||
}
|
||||
|
||||
|
@ -281,7 +282,7 @@ public class MimeTypeUtil {
|
|||
* @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx)
|
||||
*/
|
||||
public static boolean isText(OCFile file) {
|
||||
return (MimeTypeUtil.isText(file.getMimetype())
|
||||
return (MimeTypeUtil.isText(file.getMimeType())
|
||||
|| MimeTypeUtil.isText(getMimeTypeFromPath(file.getRemotePath())));
|
||||
}
|
||||
|
||||
|
@ -291,7 +292,7 @@ public class MimeTypeUtil {
|
|||
* @return 'True' if the file is a vcard
|
||||
*/
|
||||
public static boolean isVCard(OCFile file) {
|
||||
return isVCard(file.getMimetype()) || isVCard(getMimeTypeFromPath(file.getRemotePath()));
|
||||
return isVCard(file.getMimeType()) || isVCard(getMimeTypeFromPath(file.getRemotePath()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,8 +46,8 @@ public class FileCursor extends MatrixCursor {
|
|||
return;
|
||||
}
|
||||
|
||||
final int iconRes = MimeTypeUtil.getFileTypeIconId(file.getMimetype(), file.getFileName());
|
||||
final String mimeType = file.isFolder() ? Document.MIME_TYPE_DIR : file.getMimetype();
|
||||
final int iconRes = MimeTypeUtil.getFileTypeIconId(file.getMimeType(), file.getFileName());
|
||||
final String mimeType = file.isFolder() ? Document.MIME_TYPE_DIR : file.getMimeType();
|
||||
final String imagePath = MimeTypeUtil.isImage(file) && file.isDown() ? file.getStoragePath() : null;
|
||||
int flags = imagePath != null ? Document.FLAG_SUPPORTS_THUMBNAIL : 0;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
package third_parties.daveKoeller;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.resources.files.ServerFileInterface;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
|
@ -86,7 +86,7 @@ public class AlphanumComparator<T> implements Comparator<T>, Serializable {
|
|||
return chunk.toString();
|
||||
}
|
||||
|
||||
public int compare(OCFile o1, OCFile o2) {
|
||||
public int compare(ServerFileInterface o1, ServerFileInterface o2) {
|
||||
String s1 = o1.getFileName();
|
||||
String s2 = o2.getFileName();
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
|
||||
<path
|
||||
android:fillColor="#c4c4c4"
|
||||
android:pathData="M6.5,1 L6,2 L3,2 C2.446,2,2,2.446,2,3 L2,4 L14,4 L14,3 C14,2.446,13.554,2,13,2 L10,2 L9.5,1 Z M3,5 L3.875,14 C3.935,14.55,4.448,15,5,15 L11,15 C11.552,15,12.064,14.55,12.125,14 L13,5 Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
|
||||
<path
|
||||
android:fillColor="#6f6f6f"
|
||||
android:pathData="M6.5,1 L6,2 L3,2 C2.446,2,2,2.446,2,3 L2,4 L14,4 L14,3 C14,2.446,13.554,2,13,2 L10,2 L9.5,1 Z M3,5 L3.875,14 C3.935,14.55,4.448,15,5,15 L11,15 C11.552,15,12.064,14.55,12.125,14 L13,5 Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Tobias Kaminsky
|
||||
Copyright (C) 2018 Tobias Kaminsky
|
||||
Copyright (C) 2018 Nextcloud GmbH.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:fitsSystemWindows="true"
|
||||
android:focusable="true">
|
||||
|
||||
<!-- The main content view -->
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/navigation_bar"
|
||||
layout="@layout/toolbar_standard"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/bottom_navigation_view"
|
||||
android:layout_below="@+id/navigation_bar">
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipe_containing_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:footerDividersEnabled="false"
|
||||
android:visibility="visible">
|
||||
|
||||
<com.owncloud.android.ui.EmptyRecyclerView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/empty_list"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<android.support.design.widget.BottomNavigationView
|
||||
android:id="@+id/bottom_navigation_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:visibility="gone"
|
||||
app:itemBackground="@color/primary_button_background_color"
|
||||
app:itemIconTint="@color/primary_button_text_color"
|
||||
app:itemTextColor="@color/primary_button_text_color"
|
||||
app:menu="@menu/navigation_bar_menu"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/drawer"
|
||||
android:layout_width="@dimen/drawer_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"/>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
|
@ -0,0 +1,175 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
ownCloud Android client application
|
||||
|
||||
Copyright (C) 2012 Bartek Przybylski
|
||||
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/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/ListItemLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/standard_list_item_size"
|
||||
android:background="@drawable/list_selector"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/file_icon_size"
|
||||
android:layout_height="@dimen/file_icon_size"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="@dimen/standard_margin"
|
||||
android:layout_marginRight="@dimen/standard_margin"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:src="@drawable/folder"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/standard_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Filename"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:text="@string/placeholder_filename"
|
||||
android:textColor="@color/textColor"
|
||||
android:textSize="@dimen/two_line_primary_text_size"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileSize"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/placeholder_fileSize"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_separator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:paddingEnd="@dimen/standard_quarter_padding"
|
||||
android:paddingLeft="@dimen/zero"
|
||||
android:paddingRight="@dimen/standard_quarter_padding"
|
||||
android:paddingStart="@dimen/zero"
|
||||
android:text="@string/info_separator"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deletionTimestamp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="@string/placeholder_media_time"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/originalLocation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="@string/placeholder_filename"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingEnd="@dimen/zero"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/zero"
|
||||
android:paddingStart="@dimen/standard_half_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/restore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/restore"
|
||||
android:focusable="false"
|
||||
android:paddingEnd="@dimen/list_item_share_right_margin"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/list_item_share_right_margin"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_history"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/customCheckbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/restore"
|
||||
android:layout_toRightOf="@id/restore"
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/checkbox"
|
||||
android:focusable="false"
|
||||
android:paddingEnd="@dimen/alternate_padding"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/alternate_padding"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_checkbox_blank_outline"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/overflowMenu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/customCheckbox"
|
||||
android:layout_toRightOf="@id/customCheckbox"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/overflow_menu"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/alternate_padding"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/standard_half_padding"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_dots_vertical"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/list_divider_background"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -88,6 +88,11 @@
|
|||
android:icon="@drawable/nav_uploads"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/drawer_item_uploads_list"/>
|
||||
<item
|
||||
android:id="@+id/nav_trashbin"
|
||||
android:icon="@drawable/nav_trashbin"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/drawer_item_trashbin"/>
|
||||
</group>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Tobias Kaminsky
|
||||
Copyright (C) 2018 Tobias Kaminsky
|
||||
Copyright (C) 2018 Nextcloud GmbH.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu 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"
|
||||
tools:ignore="AppCompatResource">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_delete"
|
||||
android:orderInCategory="1"
|
||||
android:showAsAction="never"
|
||||
android:title="@string/common_remove"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Tobias Kaminsky
|
||||
Copyright (C) 2018 Tobias Kaminsky
|
||||
Copyright (C) 2018 Nextcloud GmbH.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu 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"
|
||||
tools:ignore="AppCompatResource">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_sort"
|
||||
android:contentDescription="@string/actionbar_sort"
|
||||
android:icon="@drawable/ic_sort_variant"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/actionbar_sort"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_empty_trashbin"
|
||||
android:contentDescription="@string/action_empty_trashbin"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/action_empty_trashbin"
|
||||
app:showAsAction="never"/>
|
||||
</menu>
|
|
@ -114,6 +114,8 @@
|
|||
<string name="file_list_empty_text_photos_filter">No photos.</string>
|
||||
<string name="file_list_empty_text_videos">Upload some videos or activate auto upload.</string>
|
||||
<string name="file_list_empty_text_videos_filter">No videos.</string>
|
||||
<string name="trashbin_empty_headline">No deleted files</string>
|
||||
<string name="trashbin_empty_message">You will be able to recover deleted files from here</string>
|
||||
<string name="upload_list_empty_headline">No uploads available</string>
|
||||
<string name="upload_list_empty_text_auto_upload">Upload some content or activate auto upload.</string>
|
||||
<string name="file_list_folder">folder</string>
|
||||
|
@ -807,4 +809,12 @@
|
|||
<string name="outdated_server">The server has reached end of life, please upgrade!</string>
|
||||
<string name="dismiss">Dismiss</string>
|
||||
<string name="feedback_no_mail_app">No app available to send mails!</string>
|
||||
<string name="drawer_item_trashbin">Deleted files</string>
|
||||
<string name="trashbin_activity_title">Deleted files</string>
|
||||
<string name="restore_deleted_file">Restore deleted file</string>
|
||||
<string name="action_empty_trashbin">Empty trashbin</string>
|
||||
<string name="trashbin_loading_failed">Loading trashbin failed!</string>
|
||||
<string name="trashbin_file_not_deleted">File %1$s could not be deleted!</string>
|
||||
<string name="trashbin_file_not_restored">File %1$s could not be restored!</string>
|
||||
<string name="trashbin_not_emptied">Trashbin could not emptied!</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue