diff --git a/app/src/androidTest/java/com/nmc/android/ui/FileSharingIT.kt b/app/src/androidTest/java/com/nmc/android/ui/FileSharingIT.kt
index 27f64df78d40..91c8cf7fdfb1 100644
--- a/app/src/androidTest/java/com/nmc/android/ui/FileSharingIT.kt
+++ b/app/src/androidTest/java/com/nmc/android/ui/FileSharingIT.kt
@@ -340,7 +340,7 @@ class FileSharingIT : AbstractIT() {
)
)
- val permissionList = permissionList(isFolder, ocShare.shareType)
+ val permissionList = permissionList(isFolder, ocShare.shareType!!)
for (i in permissionList.indices) {
// Scroll to the item at position i
diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt
index 404f31485b2d..7bf0da364642 100644
--- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt
+++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt
@@ -269,6 +269,7 @@ class FileDetailSharingFragmentIT : AbstractIT() {
onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed()))
onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed()))
onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed())))
+ onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(not(isDisplayed())))
// read-only
onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isChecked()))
@@ -397,6 +398,7 @@ class FileDetailSharingFragmentIT : AbstractIT() {
onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed()))
onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed()))
onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed())))
+ onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(isDisplayed()))
// read-only
publicShare.permissions = 17 // from server
@@ -514,6 +516,7 @@ class FileDetailSharingFragmentIT : AbstractIT() {
onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed())))
onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed())))
onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isDisplayed()))
+ onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(not(isDisplayed())))
// read-only
userShare.permissions = 17 // from server
@@ -637,6 +640,7 @@ class FileDetailSharingFragmentIT : AbstractIT() {
onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed())))
onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed())))
onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isDisplayed()))
+ onView(ViewMatchers.withId(R.id.share_process_download_limit_switch)).check(matches(not(isDisplayed())))
// read-only
userShare.permissions = 17 // from server
diff --git a/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java
index 6fa42d1ca754..dbec888aed48 100644
--- a/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java
+++ b/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java
@@ -149,6 +149,11 @@ protected RemoteOperationResult run(OwnCloudClient client) {
updateShareInfoOperation.setHideFileDownload(hideFileDownload);
updateShareInfoOperation.setLabel(label);
+ //update the permission using update info api
+ //because for external share the selected permission is not getting updated
+ //instead default Read/View Only permission is getting updated
+ updateShareInfoOperation.setPermissions(permissions);
+
//execute and save the result in database
RemoteOperationResult updateShareInfoResult = updateShareInfoOperation.execute(client);
if (updateShareInfoResult.isSuccess() && updateShareInfoResult.getData().size() > 0) {
diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java
index 580cfc7f2b56..1022ccdb056c 100644
--- a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java
+++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java
@@ -27,10 +27,14 @@
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 com.owncloud.android.lib.resources.shares.GetShareRemoteOperation;
import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.shares.UpdateShareRemoteOperation;
import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.operations.share_download_limit.DeleteShareDownloadLimitRemoteOperation;
+import com.owncloud.android.operations.share_download_limit.UpdateShareDownloadLimitRemoteOperation;
/**
@@ -38,6 +42,7 @@
*/
public class UpdateShareInfoOperation extends SyncOperation {
+ private static final String TAG = UpdateShareInfoOperation.class.getSimpleName();
private OCShare share;
private long shareId;
private long expirationDateInMillis;
@@ -46,6 +51,8 @@ public class UpdateShareInfoOperation extends SyncOperation {
private int permissions = -1;
private String password;
private String label;
+ //download limit for link share
+ private long downloadLimit;
/**
* Constructor
@@ -116,6 +123,9 @@ protected RemoteOperationResult run(OwnCloudClient client) {
if (result.isSuccess() && shareId > 0) {
OCShare ocShare = (OCShare) result.getData().get(0);
ocShare.setPasswordProtected(!TextUtils.isEmpty(password));
+
+ executeShareDownloadLimitOperation(client, ocShare);
+
getStorageManager().saveShare(ocShare);
}
@@ -124,6 +134,44 @@ protected RemoteOperationResult run(OwnCloudClient client) {
return result;
}
+ /**
+ * method will be used to update or delete the download limit for the particular share
+ *
+ * @param client
+ * @param ocShare share object
+ */
+ private void executeShareDownloadLimitOperation(OwnCloudClient client, OCShare ocShare) {
+ //if share type is of Link Share then only we have to update the download limit if configured by user
+ if (ocShare.getShareType() == ShareType.PUBLIC_LINK && !ocShare.isFolder()) {
+
+ //if download limit it greater than 0 then update the limit
+ //else delete the download limit
+ if (downloadLimit > 0) {
+ //api will update the download limit for the particular share
+ UpdateShareDownloadLimitRemoteOperation updateShareDownloadLimitRemoteOperation =
+ new UpdateShareDownloadLimitRemoteOperation(ocShare.getToken(), downloadLimit);
+
+ RemoteOperationResult downloadLimitOp =
+ updateShareDownloadLimitRemoteOperation.execute(client);
+ if (downloadLimitOp.isSuccess()) {
+ Log_OC.d(TAG, "Download limit updated for the share.");
+ Log_OC.d(TAG, "Download limit " + downloadLimit);
+ }
+ } else {
+ //api will delete the download limit for the particular share
+ DeleteShareDownloadLimitRemoteOperation limitRemoteOperation =
+ new DeleteShareDownloadLimitRemoteOperation(ocShare.getToken());
+
+ RemoteOperationResult deleteDownloadLimitOp =
+ limitRemoteOperation.execute(client);
+ if (deleteDownloadLimitOp.isSuccess()) {
+ Log_OC.d(TAG, "Download limit delete for the share.");
+ }
+ }
+
+ }
+ }
+
public void setExpirationDateInMillis(long expirationDateInMillis) {
this.expirationDateInMillis = expirationDateInMillis;
}
@@ -147,5 +195,9 @@ public void setPassword(String password) {
public void setLabel(String label) {
this.label = label;
}
+
+ public void setDownloadLimit(long downloadLimit) {
+ this.downloadLimit = downloadLimit;
+ }
}
diff --git a/app/src/main/java/com/owncloud/android/operations/share_download_limit/DeleteShareDownloadLimitRemoteOperation.java b/app/src/main/java/com/owncloud/android/operations/share_download_limit/DeleteShareDownloadLimitRemoteOperation.java
new file mode 100644
index 000000000000..303042240c60
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/share_download_limit/DeleteShareDownloadLimitRemoteOperation.java
@@ -0,0 +1,90 @@
+/**
+ * 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.share_download_limit;
+
+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 download limit for the link share
+ * this has to be executed when user has toggled off the download limit
+ *
+ * API : //DELETE to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit
+ */
+public class DeleteShareDownloadLimitRemoteOperation extends RemoteOperation {
+
+ private static final String TAG = DeleteShareDownloadLimitRemoteOperation.class.getSimpleName();
+
+ private final String shareToken;
+
+ public DeleteShareDownloadLimitRemoteOperation(String shareToken) {
+ this.shareToken = shareToken;
+ }
+
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ RemoteOperationResult result;
+ int status;
+
+ DeleteMethod deleteMethod = null;
+
+ try {
+ // Post Method
+ deleteMethod = new DeleteMethod(client.getBaseUri() + ShareDownloadLimitUtils.INSTANCE.getDownloadLimitApiPath(shareToken));
+
+ deleteMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
+
+ status = client.executeMethod(deleteMethod);
+
+ if (isSuccess(status)) {
+ String response = deleteMethod.getResponseBodyAsString();
+
+ Log_OC.d(TAG, "Delete Download Limit response: " + response);
+
+ DownloadLimitXMLParser parser = new DownloadLimitXMLParser();
+ result = parser.parse(true, response);
+
+ if (result.isSuccess()) {
+ return result;
+ }
+
+ } else {
+ result = new RemoteOperationResult<>(false, deleteMethod);
+ }
+
+ } catch (Exception e) {
+ result = new RemoteOperationResult<>(e);
+ Log_OC.e(TAG, "Exception while deleting share download limit", e);
+
+ } finally {
+ if (deleteMethod != null) {
+ deleteMethod.releaseConnection();
+ }
+ }
+ return result;
+ }
+
+ private boolean isSuccess(int status) {
+ return status == HttpStatus.SC_OK || status == HttpStatus.SC_BAD_REQUEST;
+ }
+
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitResponse.java b/app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitResponse.java
new file mode 100644
index 000000000000..f54edb17fc60
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitResponse.java
@@ -0,0 +1,37 @@
+package com.owncloud.android.operations.share_download_limit;
+
+/**
+ * response from the Get download limit api
+ *
+ *
+ *
+ * ok
+ * 200
+ * OK
+ *
+ *
+ * 5
+ * 0
+ *
+ *
+ */
+public class DownloadLimitResponse {
+ private long limit;
+ private long count;
+
+ public long getLimit() {
+ return limit;
+ }
+
+ public void setLimit(long limit) {
+ this.limit = limit;
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public void setCount(long count) {
+ this.count = count;
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitXMLParser.java b/app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitXMLParser.java
new file mode 100644
index 000000000000..07121f52e110
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitXMLParser.java
@@ -0,0 +1,323 @@
+package com.owncloud.android.operations.share_download_limit;
+
+import android.util.Xml;
+
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * class to parse the Download Limit api XML response This class code referenced from java in NC library
+ */
+public class DownloadLimitXMLParser {
+ private static final String TAG = DownloadLimitXMLParser.class.getSimpleName();
+
+ // No namespaces
+ private static final String ns = null;
+
+ // NODES for XML Parser
+ private static final String NODE_OCS = "ocs";
+
+ private static final String NODE_META = "meta";
+ private static final String NODE_STATUS = "status";
+ private static final String NODE_STATUS_CODE = "statuscode";
+ private static final String NODE_MESSAGE = "message";
+
+ private static final String NODE_DATA = "data";
+ private static final String NODE_LIMIT = "limit";
+ private static final String NODE_COUNT = "count";
+
+ private static final int SUCCESS = 100;
+ private static final int OK = 200;
+ private static final int ERROR_WRONG_PARAMETER = 400;
+ private static final int ERROR_FORBIDDEN = 403;
+ private static final int ERROR_NOT_FOUND = 404;
+
+ private String mStatus;
+ private int mStatusCode;
+ private String mMessage = "";
+
+ // Getters and Setters
+ public String getStatus() {
+ return mStatus;
+ }
+
+ public void setStatus(String status) {
+ this.mStatus = status;
+ }
+
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.mStatusCode = statusCode;
+ }
+
+ public String getMessage() {
+ return mMessage;
+ }
+
+ public boolean isSuccess() {
+ return mStatusCode == SUCCESS || mStatusCode == OK;
+ }
+
+ public boolean isForbidden() {
+ return mStatusCode == ERROR_FORBIDDEN;
+ }
+
+ public boolean isNotFound() {
+ return mStatusCode == ERROR_NOT_FOUND;
+ }
+
+ public boolean isWrongParameter() {
+ return mStatusCode == ERROR_WRONG_PARAMETER;
+ }
+
+ public void setMessage(String message) {
+ this.mMessage = message;
+ }
+
+ /**
+ * method to parse the Download limit response
+ * @param isGet check if parsing has to do for GET api or not
+ * because the parsing will depend on that
+ * if API is GET then response will have tag else it wont have
+ * @param serverResponse
+ * @return
+ */
+ public RemoteOperationResult parse(boolean isGet, String serverResponse) {
+ if (serverResponse == null || serverResponse.length() == 0) {
+ return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
+ }
+
+ RemoteOperationResult result;
+ try {
+ // Parse xml response and obtain the list of downloadLimitResponse
+ InputStream is = new ByteArrayInputStream(serverResponse.getBytes());
+
+ DownloadLimitResponse downloadLimitResponse = parseXMLResponse(is);
+
+ if (isSuccess()) {
+ if (downloadLimitResponse != null && isGet) {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK);
+ result.setResultData(downloadLimitResponse);
+ } else if (!isGet) {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK);
+ } else {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
+ Log_OC.e(TAG, "Successful status with no share in the response");
+ }
+ } else if (isWrongParameter()) {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER);
+ result.setMessage(getMessage());
+ } else if (isNotFound()) {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND);
+ result.setMessage(getMessage());
+ } else if (isForbidden()) {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN);
+ result.setMessage(getMessage());
+ } else {
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
+ result.setMessage(getMessage());
+ }
+
+ } catch (XmlPullParserException e) {
+ Log_OC.e(TAG, "Error parsing response from server ", e);
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
+
+ } catch (IOException e) {
+ Log_OC.e(TAG, "Error reading response from server ", e);
+ result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
+ }
+
+ return result;
+ }
+
+ /**
+ * Parse is as response of Share API
+ *
+ * @param is InputStream to parse
+ * @return List of ShareRemoteFiles
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private DownloadLimitResponse parseXMLResponse(InputStream is) throws XmlPullParserException, IOException {
+ try {
+ // XMLPullParser
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+ parser.setInput(is, null);
+ parser.nextTag();
+ return readOCS(parser);
+
+ } finally {
+ is.close();
+ }
+ }
+
+ /**
+ * Parse OCS node
+ *
+ * @param parser
+ * @return List of ShareRemoteFiles
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private DownloadLimitResponse readOCS(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ DownloadLimitResponse downloadLimitResponse = new DownloadLimitResponse();
+ parser.require(XmlPullParser.START_TAG, ns, NODE_OCS);
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // read NODE_META and NODE_DATA
+ if (NODE_META.equalsIgnoreCase(name)) {
+ readMeta(parser);
+ } else if (NODE_DATA.equalsIgnoreCase(name)) {
+ downloadLimitResponse = readData(parser);
+ } else {
+ skip(parser);
+ }
+
+ }
+ return downloadLimitResponse;
+
+
+ }
+
+ /**
+ * Parse Meta node
+ *
+ * @param parser
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void readMeta(XmlPullParser parser) throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, ns, NODE_META);
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+
+ if (NODE_STATUS.equalsIgnoreCase(name)) {
+ setStatus(readNode(parser, NODE_STATUS));
+
+ } else if (NODE_STATUS_CODE.equalsIgnoreCase(name)) {
+ setStatusCode(Integer.parseInt(readNode(parser, NODE_STATUS_CODE)));
+
+ } else if (NODE_MESSAGE.equalsIgnoreCase(name)) {
+ setMessage(readNode(parser, NODE_MESSAGE));
+
+ } else {
+ skip(parser);
+ }
+
+ }
+ }
+
+ /**
+ * Parse Data node
+ *
+ * @param parser
+ * @return
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private DownloadLimitResponse readData(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ DownloadLimitResponse downloadLimitResponse = new DownloadLimitResponse();
+
+ parser.require(XmlPullParser.START_TAG, ns, NODE_DATA);
+ //Log_OC.d(TAG, "---- NODE DATA ---");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ if (NODE_LIMIT.equalsIgnoreCase(name)) {
+ downloadLimitResponse.setLimit(Long.parseLong(readNode(parser, NODE_LIMIT)));
+ } else if (NODE_COUNT.equalsIgnoreCase(name)) {
+ downloadLimitResponse.setCount(Long.parseLong(readNode(parser, NODE_COUNT)));
+ } else {
+ skip(parser);
+ }
+ }
+
+ return downloadLimitResponse;
+ }
+
+
+ /**
+ * Parse a node, to obtain its text. Needs readText method
+ *
+ * @param parser
+ * @param node
+ * @return Text of the node
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private String readNode(XmlPullParser parser, String node) throws XmlPullParserException,
+ IOException {
+ parser.require(XmlPullParser.START_TAG, ns, node);
+ String value = readText(parser);
+ //Log_OC.d(TAG, "node= " + node + ", value= " + value);
+ parser.require(XmlPullParser.END_TAG, ns, node);
+ return value;
+ }
+
+
+ /**
+ * Read the text from a node
+ *
+ * @param parser
+ * @return Text of the node
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
+ String result = "";
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+ return result;
+ }
+
+ /**
+ * Skip tags in parser procedure
+ *
+ * @param parser
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/share_download_limit/GetShareDownloadLimitOperation.java b/app/src/main/java/com/owncloud/android/operations/share_download_limit/GetShareDownloadLimitOperation.java
new file mode 100644
index 000000000000..f10036961823
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/share_download_limit/GetShareDownloadLimitOperation.java
@@ -0,0 +1,90 @@
+/**
+ * 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.share_download_limit;
+
+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.GetMethod;
+
+/**
+ * class to fetch the download limit for the link share it requires share token to fetch the data
+ *
+ * API : //GET to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit
+ */
+public class GetShareDownloadLimitOperation extends RemoteOperation {
+
+ private static final String TAG = GetShareDownloadLimitOperation.class.getSimpleName();
+
+ //share token from OCShare
+ private final String shareToken;
+
+ public GetShareDownloadLimitOperation(String shareToken) {
+ this.shareToken = shareToken;
+ }
+
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ RemoteOperationResult result = null;
+ int status = -1;
+
+ GetMethod get = null;
+
+ try {
+ // Get Method
+ get = new GetMethod(client.getBaseUri() + ShareDownloadLimitUtils.INSTANCE.getDownloadLimitApiPath(shareToken));
+
+ get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
+
+ status = client.executeMethod(get);
+
+ if (isSuccess(status)) {
+ String response = get.getResponseBodyAsString();
+
+ Log_OC.d(TAG, "Get Download Limit response: " + response);
+
+ DownloadLimitXMLParser parser = new DownloadLimitXMLParser();
+ result = parser.parse(true, response);
+
+ if (result.isSuccess()) {
+ Log_OC.d(TAG, "Got " + result.getResultData() + " Response");
+ }
+
+ } else {
+ result = new RemoteOperationResult(false, get);
+ }
+
+ } catch (Exception e) {
+ result = new RemoteOperationResult(e);
+ Log_OC.e(TAG, "Exception while getting share download limit", e);
+
+ } finally {
+ if (get != null) {
+ get.releaseConnection();
+ }
+ }
+ return result;
+ }
+
+ private boolean isSuccess(int status) {
+ return (status == HttpStatus.SC_OK);
+ }
+
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/share_download_limit/ShareDownloadLimitUtils.kt b/app/src/main/java/com/owncloud/android/operations/share_download_limit/ShareDownloadLimitUtils.kt
new file mode 100644
index 000000000000..4c0780a9a532
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/share_download_limit/ShareDownloadLimitUtils.kt
@@ -0,0 +1,30 @@
+/**
+ * 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.share_download_limit
+
+object ShareDownloadLimitUtils {
+
+ private const val SHARE_TOKEN_PATH = "{share_token}"
+
+ //ocs route
+ //replace the {share_token}
+ private const val SHARE_DOWNLOAD_LIMIT_API_PATH = "/ocs/v2.php/apps/files_downloadlimit/$SHARE_TOKEN_PATH/limit"
+
+ fun getDownloadLimitApiPath(shareToken: String) : String{
+ return SHARE_DOWNLOAD_LIMIT_API_PATH.replace(SHARE_TOKEN_PATH, shareToken)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/owncloud/android/operations/share_download_limit/UpdateShareDownloadLimitRemoteOperation.java b/app/src/main/java/com/owncloud/android/operations/share_download_limit/UpdateShareDownloadLimitRemoteOperation.java
new file mode 100644
index 000000000000..f177a515e612
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/operations/share_download_limit/UpdateShareDownloadLimitRemoteOperation.java
@@ -0,0 +1,114 @@
+/**
+ * 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.share_download_limit;
+
+import android.util.Pair;
+
+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.PutMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * class to update the download limit for the link share
+ *
+ * API : //PUT to /ocs/v2.php/apps/files_downloadlimit/{share_token}/limit
+ *
+ * Body: {"token" : "Bpd4oEAgPqn3AbG", "limit" : 5}
+ */
+public class UpdateShareDownloadLimitRemoteOperation extends RemoteOperation {
+
+ private static final String TAG = UpdateShareDownloadLimitRemoteOperation.class.getSimpleName();
+
+ private static final String PARAM_TOKEN = "token";
+ private static final String PARAM_LIMIT = "limit";
+
+ private static final String ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded";
+ private static final String ENTITY_CHARSET = "UTF-8";
+
+ private final String shareToken;
+ private final long downloadLimit;
+
+ public UpdateShareDownloadLimitRemoteOperation(String shareToken, long downloadLimit) {
+ this.shareToken = shareToken;
+ this.downloadLimit = downloadLimit;
+ }
+
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ RemoteOperationResult result;
+ int status;
+
+ PutMethod put = null;
+
+ try {
+ // Post Method
+ put = new PutMethod(client.getBaseUri() + ShareDownloadLimitUtils.INSTANCE.getDownloadLimitApiPath(shareToken));
+
+ put.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
+ List> parametersToUpdate = new ArrayList<>();
+ parametersToUpdate.add(new Pair<>(PARAM_TOKEN, shareToken));
+ parametersToUpdate.add(new Pair<>(PARAM_LIMIT, String.valueOf(downloadLimit)));
+
+ for (Pair parameter : parametersToUpdate) {
+ put.setRequestEntity(new StringRequestEntity(parameter.first + "=" + parameter.second,
+ ENTITY_CONTENT_TYPE,
+ ENTITY_CHARSET));
+ }
+
+ status = client.executeMethod(put);
+
+ if (isSuccess(status)) {
+ String response = put.getResponseBodyAsString();
+
+ Log_OC.d(TAG, "Download Limit response: " + response);
+
+ DownloadLimitXMLParser parser = new DownloadLimitXMLParser();
+ result = parser.parse(true, response);
+
+ if (result.isSuccess()) {
+ return result;
+ }
+
+ } else {
+ result = new RemoteOperationResult<>(false, put);
+ }
+
+ } catch (Exception e) {
+ result = new RemoteOperationResult<>(e);
+ Log_OC.e(TAG, "Exception while updating share download limit", e);
+
+ } finally {
+ if (put != null) {
+ put.releaseConnection();
+ }
+ }
+ return result;
+ }
+
+ private boolean isSuccess(int status) {
+ return status == HttpStatus.SC_OK || status == HttpStatus.SC_BAD_REQUEST;
+ }
+
+}
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 ce6ca4697eb2..5fe23ed75b5c 100644
--- a/app/src/main/java/com/owncloud/android/services/OperationsService.java
+++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java
@@ -73,6 +73,7 @@
import com.owncloud.android.operations.UpdateShareInfoOperation;
import com.owncloud.android.operations.UpdateSharePermissionsOperation;
import com.owncloud.android.operations.UpdateShareViaLinkOperation;
+import com.owncloud.android.operations.share_download_limit.GetShareDownloadLimitOperation;
import java.io.IOException;
import java.util.Iterator;
@@ -108,6 +109,8 @@ public class OperationsService extends Service {
public static final String EXTRA_SHARE_HIDE_FILE_DOWNLOAD = "HIDE_FILE_DOWNLOAD";
public static final String EXTRA_SHARE_ID = "SHARE_ID";
public static final String EXTRA_SHARE_NOTE = "SHARE_NOTE";
+ public static final String EXTRA_SHARE_TOKEN = "SHARE_TOKEN";
+ public static final String EXTRA_SHARE_DOWNLOAD_LIMIT = "SHARE_DOWNLOAD_LIMIT";
public static final String EXTRA_IN_BACKGROUND = "IN_BACKGROUND";
public static final String ACTION_CREATE_SHARE_VIA_LINK = "CREATE_SHARE_VIA_LINK";
@@ -128,6 +131,7 @@ public class OperationsService extends Service {
public static final String ACTION_MOVE_FILE = "MOVE_FILE";
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_GET_SHARE_DOWNLOAD_LIMIT = "GET_SHARE_DOWNLOAD_LIMIT";
public static final String ACTION_RESTORE_VERSION = "RESTORE_VERSION";
private ServiceHandler mOperationsHandler;
@@ -643,6 +647,12 @@ private Pair newOperation(Intent operationIntent) {
updateShare.setLabel(operationIntent.getStringExtra(EXTRA_SHARE_PUBLIC_LABEL));
}
+ //download limit for link share type
+ if (operationIntent.hasExtra(EXTRA_SHARE_DOWNLOAD_LIMIT)) {
+ updateShare.setDownloadLimit(operationIntent.getLongExtra(EXTRA_SHARE_DOWNLOAD_LIMIT,
+ 0L));
+ }
+
operation = updateShare;
}
break;
@@ -734,6 +744,13 @@ private Pair newOperation(Intent operationIntent) {
fileVersion.getFileName());
break;
+ case ACTION_GET_SHARE_DOWNLOAD_LIMIT:
+ String shareToken = operationIntent.getStringExtra(EXTRA_SHARE_TOKEN);
+ if (!TextUtils.isEmpty(shareToken)) {
+ operation = new GetShareDownloadLimitOperation(shareToken);
+ }
+ break;
+
default:
// do nothing
break;
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
index eeb8536f5bd5..8e2b453654fd 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
@@ -78,6 +78,8 @@
import com.owncloud.android.operations.UpdateShareInfoOperation;
import com.owncloud.android.operations.UpdateSharePermissionsOperation;
import com.owncloud.android.operations.UpdateShareViaLinkOperation;
+import com.owncloud.android.operations.share_download_limit.DownloadLimitResponse;
+import com.owncloud.android.operations.share_download_limit.GetShareDownloadLimitOperation;
import com.owncloud.android.providers.UsersAndGroupsSearchProvider;
import com.owncloud.android.services.OperationsService;
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
@@ -89,6 +91,7 @@
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
import com.owncloud.android.ui.fragment.FileDetailFragment;
import com.owncloud.android.ui.fragment.FileDetailSharingFragment;
+import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment;
import com.owncloud.android.ui.fragment.OCFileListFragment;
import com.owncloud.android.ui.helpers.FileOperationsHelper;
import com.owncloud.android.ui.preview.PreviewImageActivity;
@@ -416,6 +419,8 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe
onUpdateShareInformation(result, R.string.unsharing_failed);
} else if (operation instanceof UpdateNoteForShareOperation) {
onUpdateNoteForShareOperationFinish(result);
+ } else if (operation instanceof GetShareDownloadLimitOperation) {
+ onShareDownloadLimitFetched(result);
}
}
@@ -848,6 +853,22 @@ private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation ope
}
}
+ /**
+ * method will be called when download limit is fetched
+ *
+ * @param result
+ */
+ private void onShareDownloadLimitFetched(RemoteOperationResult result) {
+ FileDetailSharingFragment sharingFragment = getShareFileFragment();
+
+ if (result.isSuccess() && sharingFragment != null && result.isSuccess() && result.getResultData() != null
+ && result.getResultData() instanceof DownloadLimitResponse) {
+ onLinkShareDownloadLimitFetched(((DownloadLimitResponse) result.getResultData()).getLimit(),
+ ((DownloadLimitResponse) result.getResultData()).getCount());
+
+ }
+ }
+
/**
* Shortcut to get access to the {@link FileDetailSharingFragment} instance, if any
*
@@ -937,6 +958,14 @@ public void editExistingShare(OCShare share, int screenTypePermission, boolean i
}
}
+ @Override
+ public void onLinkShareDownloadLimitFetched(long downloadLimit, long downloadCount) {
+ Fragment fileDetailsSharingProcessFragment = getSupportFragmentManager().findFragmentByTag(FileDetailsSharingProcessFragment.TAG);
+ if (fileDetailsSharingProcessFragment != null) {
+ ((FileDetailsSharingProcessFragment) fileDetailsSharingProcessFragment).onLinkShareDownloadLimitFetched(downloadLimit, downloadCount);
+ }
+ }
+
/**
* callback triggered on closing/finishing the sharing process
*/
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java
index dc93201c7bc5..62f5e3dc769e 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java
@@ -665,6 +665,8 @@ void editExistingShare(OCShare share, int screenTypePermission, boolean isReshar
boolean isExpiryDateShown);
void onShareProcessClosed();
+
+ void onLinkShareDownloadLimitFetched(long downloadLimit, long downloadCount);
}
@Override
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt
index 9083a0b4100f..ea0ad16d5ce1 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt
@@ -24,6 +24,8 @@ package com.owncloud.android.ui.fragment
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.MotionEvent
@@ -46,6 +48,7 @@ import com.owncloud.android.ui.fragment.util.SharingMenuHelper
import com.owncloud.android.ui.helpers.FileOperationsHelper
import com.owncloud.android.utils.ClipboardUtil
import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.KeyboardUtils
import com.owncloud.android.utils.theme.ViewThemeUtils
import java.text.SimpleDateFormat
import java.util.Date
@@ -123,6 +126,8 @@ class FileDetailsSharingProcessFragment :
@Inject
lateinit var viewThemeUtils: ViewThemeUtils
+ @Inject
+ lateinit var keyboardUtils: KeyboardUtils
private lateinit var onEditShareListener: FileDetailSharingFragment.OnEditShareListener
@@ -141,6 +146,7 @@ class FileDetailsSharingProcessFragment :
private var share: OCShare? = null
private var isReshareShown: Boolean = true // show or hide reshare option
private var isExpDateShown: Boolean = true // show or hide expiry date option
+ private var isDownloadCountFetched: Boolean = false
private var expirationDatePickerFragment: ExpirationDatePickerDialogFragment? = null
@@ -218,7 +224,11 @@ class FileDetailsSharingProcessFragment :
} else {
showShareProcessSecond()
}
-
+ //Set default value to 0 for download count
+ if (!isDownloadCountFetched) {
+ binding.shareProcessRemainingDownloadCountTv.text =
+ String.format(resources.getString(R.string.download_text), "0")
+ }
binding.shareProcessPermissionRadioGroup.setOnCheckedChangeListener(this)
implementClickEvents()
binding.shareProcessHideDownloadCheckbox.setOnCheckedChangeListener { _, isChecked ->
@@ -345,10 +355,13 @@ class FileDetailsSharingProcessFragment :
}
showChangeNameInput(binding.shareProcessChangeNameSwitch.isChecked)
- //download limit will only be available for Files
+ //download limit will only be available for files
if (share?.isFolder == false || file?.isFolder == false) {
binding.shareProcessDownloadLimitSwitch.visibility = View.VISIBLE
binding.dividerSharingDownloadLimit.visibility = View.VISIBLE
+
+ //fetch the download limit for link share
+ fetchDownloadLimitForShareLink()
} else {
binding.shareProcessDownloadLimitSwitch.visibility = View.GONE
binding.dividerSharingDownloadLimit.visibility = View.GONE
@@ -515,6 +528,9 @@ class FileDetailsSharingProcessFragment :
binding.shareProcessSelectExpDate.setOnClickListener {
showExpirationDateDialog()
}
+ binding.shareProcessDownloadLimitSwitch.setOnCheckedChangeListener { _, isChecked ->
+ showDownloadLimitInput(isChecked)
+ }
binding.noteText.setOnTouchListener { view, event ->
view.parent.requestDisallowInterceptTouchEvent(true)
if ((event.action and MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
@@ -541,16 +557,27 @@ class FileDetailsSharingProcessFragment :
binding.shareProcessChangeNameEt.visibility = if (isChecked) View.VISIBLE else View.GONE
if (!isChecked) {
binding.shareProcessChangeNameEt.setText("")
- // TODO: Hide keyboard after download limit PR merged by NC
- // hide keyboard when user unchecks
- //hideKeyboard()
+ //hide keyboard when user unchecks
+ hideKeyboard()
+ }
+ }
+
+ private fun showDownloadLimitInput(isChecked: Boolean) {
+ binding.shareProcessDownloadLimitEt.visibility = if (isChecked) View.VISIBLE else View.GONE
+ binding.shareProcessRemainingDownloadCountTv.visibility = if (isChecked) View.VISIBLE else View.GONE
+ if (!isChecked) {
+ binding.shareProcessDownloadLimitEt.setText("")
+ if (!isDownloadCountFetched) {
+ binding.shareProcessRemainingDownloadCountTv.text = String.format(resources.getString(R.string.download_text), "0")
+ }
+ //hide keyboard when user unchecks
+ hideKeyboard()
}
}
private fun onCancelClick() {
- // TODO: Hide keyboard after download limit PR merged by NC
// hide keyboard when user clicks cancel button
- //hideKeyboard()
+ hideKeyboard()
// if modifying the existing share then on back press remove the current fragment
if (share != null) {
removeCurrentFragment()
@@ -590,9 +617,14 @@ class FileDetailsSharingProcessFragment :
// reset the password if switch is unchecked
if (!isChecked) {
binding.shareProcessEnterPassword.setText("")
- // TODO: Hide keyboard after download limit PR merged by NC
// hide keyboard when user unchecks
- //hideKeyboard()
+ hideKeyboard()
+ }
+ }
+
+ private fun hideKeyboard() {
+ if (this::binding.isInitialized) {
+ keyboardUtils.hideKeyboardFrom(requireContext(), binding.root)
}
}
@@ -615,8 +647,7 @@ class FileDetailsSharingProcessFragment :
*/
@Suppress("ReturnCount")
private fun validateShareProcessFirst() {
- // TODO: Hide keyboard after download limit PR merged by NC
- //hideKeyboard()
+ hideKeyboard()
permission = getSelectedPermission()
if (permission == OCShare.NO_PERMISSION) {
DisplayUtils.showSnackMessage(binding.root, R.string.no_share_permission_selected)
@@ -644,6 +675,17 @@ class FileDetailsSharingProcessFragment :
return
}
+ if (binding.shareProcessDownloadLimitSwitch.isChecked) {
+ val downloadLimit = binding.shareProcessDownloadLimitEt.text?.trim()
+ if (downloadLimit.isNullOrEmpty()) {
+ DisplayUtils.showSnackMessage(binding.root, R.string.download_limit_empty)
+ return
+ } else if (downloadLimit.toString().toLong() <= 0) {
+ DisplayUtils.showSnackMessage(binding.root, R.string.download_limit_zero)
+ return
+ }
+ }
+
// if modifying existing share information then execute the process
if (share != null) {
updateShare()
@@ -675,7 +717,8 @@ class FileDetailsSharingProcessFragment :
binding.shareProcessHideDownloadCheckbox.isChecked,
binding.shareProcessEnterPassword.text.toString().trim(),
chosenExpDateInMills,
- binding.shareProcessChangeNameEt.text.toString().trim()
+ binding.shareProcessChangeNameEt.text.toString().trim(),
+ binding.shareProcessDownloadLimitEt.text.toString().trim()
)
// copy the share link if available
if (!TextUtils.isEmpty(share?.shareLink)) {
@@ -687,8 +730,7 @@ class FileDetailsSharingProcessFragment :
* method to validate step 2 (note screen) information
*/
private fun validateShareProcessSecond() {
- // TODO: Hide keyboard after download limit PR merged by NC
- //hideKeyboard()
+ hideKeyboard()
// if modifying existing share then directly update the note and send email
if (share != null) {
if (TextUtils.isEmpty(binding.noteText.text.toString().trim())) {
@@ -714,6 +756,19 @@ class FileDetailsSharingProcessFragment :
removeCurrentFragment()
}
+ /**
+ * fetch the download limit for the link share
+ * the response will be received in FileActivity --> onRemoteOperationFinish() method
+ */
+ private fun fetchDownloadLimitForShareLink() {
+ //need to call this method in handler else to show progress dialog it will throw exception
+ Handler(Looper.getMainLooper()).post {
+ share?.let {
+ fileOperationsHelper?.getShareDownloadLimit(it.token)
+ }
+ }
+ }
+
/**
* method will be called from DrawerActivity on back press to handle screen backstack
*/
@@ -722,16 +777,25 @@ class FileDetailsSharingProcessFragment :
}
override fun onDateSet(year: Int, monthOfYear: Int, dayOfMonth: Int, chosenDateInMillis: Long) {
- binding.shareProcessSelectExpDate.text = (
- resources.getString(
- R.string.share_expiration_date_format,
- SimpleDateFormat.getDateInstance().format(Date(chosenDateInMillis))
- )
- )
+ binding.shareProcessSelectExpDate.text = (resources.getString(
+ R.string.share_expiration_date_format,
+ SimpleDateFormat.getDateInstance().format(Date(chosenDateInMillis))
+ ))
this.chosenExpDateInMills = chosenDateInMillis
}
override fun onDateUnSet() {
binding.shareProcessSetExpDateSwitch.isChecked = false
}
+
+ /**
+ * will be called when download limit is fetched
+ */
+ fun onLinkShareDownloadLimitFetched(downloadLimit: Long, downloadCount: Long) {
+ binding.shareProcessDownloadLimitSwitch.isChecked = downloadLimit > 0
+ showDownloadLimitInput(binding.shareProcessDownloadLimitSwitch.isChecked)
+ binding.shareProcessDownloadLimitEt.setText(if (downloadLimit > 0) downloadLimit.toString() else "")
+ binding.shareProcessRemainingDownloadCountTv.text = String.format(resources.getString(R.string.download_text), downloadCount.toString())
+ isDownloadCountFetched = true
+ }
}
diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
index 229d4786d986..3799cd153a66 100755
--- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
+++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
@@ -636,9 +636,10 @@ public void unshareShare(OCFile file, OCShare share) {
private void queueShareIntent(Intent shareIntent) {
// Unshare the file
- mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(shareIntent);
-
- fileActivity.showLoadingDialog(fileActivity.getApplicationContext().getString(R.string.wait_a_moment));
+ if(fileActivity.getOperationsServiceBinder() != null) {
+ mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(shareIntent);
+ fileActivity.showLoadingDialog(fileActivity.getApplicationContext().getString(R.string.wait_a_moment));
+ }
}
/**
@@ -777,7 +778,7 @@ public void updateNoteToShare(OCShare share, String note) {
*/
public void updateShareInformation(OCShare share, int permissions,
boolean hideFileDownload, String password, long expirationTimeInMillis,
- String label) {
+ String label, String downloadLimit) {
Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_INFO);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
@@ -787,6 +788,26 @@ public void updateShareInformation(OCShare share, int permissions,
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password);
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label);
+
+ //download limit for link share type
+ updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_DOWNLOAD_LIMIT,
+ (downloadLimit == null || downloadLimit.equals("")) ? 0 :
+ Long.parseLong(downloadLimit));
+
+ queueShareIntent(updateShareIntent);
+ }
+
+ /**
+ * method to fetch the download limit for the particular share Note: Download limit is only for Link share type
+ *
+ * @param shareToken of the OCShare
+ */
+ public void getShareDownloadLimit(String shareToken) {
+ Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
+ updateShareIntent.setAction(OperationsService.ACTION_GET_SHARE_DOWNLOAD_LIMIT);
+ updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
+ updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_TOKEN, shareToken);
+
queueShareIntent(updateShareIntent);
}
diff --git a/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt b/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt
index 2d0b922a0bf3..e1e812d8213d 100644
--- a/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt
+++ b/app/src/main/java/com/owncloud/android/utils/KeyboardUtils.kt
@@ -22,7 +22,9 @@
package com.owncloud.android.utils
+import android.app.Activity
import android.content.Context
+import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import javax.inject.Inject
@@ -41,6 +43,12 @@ class KeyboardUtils @Inject constructor() {
}, SHOW_INPUT_DELAY_MILLIS)
}
+ fun hideKeyboardFrom(context: Context, view: View) {
+ view.clearFocus()
+ val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
+ imm.hideSoftInputFromWindow(view.windowToken, 0)
+ }
+
companion object {
private const val SHOW_INPUT_DELAY_MILLIS = 100L
}
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index a1c5fe3fe55f..5f306ec784e9 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -946,7 +946,7 @@
Download Limit
Das Feld für das Download-Limit darf nicht leer sein.
Downlimit eingeben
- Downloads:\u0020
+ Downloads: %s
Der Wert für das Download limit sollte größer als 0 sein.
Sie teilen mit einer/einem MagentaCLOUD Nutzer(in). Sie können ihr oder ihm erlauben, den Ordner oder die Dateien weiterzuteilen.
Der Passwortschutz ist aktiviert. Sie müssen dem Empfänger das Passwort
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2a9011220040..4fb123963f83 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -999,7 +999,7 @@
Download Limit
Download limit cannot be empty.
Enter download limit
- Downloads:\u0020
+ Downloads: %s
Download limit should be greater than 0.
You are sharing with a MagentaCLOUD user and you can allow her or him to reshare.
Password protection has been enabled. You have to provide the password to