From 6f8d7dfda802b17fff852db3e6db780f28c3df0e Mon Sep 17 00:00:00 2001 From: A117870935 Date: Mon, 26 Jun 2023 23:48:48 +0530 Subject: [PATCH] Download limit functionality added. --- .../java/com/nmc/android/ui/FileSharingIT.kt | 2 +- .../fragment/FileDetailSharingFragmentIT.kt | 4 + .../CreateShareWithShareeOperation.java | 5 + .../operations/UpdateShareInfoOperation.java | 52 +++ ...leteShareDownloadLimitRemoteOperation.java | 90 +++++ .../DownloadLimitResponse.java | 37 ++ .../DownloadLimitXMLParser.java | 323 ++++++++++++++++++ .../GetShareDownloadLimitOperation.java | 90 +++++ .../ShareDownloadLimitUtils.kt | 30 ++ ...dateShareDownloadLimitRemoteOperation.java | 114 +++++++ .../android/services/OperationsService.java | 17 + .../android/ui/activity/FileActivity.java | 29 ++ .../fragment/FileDetailSharingFragment.java | 2 + .../FileDetailsSharingProcessFragment.kt | 104 ++++-- .../ui/helpers/FileOperationsHelper.java | 29 +- .../owncloud/android/utils/KeyboardUtils.kt | 8 + app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 18 files changed, 913 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/operations/share_download_limit/DeleteShareDownloadLimitRemoteOperation.java create mode 100644 app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitResponse.java create mode 100644 app/src/main/java/com/owncloud/android/operations/share_download_limit/DownloadLimitXMLParser.java create mode 100644 app/src/main/java/com/owncloud/android/operations/share_download_limit/GetShareDownloadLimitOperation.java create mode 100644 app/src/main/java/com/owncloud/android/operations/share_download_limit/ShareDownloadLimitUtils.kt create mode 100644 app/src/main/java/com/owncloud/android/operations/share_download_limit/UpdateShareDownloadLimitRemoteOperation.java 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