Skip to content

Commit 61c8a95

Browse files
committed
Adding files to Albums api integrated with flow and listing Album items thumbnail issue fixed.
1 parent a62fa0d commit 61c8a95

9 files changed

Lines changed: 235 additions & 6 deletions

File tree

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2021 Tobias Kaminsky <tobias@kaminsky.me>
5+
* SPDX-FileCopyrightText: 2019 Andy Scherzinger <info@andy-scherzinger.de>
6+
* SPDX-FileCopyrightText: 2012-2014 ownCloud Inc.
7+
* SPDX-FileCopyrightText: 2014 Jorge Antonio Diaz-Benito Soriano <jorge.diazbenitosoriano@gmail.com>
8+
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
9+
*/
10+
package com.owncloud.android.operations.albums;
11+
12+
import android.util.Log;
13+
14+
import com.owncloud.android.datamodel.FileDataStorageManager;
15+
import com.owncloud.android.datamodel.OCFile;
16+
import com.owncloud.android.lib.common.OwnCloudClient;
17+
import com.owncloud.android.lib.common.network.WebdavUtils;
18+
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
19+
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
20+
import com.owncloud.android.operations.UploadFileOperation;
21+
import com.owncloud.android.operations.common.SyncOperation;
22+
23+
import org.apache.jackrabbit.webdav.DavException;
24+
import org.apache.jackrabbit.webdav.MultiStatusResponse;
25+
import org.apache.jackrabbit.webdav.Status;
26+
import org.apache.jackrabbit.webdav.client.methods.CopyMethod;
27+
28+
import java.io.IOException;
29+
30+
/**
31+
* Operation copying an {@link OCFile} to a different folder.
32+
*
33+
* @author David A. Velasco
34+
*/
35+
public class CopyFileToAlbumOperation extends SyncOperation {
36+
private static final String TAG = CopyFileToAlbumOperation.class.getSimpleName();
37+
38+
private final String srcPath;
39+
private String targetParentPath;
40+
41+
/**
42+
* Constructor
43+
*
44+
* @param srcPath Remote path of the {@link OCFile} to move.
45+
* @param targetParentPath Path to the folder where the file will be copied into.
46+
*/
47+
public CopyFileToAlbumOperation(String srcPath, String targetParentPath, FileDataStorageManager storageManager) {
48+
super(storageManager);
49+
50+
this.srcPath = srcPath;
51+
this.targetParentPath = targetParentPath;
52+
if (!this.targetParentPath.endsWith(OCFile.PATH_SEPARATOR)) {
53+
this.targetParentPath += OCFile.PATH_SEPARATOR;
54+
}
55+
}
56+
57+
/**
58+
* Performs the operation.
59+
*
60+
* @param client Client object to communicate with the remote ownCloud server.
61+
*/
62+
@Override
63+
protected RemoteOperationResult run(OwnCloudClient client) {
64+
/// 1. check copy validity
65+
if (targetParentPath.startsWith(srcPath)) {
66+
return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT);
67+
}
68+
OCFile file = getStorageManager().getFileByPath(srcPath);
69+
if (file == null) {
70+
return new RemoteOperationResult(ResultCode.FILE_NOT_FOUND);
71+
}
72+
73+
/// 2. remote copy
74+
String targetPath = targetParentPath + file.getFileName();
75+
if (file.isFolder()) {
76+
targetPath += OCFile.PATH_SEPARATOR;
77+
}
78+
79+
// auto rename, to allow copy
80+
if (targetPath.equals(srcPath)) {
81+
if (file.isFolder()) {
82+
targetPath = targetParentPath + file.getFileName();
83+
}
84+
targetPath = UploadFileOperation.getNewAvailableRemotePath(client, targetPath, null, false);
85+
86+
if (file.isFolder()) {
87+
targetPath += OCFile.PATH_SEPARATOR;
88+
}
89+
}
90+
91+
RemoteOperationResult result = performCopyOperation(targetPath, client);
92+
93+
/// 3. local copy
94+
if (result.isSuccess()) {
95+
getStorageManager().copyLocalFile(file, targetPath);
96+
}
97+
// TODO handle ResultCode.PARTIAL_COPY_DONE in client Activity, for the moment
98+
99+
return result;
100+
}
101+
102+
private RemoteOperationResult performCopyOperation(String targetRemotePath, OwnCloudClient client) {
103+
if (targetRemotePath.equals(this.srcPath)) {
104+
return new RemoteOperationResult(ResultCode.OK);
105+
} else if (targetRemotePath.startsWith(this.srcPath)) {
106+
return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT);
107+
} else {
108+
CopyMethod copyMethod = null;
109+
RemoteOperationResult result = null;
110+
111+
try {
112+
copyMethod = new CopyMethod(client.getFilesDavUri(this.srcPath), "https://pre1.next.magentacloud.de/remote.php/dav/photos/" + client.getUserId() + "/albums/" + WebdavUtils.encodePath(targetRemotePath), false);
113+
int status = client.executeMethod(copyMethod);
114+
if (status == 207) {
115+
result = this.processPartialError(copyMethod);
116+
} else if (status == 412) {
117+
result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
118+
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
119+
} else {
120+
result = new RemoteOperationResult(this.isSuccess(status), copyMethod);
121+
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
122+
}
123+
124+
Log.i(TAG, "Copy " + this.srcPath + " to " + targetRemotePath + ": " + result.getLogMessage());
125+
} catch (Exception e) {
126+
result = new RemoteOperationResult(e);
127+
Log.e(TAG, "Copy " + this.srcPath + " to " + targetRemotePath + ": " + result.getLogMessage(), e);
128+
} finally {
129+
if (copyMethod != null) {
130+
copyMethod.releaseConnection();
131+
}
132+
133+
}
134+
135+
return result;
136+
}
137+
}
138+
139+
private RemoteOperationResult processPartialError(CopyMethod copyMethod) throws IOException, DavException {
140+
MultiStatusResponse[] responses = copyMethod.getResponseBodyAsMultiStatus().getResponses();
141+
boolean failFound = false;
142+
143+
for (int i = 0; i < responses.length && !failFound; ++i) {
144+
Status[] status = responses[i].getStatus();
145+
failFound = status != null && status.length > 0 && status[0].getStatusCode() > 299;
146+
}
147+
148+
RemoteOperationResult result;
149+
if (failFound) {
150+
result = new RemoteOperationResult(ResultCode.PARTIAL_COPY_DONE);
151+
} else {
152+
result = new RemoteOperationResult(true, copyMethod);
153+
}
154+
155+
return result;
156+
}
157+
158+
protected boolean isSuccess(int status) {
159+
return status == 201 || status == 204;
160+
}
161+
}

app/src/main/java/com/owncloud/android/operations/albums/ReadAlbumItemsOperation.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import android.net.Uri;
1414

15+
import com.owncloud.android.datamodel.FileDataStorageManager;
1516
import com.owncloud.android.datamodel.OCFile;
1617
import com.owncloud.android.lib.common.OwnCloudClient;
1718
import com.owncloud.android.lib.common.network.WebdavEntry;
@@ -33,8 +34,10 @@ public class ReadAlbumItemsOperation extends RemoteOperation<List<OCFile>> {
3334
private static final String TAG = ReadAlbumItemsOperation.class.getSimpleName();
3435
private final String albumPath;
3536
private ArrayList<OCFile> mFolderAndFiles;
37+
private final FileDataStorageManager fileDataStorageManager;
3638

37-
public ReadAlbumItemsOperation(String albumPath) {
39+
public ReadAlbumItemsOperation(String albumPath, FileDataStorageManager fileDataStorageManager) {
40+
this.fileDataStorageManager = fileDataStorageManager;
3841
Log_OC.e(TAG, "Reading Album Operations");
3942
this.albumPath = albumPath;
4043
}
@@ -43,7 +46,7 @@ protected RemoteOperationResult<List<OCFile>> run(OwnCloudClient client) {
4346
Log_OC.e(TAG, "Reading Album Operations running");
4447
RemoteOperationResult<List<OCFile>> result = null;
4548
PropFindMethod query = null;
46-
String url = "https://pre1.next.magentacloud.de/remote.php/dav/photos/" + client.getUserId() + "/albums/" + WebdavUtils.encodePath(albumPath);
49+
String url = "https://pre1.next.magentacloud.de/remote.php/dav/photos/" + client.getUserId() + "/albums" + WebdavUtils.encodePath(albumPath);
4750
try {
4851
query = new PropFindMethod(url, WebdavUtils.getAllPropSet(), 1);
4952
int status = client.executeMethod(query);
@@ -91,7 +94,10 @@ private void readData(MultiStatus remoteData, OwnCloudClient client) {
9194
for (int i = 1; i < remoteData.getResponses().length; ++i) {
9295
WebdavEntry we = new WebdavEntry(remoteData.getResponses()[i], Uri.parse(url).getEncodedPath());
9396
RemoteFile remoteFile = new RemoteFile(we);
94-
OCFile ocFile = FileStorageUtils.fillOCFile(remoteFile);
97+
OCFile ocFile = fileDataStorageManager.getFileByLocalId(remoteFile.getLocalId());
98+
if (ocFile == null) {
99+
ocFile = FileStorageUtils.fillOCFile(remoteFile);
100+
}
95101
this.mFolderAndFiles.add(ocFile);
96102
}
97103

app/src/main/java/com/owncloud/android/services/OperationsService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import com.owncloud.android.operations.UpdateShareInfoOperation;
6565
import com.owncloud.android.operations.UpdateSharePermissionsOperation;
6666
import com.owncloud.android.operations.UpdateShareViaLinkOperation;
67+
import com.owncloud.android.operations.albums.CopyFileToAlbumOperation;
6768
import com.owncloud.android.operations.albums.CreateNewAlbumOperation;
6869

6970
import java.io.IOException;
@@ -125,6 +126,7 @@ public class OperationsService extends Service {
125126
public static final String ACTION_UPDATE_FILES_DOWNLOAD_LIMIT = "UPDATE_FILES_DOWNLOAD_LIMIT";
126127
public static final String ACTION_CREATE_ALBUM = "CREATE_ALBUM";
127128
public static final String EXTRA_ALBUM_NAME = "ALBUM_NAME";
129+
public static final String ACTION_ALBUM_COPY_FILE = "ALBUM_COPY_FILE";
128130

129131
private ServiceHandler mOperationsHandler;
130132
private OperationsServiceBinder mOperationsBinder;
@@ -735,6 +737,12 @@ private Pair<Target, RemoteOperation> newOperation(Intent operationIntent) {
735737
operation = new CopyFileOperation(remotePath, newParentPath, fileDataStorageManager);
736738
break;
737739

740+
case ACTION_ALBUM_COPY_FILE:
741+
remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
742+
newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
743+
operation = new CopyFileToAlbumOperation(remotePath, newParentPath, fileDataStorageManager);
744+
break;
745+
738746
case ACTION_CHECK_CURRENT_CREDENTIALS:
739747
operation = new CheckCurrentCredentialsOperation(user, fileDataStorageManager);
740748
break;

app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
import com.owncloud.android.ui.fragment.GroupfolderListFragment;
9494
import com.owncloud.android.ui.fragment.OCFileListFragment;
9595
import com.owncloud.android.ui.fragment.SharedListFragment;
96+
import com.owncloud.android.ui.fragment.albums.AlbumItemsFragment;
9697
import com.owncloud.android.ui.fragment.albums.AlbumsFragment;
9798
import com.owncloud.android.ui.preview.PreviewTextStringFragment;
9899
import com.owncloud.android.ui.trashbin.TrashbinActivity;
@@ -612,6 +613,11 @@ public boolean isAlbumsFragmentVisible() {
612613
return albumsFragment != null && albumsFragment.isVisible();
613614
}
614615

616+
public boolean isAlbumItemsFragmentVisible() {
617+
Fragment albumsFragment = getSupportFragmentManager().findFragmentByTag(AlbumItemsFragment.Companion.getTAG());
618+
return albumsFragment != null && albumsFragment.isVisible();
619+
}
620+
615621
private void startComposeActivity(ComposeDestination destination, int titleId) {
616622
Intent composeActivity = new Intent(getApplicationContext(), ComposeActivity.class);
617623
composeActivity.putExtra(ComposeActivity.DESTINATION, destination);

app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
import com.owncloud.android.operations.RenameFileOperation;
101101
import com.owncloud.android.operations.SynchronizeFileOperation;
102102
import com.owncloud.android.operations.UploadFileOperation;
103+
import com.owncloud.android.operations.albums.CopyFileToAlbumOperation;
103104
import com.owncloud.android.operations.albums.CreateNewAlbumOperation;
104105
import com.owncloud.android.syncadapter.FileSyncAdapter;
105106
import com.owncloud.android.ui.activity.fileDisplayActivity.OfflineFolderConflictManager;
@@ -1834,6 +1835,8 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe
18341835
onRestoreFileVersionOperationFinish(result);
18351836
} else if (operation instanceof CreateNewAlbumOperation createNewAlbumOperation) {
18361837
onCreateAlbumOperationFinish(createNewAlbumOperation, result);
1838+
} else if (operation instanceof CopyFileToAlbumOperation copyFileOperation) {
1839+
onCopyAlbumFileOperationFinish(copyFileOperation, result);
18371840
}
18381841
}
18391842

@@ -1986,6 +1989,19 @@ private void onCopyFileOperationFinish(CopyFileOperation operation, RemoteOperat
19861989
}
19871990
}
19881991

1992+
private void onCopyAlbumFileOperationFinish(CopyFileToAlbumOperation operation, RemoteOperationResult result) {
1993+
if (result.isSuccess()) {
1994+
DisplayUtils.showSnackMessage(this, "File added successfully");
1995+
Log_OC.e(TAG, "Files copied successfully");
1996+
} else {
1997+
try {
1998+
DisplayUtils.showSnackMessage(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()));
1999+
} catch (NotFoundException e) {
2000+
Log_OC.e(TAG, "Error while trying to show fail message ", e);
2001+
}
2002+
}
2003+
}
2004+
19892005
/**
19902006
* Updates the view associated to the activity after the finish of an operation trying to rename a file.
19912007
*

app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.view.View;
2323
import android.view.ViewGroup;
2424

25+
import com.nextcloud.client.network.ConnectivityService;
2526
import com.nextcloud.utils.extensions.IntentExtensionsKt;
2627
import com.owncloud.android.BuildConfig;
2728
import com.owncloud.android.R;
@@ -38,6 +39,10 @@
3839
import com.owncloud.android.ui.asynctasks.GallerySearchTask;
3940
import com.owncloud.android.ui.events.ChangeMenuEvent;
4041
import com.owncloud.android.ui.fragment.albums.AlbumsFragment;
42+
import com.owncloud.android.utils.DisplayUtils;
43+
44+
import java.util.ArrayList;
45+
import java.util.Set;
4146

4247
import javax.inject.Inject;
4348

@@ -68,6 +73,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
6873
private GalleryFragmentBottomSheetDialog galleryFragmentBottomSheetDialog;
6974

7075
@Inject FileDataStorageManager fileDataStorageManager;
76+
@Inject ConnectivityService connectivityService;
7177
private final static int maxColumnSizeLandscape = 5;
7278
private final static int maxColumnSizePortrait = 2;
7379
private int columnSize;
@@ -434,7 +440,7 @@ public void markAsFavorite(String remotePath, boolean favorite) {
434440
mAdapter.markAsFavorite(remotePath, favorite);
435441
}
436442

437-
public void addImagesToAlbum() {
443+
public void addImagesToAlbum(Set<OCFile> checkedFiles) {
438444
FragmentTransaction transaction = requireActivity().getSupportFragmentManager().beginTransaction();
439445
transaction.addToBackStack(null);
440446
transaction.add(R.id.left_fragment_container, AlbumsFragment.Companion.newInstance(true), AlbumsFragment.Companion.getTAG());
@@ -443,6 +449,18 @@ public void addImagesToAlbum() {
443449
if (requestKey.equals(AlbumsFragment.SELECT_ALBUM_REQ_KEY)) {
444450
String albumName = bundle.getString(AlbumsFragment.ARG_SELECTED_ALBUM_NAME);
445451
Log_OC.e(TAG, "Selected album name: " + albumName);
452+
453+
connectivityService.isNetworkAndServerAvailable(result -> {
454+
if (result) {
455+
final ArrayList<String> paths = new ArrayList<>(checkedFiles.size());
456+
for (OCFile file : checkedFiles) {
457+
paths.add(file.getRemotePath());
458+
}
459+
mContainerActivity.getFileOperationsHelper().albumCopyFiles(paths, albumName);
460+
} else {
461+
DisplayUtils.showSnackMessage(requireActivity(), getString(R.string.offline_mode));
462+
}
463+
});
446464
}
447465
});
448466
}

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2200,8 +2200,10 @@ public void setFabVisible(final boolean visible) {
22002200
return;
22012201
}
22022202

2203+
// NMC Customizations: to hide the fab if user is on Albums Fragment
22032204
if (requireActivity() instanceof FileDisplayActivity fda
2204-
&& fda.isAlbumsFragmentVisible()) {
2205+
&& (fda.isAlbumsFragmentVisible()
2206+
|| fda.isAlbumItemsFragmentVisible())) {
22052207
mFabMain.hide();
22062208
return;
22072209
}

app/src/main/java/com/owncloud/android/ui/fragment/albums/AlbumItemsFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class AlbumItemsFragment : Fragment(), OCFileListFragmentInterface, Injectable {
189189
initializeAdapter()
190190
val t = Thread {
191191
setEmptyListLoadingMessage()
192-
val getRemoteNotificationOperation = ReadAlbumItemsOperation(albumName)
192+
val getRemoteNotificationOperation = ReadAlbumItemsOperation(albumName, mContainerActivity?.storageManager)
193193
val result = client?.let { getRemoteNotificationOperation.execute(it) }
194194
if (result?.isSuccess == true && result.resultData != null) {
195195
if (result.resultData.isEmpty()) {

app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,18 @@ public void moveOrCopyFiles(String action, final List<String> filePaths, final O
10101010
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
10111011
}
10121012

1013+
public void albumCopyFiles(final List<String> filePaths, final String targetFolder) {
1014+
for (String path : filePaths) {
1015+
Intent service = new Intent(fileActivity, OperationsService.class);
1016+
service.setAction(OperationsService.ACTION_ALBUM_COPY_FILE);
1017+
service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder);
1018+
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, path);
1019+
service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
1020+
mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
1021+
}
1022+
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
1023+
}
1024+
10131025
public void exportFiles(Collection<OCFile> files,
10141026
Context context,
10151027
View view,

0 commit comments

Comments
 (0)