service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
- service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
+ service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, password);
service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
updateShareIntent.putExtra(
- OperationsService.EXTRA_PASSWORD_SHARE,
+ OperationsService.EXTRA_SHARE_PASSWORD,
(password == null) ? "" : password
);
/**
+ * Updates a public share on a file to set its expiration date.
+ * Starts a request to do it in {@link OperationsService}
+ *
+ * @param file File which public share will be constrained with an expiration date.
+ * @param year Year of the date expiration chosen. Negative value to remove current
+ * expiration date and leave the link unrestricted.
+ * @param monthOfYear Month of the date chosen [0, 11]
+ * @param dayOfMonth Day of the date chosen
+ */
+ public void setExpirationDateToShareViaLink(OCFile file, int year, int monthOfYear, int dayOfMonth) {
+ Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
+ updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
+ updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+ updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+ updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_YEAR, year);
+ updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_MONTH_OF_YEAR, monthOfYear);
+ updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DAY_OF_MONTH, dayOfMonth);
+ queueShareIntent(updateShareIntent);
+ }
+
+
+ /**
* @return 'True' if the server supports the Search Users API
*/
public boolean isSearchUsersSupportedSupported() {
import com.owncloud.android.lib.resources.shares.UpdateRemoteShareOperation;
import com.owncloud.android.operations.common.SyncOperation;
+import java.util.Calendar;
+
/**
* Updates an existing public share for a given file
private String mPath;
private String mPassword;
+ private Calendar mExpirationDate;
/**
* Constructor
+ *
* @param path Full path of the file/folder being shared. Mandatory argument
- * @param password Password to protect a public link share.
*/
- public UpdateShareViaLinkOperation(
- String path,
- String password
- ) {
+ public UpdateShareViaLinkOperation(String path) {
mPath = path;
+ mPassword = null;
+ mExpirationDate = null;
+ }
+
+
+ /**
+ * Set password to update in public link.
+ *
+ * @param password Password to set to the public link.
+ * Empty string clears the current password.
+ * Null results in no update applied to the password.
+ */
+ public void setPassword(String password) {
mPassword = password;
}
+
+ /**
+ * Set expiration date to update in Share resource.
+ *
+ * @param expirationDate Expiration date to set to the public link.
+ * Start-of-epoch clears the current expiration date.
+ * Null results in no update applied to the expiration date.
+ */
+ public void setExpirationDate(Calendar expirationDate) {
+ mExpirationDate = expirationDate;
+ }
+
+
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
}
// Update remote share with password
- RemoteOperation operation = new UpdateRemoteShareOperation(
+ UpdateRemoteShareOperation udpateOp = new UpdateRemoteShareOperation(
publicShare.getRemoteId()
);
- ((UpdateRemoteShareOperation)operation).setPassword(mPassword);
- RemoteOperationResult result = operation.execute(client);
+ udpateOp.setPassword(mPassword);
+ udpateOp.setExpirationDate(mExpirationDate);
+ RemoteOperationResult result = udpateOp.execute(client);
/*
if (!result.isSuccess() || result.getData().size() <= 0) {
if (result.isSuccess()) {
// Retrieve updated share / save directly with password? -> no; the password is not be saved
- operation = new GetRemoteShareOperation(publicShare.getRemoteId());
- result = operation.execute(client);
+ RemoteOperation getShareOp = new GetRemoteShareOperation(publicShare.getRemoteId());
+ result = getShareOp.execute(client);
if (result.isSuccess()) {
OCShare share = (OCShare) result.getData().get(0);
updateData(share);
import com.owncloud.android.operations.common.SyncOperation;
import java.io.IOException;
+import java.util.Calendar;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public static final String EXTRA_RESULT = "RESULT";
public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
public static final String EXTRA_FILE = "FILE";
- public static final String EXTRA_PASSWORD_SHARE = "PASSWORD_SHARE";
+ public static final String EXTRA_SHARE_PASSWORD = "SHARE_PASSWORD";
public static final String EXTRA_SHARE_TYPE = "SHARE_TYPE";
public static final String EXTRA_SHARE_WITH = "SHARE_WITH";
+ public static final String EXTRA_SHARE_EXPIRATION_YEAR = "SHARE_EXPIRATION_YEAR";
+ public static final String EXTRA_SHARE_EXPIRATION_MONTH_OF_YEAR = "SHARE_EXPIRATION_MONTH_OF_YEAR";
+ public static final String EXTRA_SHARE_EXPIRATION_DAY_OF_MONTH = "SHARE_EXPIRATION_DAY_OF_MONTH";
public static final String EXTRA_COOKIE = "COOKIE";
String action = operationIntent.getAction();
if (action.equals(ACTION_CREATE_SHARE_VIA_LINK)) { // Create public share via link
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
+ String password = operationIntent.getStringExtra(EXTRA_SHARE_PASSWORD);
Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
if (remotePath.length() > 0) {
operation = new CreateShareViaLinkOperation(
} else if (ACTION_UPDATE_SHARE.equals(action)) {
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
if (remotePath.length() > 0) {
- operation = new UpdateShareViaLinkOperation(remotePath, password);
- }
+ operation = new UpdateShareViaLinkOperation(remotePath);
+
+ String password = operationIntent.getStringExtra(EXTRA_SHARE_PASSWORD);
+ ((UpdateShareViaLinkOperation)operation).setPassword(password);
- } else if (action.equals(ACTION_CREATE_SHARE_WITH_SHAREE)) { // Create private share with user or group
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- String shareeName = operationIntent.getStringExtra(EXTRA_SHARE_WITH);
- ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE);
- if (remotePath.length() > 0) {
- operation = new CreateShareWithShareeOperation(
- remotePath,
- shareeName,
- shareType
+ int year = operationIntent.getIntExtra(EXTRA_SHARE_EXPIRATION_YEAR, 0);
+ if (year > 0) {
+ // expiration date is set
+ int monthOfYear = operationIntent.getIntExtra(
+ EXTRA_SHARE_EXPIRATION_MONTH_OF_YEAR, 0
);
- }
+ int dayOfMonth = operationIntent.getIntExtra(
+ EXTRA_SHARE_EXPIRATION_DAY_OF_MONTH, 1
+ );
+ Calendar expirationDate = Calendar.getInstance();
+ expirationDate.set(Calendar.YEAR, year);
+ expirationDate.set(Calendar.MONTH, monthOfYear);
+ expirationDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+ ((UpdateShareViaLinkOperation)operation).setExpirationDate(
+ expirationDate
+ );
+
+ } else if (year < 0) {
+ // expiration date to be cleared
+ Calendar zeroDate = Calendar.getInstance();
+ zeroDate.clear();
+ ((UpdateShareViaLinkOperation)operation).setExpirationDate(
+ zeroDate
+ );
+
+ } // else, no update on expiration date
+ }
+
+ } else if (action.equals(ACTION_CREATE_SHARE_WITH_SHAREE)) {
+ // Create private share with user or group
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ String shareeName = operationIntent.getStringExtra(EXTRA_SHARE_WITH);
+ ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE);
+ if (remotePath.length() > 0) {
+ operation = new CreateShareWithShareeOperation(
+ remotePath,
+ shareeName,
+ shareType
+ );
+ }
} else if (action.equals(ACTION_UNSHARE)) { // Unshare file
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
super.onRemoteOperationFinish(operation, result);
if (result.isSuccess()) {
- Log_OC.d(TAG, "Refreshing lists on successful operation");
+ Log_OC.d(TAG, "Refreshing view on successful operation");
refreshSharesFromStorageManager();
}
-
}
+
+ /**
+ * Updates the view, reading data from {@link com.owncloud.android.datamodel.FileDataStorageManager}
+ */
private void refreshSharesFromStorageManager() {
+
ShareFileFragment shareFileFragment = getShareFileFragment();
- if (shareFileFragment != null) { // only if added to the view hierarchy!!
- if (shareFileFragment.isAdded()) {
- shareFileFragment.refreshUsersOrGroupsListFromDB();
- shareFileFragment.refreshPublicShareFromDB();
- }
+ if (shareFileFragment != null
+ && shareFileFragment.isAdded()) { // only if added to the view hierarchy!!
+ shareFileFragment.refreshUsersOrGroupsListFromDB();
+ shareFileFragment.refreshPublicShareFromDB();
}
SearchShareesFragment searchShareesFragment = getSearchFragment();
- if (searchShareesFragment != null) {
- if (searchShareesFragment.isAdded()) { // only if added to the view hierarchy!!
- searchShareesFragment.refreshUsersOrGroupsListFromDB();
- }
+ if (searchShareesFragment != null &&
+ searchShareesFragment.isAdded()) { // only if added to the view hierarchy!!
+ searchShareesFragment.refreshUsersOrGroupsListFromDB();
}
}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.dialog;
+
+
+import android.app.DatePickerDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.text.format.DateUtils;
+import android.widget.DatePicker;
+import android.widget.Toast;
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.FileActivity;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Dialog requesting a date after today.
+ */
+public class ExpirationDatePickerDialogFragment
+ extends DialogFragment
+ implements DatePickerDialog.OnDateSetListener {
+
+ /** Tag for FragmentsManager */
+ public static final String DATE_PICKER_DIALOG = "DATE_PICKER_DIALOG";
+
+ /** Constructor arguments */
+ private static final String ARG_FILE = "ARG_FILE";
+
+ /** File to bind an expiration date */
+ private OCFile mFile;
+
+ /**
+ * Factory method to create new instances
+ *
+ * @param file File to bind an expiration date
+ * @return New dialog instance
+ */
+ public static ExpirationDatePickerDialogFragment newInstance(OCFile file) {
+ Bundle arguments = new Bundle();
+ arguments.putParcelable(ARG_FILE, file);
+
+ ExpirationDatePickerDialogFragment dialog = new ExpirationDatePickerDialogFragment();
+ dialog.setArguments(arguments);
+ return dialog;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return A new dialog to let the user choose an expiration date that will be bound to a share link.
+ */
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Load arguments
+ mFile = getArguments().getParcelable(ARG_FILE);
+
+ // Get current day
+ final Calendar c = Calendar.getInstance();
+ int year = c.get(Calendar.YEAR);
+ int month = c.get(Calendar.MONTH);
+ int day = c.get(Calendar.DAY_OF_MONTH);
+
+ // Create a new instance of DatePickerDialog, highlighting "tomorrow" as chosen day
+ DatePickerDialog dialog = new DatePickerDialog(getActivity(), this, year, month, day + 1);
+
+ // Prevent days in the past may be chosen
+ DatePicker picker = dialog.getDatePicker();
+ picker.setMinDate(System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS - 1000);
+
+ // Enforce spinners view; ignored by MD-based theme in Android >=5, but calendar is REALLY buggy
+ // in Android < 5, so let's be sure it never appears (in tablets both spinners and calendar are
+ // shown by default)
+ picker.setCalendarViewShown(false);
+
+ return dialog;
+ }
+
+ /**
+ * Called when the user choses an expiration date.
+ *
+ * @param view View instance where the date was chosen
+ * @param year Year of the date chosen.
+ * @param monthOfYear Month of the date chosen [0, 11]
+ * @param dayOfMonth Day of the date chosen
+ */
+ @Override
+ public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
+
+ Calendar chosenDate = Calendar.getInstance();
+ chosenDate.set(Calendar.YEAR, year);
+ chosenDate.set(Calendar.MONTH, monthOfYear);
+ chosenDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+
+ ((FileActivity)getActivity()).getFileOperationsHelper().setExpirationDateToShareViaLink(
+ mFile,
+ year,
+ monthOfYear,
+ dayOfMonth
+ );
+ }
+}
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.adapter.ShareUserListAdapter;
+import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.MimetypeIconUtil;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Date;
/**
* Fragment for Sharing a file with sharees (users or groups) or creating
/** Listener for changes on switch to share / unshare publicly */
private CompoundButton.OnCheckedChangeListener mOnShareViaLinkSwitchCheckedChangeListener;
- /** Listener for changes on switch to set / clear password on public link */
+ /**
+ * Listener for changes on switch to set / clear password on public link
+ */
private CompoundButton.OnCheckedChangeListener mOnPasswordSwitchCheckedChangeListener;
+ /**
+ * Listener for changes on switch to set / clear expiration date on public link
+ */
+ private CompoundButton.OnCheckedChangeListener mOnExpirationDateSwitchCheckedChangeListener;
+
/**
* Public factory method to create new ShareFileFragment instances.
shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
// Switch for expiration date
- Switch shareViaLinkExpirationSwitch = (Switch) view.findViewById(R.id.shareViaLinkExpirationSwitch);
- shareViaLinkExpirationSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ mOnExpirationDateSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isResumed()) {
return;
}
if (isChecked) {
- // TODO real implementation: update share with expiration date
- // show value of expiration date
- getExpirationDateValue().setText(R.string.placeholder_timestamp);
+ ExpirationDatePickerDialogFragment dialog =
+ ExpirationDatePickerDialogFragment.newInstance(mFile);
+ dialog.show(
+ getActivity().getSupportFragmentManager(),
+ ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
+ );
} else {
- // TODO real implementation: update share without expiration date
- // empty value
- getExpirationDateValue().setText(R.string.empty);
+ ((FileActivity) getActivity()).getFileOperationsHelper().
+ setExpirationDateToShareViaLink(mFile, -1, -1, -1);
}
+
+ // undo the toggle to grant the view will be correct if the dialog is cancelled
+ buttonView.setOnCheckedChangeListener(null);
+ buttonView.toggle();
+ buttonView.setOnCheckedChangeListener(mOnExpirationDateSwitchCheckedChangeListener);
}
- });
+ };
+ Switch shareViaLinkExpirationSwitch = (Switch) view.findViewById(R.id.shareViaLinkExpirationSwitch);
+ shareViaLinkExpirationSwitch.setOnCheckedChangeListener(mOnExpirationDateSwitchCheckedChangeListener);
// Switch for password
mOnPasswordSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
((FileActivity) getActivity()).getFileOperationsHelper().
setPasswordToShareViaLink(mFile, ""); // "" clears
}
+
+ // undo the toggle to grant the view will be correct if the dialog is cancelled
+ buttonView.setOnCheckedChangeListener(null);
+ buttonView.toggle();
+ buttonView.setOnCheckedChangeListener(mOnPasswordSwitchCheckedChangeListener);
}
};
Switch shareViaLinkPasswordSwitch = (Switch) view.findViewById(R.id.shareViaLinkPasswordSwitch);
}
/**
- * Get users and groups from the DB to fill in the "share with" list
+ * Get users and groups from the DB to fill in the "share with" list.
*
* Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
* instance ready to use. If not ready, does nothing.
/**
- * Get public link from the DB to fill in the "Share link" section
+ * Get public link from the DB to fill in the "Share link" section in the UI.
*
* Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
* instance ready to use. If not ready, does nothing.
""
);
- // Update list of users/groups
+ // Update public share section
updatePublicShareSection();
}
}
getPasswordSection().setVisibility(View.VISIBLE);
getGetLinkButton().setVisibility(View.VISIBLE);
+ /// update state of expiration date switch and message depending on expiration date
+ /// update state of expiration date switch and message depending on expiration date
+ Switch expirationDateSwitch = getExpirationDateSwitch();
+ // set null listener before setChecked() to prevent infinite loop of calls
+ expirationDateSwitch.setOnCheckedChangeListener(null);
+ long expirationDate = mPublicShare.getExpirationDate();
+ if (expirationDate > 0) {
+ if (!expirationDateSwitch.isChecked()) {
+ expirationDateSwitch.toggle();
+ }
+ String formattedDate =
+ SimpleDateFormat.getDateInstance().format(
+ new Date(expirationDate)
+ );
+ getExpirationDateValue().setText(formattedDate);
+ } else {
+ if (expirationDateSwitch.isChecked()) {
+ expirationDateSwitch.toggle();
+ }
+ getExpirationDateValue().setText(R.string.empty);
+ }
+ // recover listener
+ expirationDateSwitch.setOnCheckedChangeListener(
+ mOnExpirationDateSwitchCheckedChangeListener
+ );
+
/// update state of password switch and message depending on password protection
Switch passwordSwitch = getPasswordSwitch();
// set null listener before setChecked() to prevent infinite loop of calls
}
}
+
/// BEWARE: next methods will failed with NullPointerException if called before onCreateView() finishes
private Switch getShareViaLinkSwitch() {
return getView().findViewById(R.id.shareViaLinkExpirationSection);
}
+ private Switch getExpirationDateSwitch() {
+ return (Switch) getView().findViewById(R.id.shareViaLinkExpirationSwitch);
+ }
+
private TextView getExpirationDateValue() {
return (TextView) getView().findViewById(R.id.shareViaLinkExpirationValue);
}