diff --git a/app/src/main/java/com/nmc/android/ui/CommentsActionsBottomSheetDialog.kt b/app/src/main/java/com/nmc/android/ui/CommentsActionsBottomSheetDialog.kt
new file mode 100644
index 000000000000..af1891388176
--- /dev/null
+++ b/app/src/main/java/com/nmc/android/ui/CommentsActionsBottomSheetDialog.kt
@@ -0,0 +1,51 @@
+package com.nmc.android.ui
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import com.google.android.material.bottomsheet.BottomSheetBehavior
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.owncloud.android.databinding.CommentsActionsBottomSheetFragmentBinding
+import com.owncloud.android.operations.comments.Comments
+
+
+class CommentsActionsBottomSheetDialog(context: Context,
+ private val comments: Comments,
+ private val commentsBottomSheetActions: CommentsBottomSheetActions) : BottomSheetDialog(context) {
+
+ private lateinit var binding: CommentsActionsBottomSheetFragmentBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding = CommentsActionsBottomSheetFragmentBinding.inflate(layoutInflater)
+
+ setContentView(binding.root)
+
+ window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+ setOnShowListener {
+ BottomSheetBehavior.from(binding.root.parent as View)
+ .setPeekHeight(binding.root.measuredHeight)
+ }
+
+
+ binding.menuEditComment.setOnClickListener {
+ commentsBottomSheetActions.onUpdateComment(comments)
+ dismiss()
+ }
+
+ binding.menuDeleteComment.setOnClickListener {
+ commentsBottomSheetActions.onDeleteComment(comments)
+ dismiss()
+ }
+
+
+ }
+
+ interface CommentsBottomSheetActions {
+ fun onUpdateComment(comments: Comments)
+ fun onDeleteComment(comments: Comments)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/owncloud/android/operations/comments/Comments.kt b/app/src/main/java/com/owncloud/android/operations/comments/Comments.kt
new file mode 100644
index 000000000000..b86185cf6797
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/comments/Comments.kt
@@ -0,0 +1,63 @@
+package com.owncloud.android.operations.comments
+
+/**
+ * response from the Get comments api
+ *
+ *
+ *
+ * /remote.php/dav/comments/files/581625/
+ *
+ *
+ *
+ *
+ *
+ * Wed, 05 Oct 2022 07:54:20 GMT
+ *
+ * HTTP/1.1 200 OK
+ *
+ *
+ *
+ * /remote.php/dav/comments/files/581625/99
+ *
+ *
+ *
+ * 99
+ * 0
+ * 0
+ * 0
+ * Cghjgrrg
+ * comment
+ * users
+ * 120049010000000010088671
+ * Wed, 05 Oct 2022 07:54:20 GMT
+ *
+ * files
+ * 581625
+ *
+ *
+ * Dev.Kumar
+ *
+ * false
+ *
+ * HTTP/1.1 200 OK
+ *
+ *
+ *
+ */
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+import java.util.*
+
+@Parcelize
+data class Comments(val path: String,
+ val commentId: Int,
+ val message: String,
+ val actorId: String,
+ val actorDisplayName: String,
+ val actorType: String,
+ val creationDateTime: Date? = null,
+ val isUnread: Boolean = false,
+ val objectId: String,
+ val objectType: String,
+ val verb: String) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/owncloud/android/operations/comments/DeleteCommentRemoteOperation.java b/app/src/main/java/com/owncloud/android/operations/comments/DeleteCommentRemoteOperation.java
new file mode 100644
index 000000000000..589ceaef25e4
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/comments/DeleteCommentRemoteOperation.java
@@ -0,0 +1,82 @@
+/**
+ * ownCloud Android client application
+ *
+ * @author TSI-mc Copyright (C) 2021 TSI-mc
+ *
+ * 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
+ * .
+ */
+
+package com.owncloud.android.operations.comments;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+
+/**
+ * class to delete the comment
+ *
+ * API : //DELETE to dav/comments/files/{file_id}/{comment_id}
+ */
+public class DeleteCommentRemoteOperation extends RemoteOperation {
+
+ private static final String TAG = DeleteCommentRemoteOperation.class.getSimpleName();
+
+ private final long fileId;
+ private final int commentId;
+
+ public DeleteCommentRemoteOperation(long fileId, int commentId) {
+ this.fileId = fileId;
+ this.commentId = commentId;
+ }
+
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ RemoteOperationResult result;
+ int status;
+
+ DeleteMethod deleteMethod = null;
+
+ try {
+ //Delete Method
+ deleteMethod = new DeleteMethod(client.getCommentsUri(fileId) + "/" + commentId);
+
+ status = client.executeMethod(deleteMethod);
+
+ if (isSuccess(status)) {
+ result = new RemoteOperationResult<>(true, status, deleteMethod.getResponseHeaders());
+ return result;
+ } else {
+ result = new RemoteOperationResult<>(false, deleteMethod);
+ }
+
+ } catch (Exception e) {
+ result = new RemoteOperationResult<>(e);
+ Log_OC.e(TAG, "Exception while deleting comment", e);
+
+ } finally {
+ if (deleteMethod != null) {
+ deleteMethod.releaseConnection();
+ }
+ }
+ return result;
+ }
+
+ private boolean isSuccess(int status) {
+ return status == HttpStatus.SC_OK
+ || status == HttpStatus.SC_NO_CONTENT
+ || status == HttpStatus.SC_MULTI_STATUS;
+ }
+
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/comments/GetCommentsRemoteOperation.java b/app/src/main/java/com/owncloud/android/operations/comments/GetCommentsRemoteOperation.java
new file mode 100644
index 000000000000..4dd14db1857e
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/comments/GetCommentsRemoteOperation.java
@@ -0,0 +1,217 @@
+/**
+ * ownCloud Android client application
+ *
+ * @author TSI-mc Copyright (C) 2021 TSI-mc
+ *
+ * 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
+ * .
+ */
+
+package com.owncloud.android.operations.comments;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.network.WebdavEntry;
+import com.owncloud.android.lib.common.network.WebdavUtils;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.jackrabbit.webdav.MultiStatus;
+import org.apache.jackrabbit.webdav.MultiStatusResponse;
+import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.xml.Namespace;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * class to fetch the list of comments for the given fileId
+ *
+ * API : //PROPFIND to dav/comments/files/{file_id}
+ */
+public class GetCommentsRemoteOperation extends RemoteOperation {
+
+ private static final String TAG = GetCommentsRemoteOperation.class.getSimpleName();
+
+ private static final String EXTENDED_PROPERTY_ID = "id";
+ protected static final String EXTENDED_PROPERTY_MESSAGE = "message";
+ private static final String EXTENDED_PROPERTY_ACTOR_DISPLAY_NAME = "actorDisplayName";
+ private static final String EXTENDED_PROPERTY_ACTOR_ID = "actorId";
+ private static final String EXTENDED_PROPERTY_ACTOR_TYPE = "actorType";
+ private static final String EXTENDED_PROPERTY_CREATION_DATE_TIME = "creationDateTime";
+ private static final String EXTENDED_PROPERTY_IS_UNREAD = "isUnread";
+ private static final String EXTENDED_PROPERTY_OBJECT_ID = "objectId";
+ private static final String EXTENDED_PROPERTY_OBJECT_TYPE = "objectType";
+ private static final String EXTENDED_PROPERTY_VERB = "verb";
+
+ private static final int CODE_PROP_SUCCESS = 200;
+ private static final int CODE_PROP_NOT_FOUND = 404;
+
+ private final long fileId;
+ private final int limit, offset;
+
+ // TODO: 10/15/22 Add pagination
+ public GetCommentsRemoteOperation(long fileId, int limit, int offset) {
+ this.fileId = fileId;
+ this.limit = limit;
+ this.offset = offset;
+ }
+
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ PropFindMethod propFind = null;
+ RemoteOperationResult result = null;
+ try {
+ propFind = new PropFindMethod(client.getCommentsUri(fileId));
+ int status = client.executeMethod(propFind);
+
+ if (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK) {
+ MultiStatus dataInServer = propFind.getResponseBodyAsMultiStatus();
+
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK);
+ result.setResultData(parseComments(dataInServer));
+
+ }
+
+ if (status == HttpStatus.SC_NOT_FOUND) {
+ result = new RemoteOperationResult(RemoteOperationResult.ResultCode.FILE_NOT_FOUND);
+ }
+
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Error while retrieving comments");
+ result = new RemoteOperationResult(e);
+ } finally {
+ if (propFind != null) {
+ propFind.releaseConnection();
+ }
+ }
+
+ return result;
+
+ }
+
+ private List parseComments(MultiStatus dataInServer) {
+ List commentsList = new ArrayList<>();
+
+ Namespace ocNamespace = Namespace.getNamespace(WebdavEntry.NAMESPACE_OC);
+
+ for (MultiStatusResponse statusResponse : dataInServer.getResponses()) {
+
+ int status = statusResponse.getStatus()[0].getStatusCode();
+ if (status == CODE_PROP_NOT_FOUND) {
+ status = statusResponse.getStatus()[1].getStatusCode();
+ }
+
+ if (status != CODE_PROP_SUCCESS) {
+ continue;
+ }
+
+ DavPropertySet propSet = statusResponse.getProperties(status);
+
+ if (propSet == null) {
+ continue;
+ }
+
+ String path = statusResponse.getHref();
+
+ // OC id property
+ DavProperty> prop = propSet.get(EXTENDED_PROPERTY_ID, ocNamespace);
+ int commentId = 0;
+ if (prop != null) {
+ String id = (String) prop.getValue();
+ if (id != null) {
+ commentId = Integer.parseInt(id);
+ }
+ }
+
+ //don't look for other elements if commentId is missing or zero
+ if (commentId == 0) continue;
+
+ // OC message property
+ prop = propSet.get(EXTENDED_PROPERTY_MESSAGE, ocNamespace);
+ String message = "";
+ if (prop != null) {
+ message = (String) prop.getValue();
+ }
+
+ // OC actorId property
+ prop = propSet.get(EXTENDED_PROPERTY_ACTOR_ID, ocNamespace);
+ String actorId = "";
+ if (prop != null) {
+ actorId = (String) prop.getValue();
+ }
+
+ // OC actorDisplayName property
+ prop = propSet.get(EXTENDED_PROPERTY_ACTOR_DISPLAY_NAME, ocNamespace);
+ String actorDisplayName = "";
+ if (prop != null) {
+ actorDisplayName = (String) prop.getValue();
+ }
+
+ // OC actorType property
+ prop = propSet.get(EXTENDED_PROPERTY_ACTOR_TYPE, ocNamespace);
+ String actorType = "";
+ if (prop != null) {
+ actorType = (String) prop.getValue();
+ }
+
+ // OC creationDateTime property
+ prop = propSet.get(EXTENDED_PROPERTY_CREATION_DATE_TIME, ocNamespace);
+ Date creationDateTime = null;
+ if (prop != null) {
+ creationDateTime = WebdavUtils.parseResponseDate((String) prop.getValue());
+ }
+
+ // OC isUnread property
+ prop = propSet.get(EXTENDED_PROPERTY_IS_UNREAD, ocNamespace);
+ boolean isUnread = false;
+ if (prop != null) {
+ String value = (String) prop.getValue();
+ if (value != null) {
+ isUnread = Boolean.parseBoolean(value);
+ }
+ }
+
+ // OC objectId property
+ prop = propSet.get(EXTENDED_PROPERTY_OBJECT_ID, ocNamespace);
+ String objectId = "";
+ if (prop != null) {
+ objectId = (String) prop.getValue();
+ }
+
+ // OC objectType property
+ prop = propSet.get(EXTENDED_PROPERTY_OBJECT_TYPE, ocNamespace);
+ String objectType = "";
+ if (prop != null) {
+ objectType = (String) prop.getValue();
+ }
+
+ // OC verb property
+ prop = propSet.get(EXTENDED_PROPERTY_VERB, ocNamespace);
+ String verb = "";
+ if (prop != null) {
+ verb = (String) prop.getValue();
+ }
+
+ Comments comments = new Comments(path, commentId, message, actorId,
+ actorDisplayName, actorType, creationDateTime,
+ isUnread, objectId, objectType, verb);
+
+ commentsList.add(comments);
+ }
+
+ return commentsList;
+ }
+
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/comments/UpdateCommentRemoteOperation.java b/app/src/main/java/com/owncloud/android/operations/comments/UpdateCommentRemoteOperation.java
new file mode 100644
index 000000000000..8004b62aa63d
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/comments/UpdateCommentRemoteOperation.java
@@ -0,0 +1,93 @@
+/**
+ * ownCloud Android client application
+ *
+ * @author TSI-mc Copyright (C) 2021 TSI-mc
+ *
+ * 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
+ * .
+ */
+
+package com.owncloud.android.operations.comments;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.network.WebdavEntry;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
+import org.apache.jackrabbit.webdav.xml.Namespace;
+
+import java.io.IOException;
+
+/**
+ * class to update the comment
+ *
+ * API : //PROPPATCH to dav/comments/files/{file_id}/{comment_id}
+ */
+public class UpdateCommentRemoteOperation extends RemoteOperation {
+
+ private static final String TAG = UpdateCommentRemoteOperation.class.getSimpleName();
+
+ private final long fileId;
+ private final int commentId;
+ private final String message;
+
+ public UpdateCommentRemoteOperation(long fileId, int commentId, String message) {
+ this.fileId = fileId;
+ this.commentId = commentId;
+ this.message = message;
+ }
+
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ RemoteOperationResult result;
+ PropPatchMethod propPatchMethod = null;
+
+ DavPropertySet newProps = new DavPropertySet();
+ DavPropertyNameSet removeProperties = new DavPropertyNameSet();
+
+ DefaultDavProperty messageDavProperty = new DefaultDavProperty<>(GetCommentsRemoteOperation.EXTENDED_PROPERTY_MESSAGE, message,
+ Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
+ newProps.add(messageDavProperty);
+
+ String commentsPath = client.getCommentsUri(fileId) + "/" + commentId;
+
+ try {
+ propPatchMethod = new PropPatchMethod(commentsPath, newProps, removeProperties);
+ int status = client.executeMethod(propPatchMethod);
+
+ if (isSuccess(status)) {
+ result = new RemoteOperationResult(true, status, propPatchMethod.getResponseHeaders());
+ } else {
+ client.exhaustResponse(propPatchMethod.getResponseBodyAsStream());
+ result = new RemoteOperationResult(false, status, propPatchMethod.getResponseHeaders());
+ }
+ } catch (IOException e) {
+ result = new RemoteOperationResult(e);
+ } finally {
+ if (propPatchMethod != null) {
+ propPatchMethod.releaseConnection();
+ }
+ }
+
+ return result;
+ }
+
+ private boolean isSuccess(int status) {
+ return status == HttpStatus.SC_OK
+ || status == HttpStatus.SC_NO_CONTENT
+ || status == HttpStatus.SC_MULTI_STATUS;
+ }
+
+}
diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java
index 0cd2d5e30a31..7f60839e844e 100644
--- a/app/src/main/java/com/owncloud/android/services/OperationsService.java
+++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java
@@ -48,6 +48,7 @@
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
import com.owncloud.android.operations.CheckCurrentCredentialsOperation;
+import com.owncloud.android.operations.CommentFileOperation;
import com.owncloud.android.operations.CopyFileOperation;
import com.owncloud.android.operations.CreateFolderOperation;
import com.owncloud.android.operations.CreateShareViaLinkOperation;
@@ -63,6 +64,7 @@
import com.owncloud.android.operations.UpdateShareInfoOperation;
import com.owncloud.android.operations.UpdateSharePermissionsOperation;
import com.owncloud.android.operations.UpdateShareViaLinkOperation;
+import com.owncloud.android.operations.comments.GetCommentsRemoteOperation;
import java.io.IOException;
import java.util.Iterator;
@@ -100,6 +102,7 @@ public class OperationsService extends Service {
public static final String EXTRA_SHARE_ID = "SHARE_ID";
public static final String EXTRA_SHARE_NOTE = "SHARE_NOTE";
public static final String EXTRA_IN_BACKGROUND = "IN_BACKGROUND";
+ public static final String EXTRA_FILE_ID = "FILE_ID";
public static final String ACTION_CREATE_SHARE_VIA_LINK = "CREATE_SHARE_VIA_LINK";
public static final String ACTION_CREATE_SECURE_FILE_DROP = "CREATE_SECURE_FILE_DROP";
@@ -120,6 +123,7 @@ public class OperationsService extends Service {
public static final String ACTION_COPY_FILE = "COPY_FILE";
public static final String ACTION_CHECK_CURRENT_CREDENTIALS = "CHECK_CURRENT_CREDENTIALS";
public static final String ACTION_RESTORE_VERSION = "RESTORE_VERSION";
+ public static final String ACTION_GET_COMMENTS = "GET_COMMENTS";
private ServiceHandler mOperationsHandler;
private OperationsServiceBinder mOperationsBinder;
@@ -735,6 +739,15 @@ private Pair newOperation(Intent operationIntent) {
fileVersion.getFileName());
break;
+ case ACTION_GET_COMMENTS:
+ long fileId = operationIntent.getLongExtra(EXTRA_FILE_ID, 0L);
+ if (fileId > 0) {
+ operation = new GetCommentsRemoteOperation(fileId, 0, 0);
+ } else {
+ Log_OC.d(TAG, "Get Comments: empty or null fileId.");
+ }
+ break;
+
default:
// do nothing
break;
diff --git a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java
index 53aeb637f0cb..4f9a31574516 100644
--- a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java
@@ -20,6 +20,7 @@
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.activities.model.RichObject;
import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.operations.comments.Comments;
import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository;
import com.owncloud.android.ui.activities.data.files.FilesRepository;
import com.owncloud.android.ui.activity.DrawerActivity;
@@ -102,7 +103,8 @@ private void setupContent() {
this,
clientFactory,
false,
- viewThemeUtils);
+ viewThemeUtils,
+ null);
binding.list.setAdapter(adapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
@@ -161,6 +163,11 @@ public void onActivityClicked(RichObject richObject) {
actionListener.openActivity(path, this);
}
+ @Override
+ public void onCommentsOverflowMenuClicked(Comments comments) {
+ //nothing to be done here
+ }
+
@Override
public void showActivities(List