Browse Source

WiP share link functionality

AndyScherzinger 6 years ago
parent
commit
d7e8f6141a

+ 104 - 1
src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -47,6 +47,7 @@ import android.os.Parcelable;
 import android.support.annotation.NonNull;
 import android.support.design.widget.BottomNavigationView;
 import android.support.design.widget.Snackbar;
+import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
@@ -73,6 +74,8 @@ import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.accounts.AccountUtils;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
@@ -83,6 +86,7 @@ import com.owncloud.android.media.MediaService;
 import com.owncloud.android.media.MediaServiceBinder;
 import com.owncloud.android.operations.CopyFileOperation;
 import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.CreateShareViaLinkOperation;
 import com.owncloud.android.operations.MoveFileOperation;
 import com.owncloud.android.operations.RefreshFolderOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
@@ -92,13 +96,16 @@ import com.owncloud.android.operations.UploadFileOperation;
 import com.owncloud.android.providers.UsersAndGroupsSearchProvider;
 import com.owncloud.android.syncadapter.FileSyncAdapter;
 import com.owncloud.android.ui.dialog.SendShareDialog;
+import com.owncloud.android.ui.dialog.ShareLinkToDialog;
 import com.owncloud.android.ui.dialog.SortingOrderDialogFragment;
 import com.owncloud.android.ui.events.SyncEventFinished;
 import com.owncloud.android.ui.events.TokenPushEvent;
 import com.owncloud.android.ui.fragment.ExtendedListFragment;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.fragment.FileDetailSharingFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
+import com.owncloud.android.ui.fragment.ShareFileFragment;
 import com.owncloud.android.ui.fragment.TaskRetainerFragment;
 import com.owncloud.android.ui.fragment.contactsbackup.ContactListFragment;
 import com.owncloud.android.ui.helpers.FileOperationsHelper;
@@ -146,6 +153,9 @@ public class FileDisplayActivity extends HookActivity
     private View mLeftFragmentContainer;
     private View mRightFragmentContainer;
 
+    private static final String TAG_PUBLIC_LINK = "PUBLIC_LINK";
+    private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
+
     private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
     private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS";
     private static final String KEY_WAITING_TO_SEND = "WAITING_TO_SEND";
@@ -1694,8 +1704,9 @@ public class FileDisplayActivity extends HookActivity
 
         } else if (operation instanceof CopyFileOperation) {
             onCopyFileOperationFinish((CopyFileOperation) operation, result);
+        } else if (operation instanceof CreateShareViaLinkOperation) {
+            onCreateShareViaLinkOperationFinish((CreateShareViaLinkOperation) operation, result);
         }
-
     }
 
     private void refreshShowDetails() {
@@ -1788,6 +1799,98 @@ public class FileDisplayActivity extends HookActivity
         }
     }
 
+    private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
+                                                     RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            updateFileFromDB();
+
+            // Create dialog to allow the user choose an app to send the link
+            Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
+
+            // if share to user and share via link multiple ocshares are returned,
+            // therefore filtering for public_link
+            String link = "";
+            for (Object object : result.getData()) {
+                OCShare shareLink = (OCShare) object;
+                if (TAG_PUBLIC_LINK.equalsIgnoreCase(shareLink.getShareType().name())) {
+                    link = shareLink.getShareLink();
+                    break;
+                }
+            }
+
+            intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
+            intentToShareLink.setType("text/plain");
+
+            String username;
+            try {
+                OwnCloudAccount oca = new OwnCloudAccount(getAccount(), this);
+                if (oca.getDisplayName() != null && !oca.getDisplayName().isEmpty()) {
+                    username = oca.getDisplayName();
+                } else {
+                    username = AccountUtils.getUsernameForAccount(getAccount());
+                }
+            } catch (Exception e) {
+                username = AccountUtils.getUsernameForAccount(getAccount());
+            }
+
+            if (username != null) {
+                intentToShareLink.putExtra(
+                        Intent.EXTRA_SUBJECT,
+                        getString(
+                                R.string.subject_user_shared_with_you,
+                                username,
+                                getFile().getFileName()
+                        )
+                );
+            } else {
+                intentToShareLink.putExtra(
+                        Intent.EXTRA_SUBJECT,
+                        getString(
+                                R.string.subject_shared_with_you,
+                                getFile().getFileName()
+                        )
+                );
+            }
+
+            String[] packagesToExclude = new String[]{getPackageName()};
+            DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intentToShareLink, packagesToExclude);
+            chooserDialog.show(getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
+
+        } else {
+            // Detect Failure (403) --> maybe needs password
+            String password = operation.getPassword();
+            if (result.getCode() == RemoteOperationResult.ResultCode.SHARE_FORBIDDEN    &&
+                    (password == null || password.length() == 0)                        &&
+                    getCapabilities().getFilesSharingPublicEnabled().isUnknown()) {
+                // Was tried without password, but not sure that it's optional.
+
+                // Try with password before giving up; see also ShareFileFragment#OnShareViaLinkListener
+                FileDetailFragment fileDetailFragment = getShareFileFragment();
+                if (fileDetailFragment != null
+                        && fileDetailFragment.isAdded()) {   // only if added to the view hierarchy!!
+
+                    fileDetailFragment.getFileDetailSharingFragment().requestPasswordForShareViaLink(true);
+                }
+
+            } else {
+                Snackbar.make(
+                        findViewById(android.R.id.content),
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                        Snackbar.LENGTH_LONG
+                ).show();
+            }
+        }
+    }
+
+    /**
+     * Shortcut to get access to the {@link FileDetailFragment} instance, if any
+     *
+     * @return A {@link FileDetailFragment} instance, or null
+     */
+    private FileDetailFragment getShareFileFragment() {
+        return (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(TAG_SECOND_FRAGMENT);
+    }
+
     /**
      * Updates the view associated to the activity after the finish of an operation trying to copy a
      * file.

+ 8 - 1
src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java

@@ -36,6 +36,8 @@ public class FileDetailTabAdapter extends FragmentStatePagerAdapter {
     private OCFile file;
     private Account account;
 
+    private FileDetailSharingFragment fileDetailSharingFragment;
+
     public FileDetailTabAdapter(FragmentManager fm, OCFile file, Account account) {
         super(fm);
 
@@ -49,12 +51,17 @@ public class FileDetailTabAdapter extends FragmentStatePagerAdapter {
             case 0:
                 return FileDetailActivitiesFragment.newInstance(file, account);
             case 1:
-                return FileDetailSharingFragment.newInstance(file, account);
+                fileDetailSharingFragment = FileDetailSharingFragment.newInstance(file, account);
+                return fileDetailSharingFragment;
             default:
                 return null;
         }
     }
 
+    public FileDetailSharingFragment getFileDetailSharingFragment() {
+        return fileDetailSharingFragment;
+    }
+
     @Override
     public int getCount() {
         return 2;

+ 12 - 17
src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java

@@ -143,27 +143,22 @@ public class FileDetailActivitiesFragment extends Fragment implements ActivityLi
 
         fetchAndSetData(null);
 
-        swipeListRefreshLayout.setOnRefreshListener(() -> {
-                    setLoadingMessage();
-                    if (swipeListRefreshLayout != null && swipeListRefreshLayout.isRefreshing()) {
-                        swipeListRefreshLayout.setRefreshing(false);
-                    }
-                    fetchAndSetData(null);
-                }
-        );
-
-        swipeEmptyListRefreshLayout.setOnRefreshListener(() -> {
-                    setLoadingMessage();
-                    if (swipeEmptyListRefreshLayout != null && swipeEmptyListRefreshLayout.isRefreshing()) {
-                        swipeEmptyListRefreshLayout.setRefreshing(false);
-                    }
-                    fetchAndSetData(null);
-                }
-        );
+        swipeListRefreshLayout.setOnRefreshListener(
+                () -> onRefreshListLayout(swipeListRefreshLayout));
+        swipeEmptyListRefreshLayout.setOnRefreshListener(
+                () -> onRefreshListLayout(swipeEmptyListRefreshLayout));
 
         return view;
     }
 
+    private void onRefreshListLayout(SwipeRefreshLayout refreshLayout) {
+        setLoadingMessage();
+        if (refreshLayout != null && refreshLayout.isRefreshing()) {
+            refreshLayout.setRefreshing(false);
+        }
+        fetchAndSetData(null);
+    }
+
     private void setLoadingMessage() {
         emptyContentHeadline.setText(R.string.file_list_loading);
         emptyContentMessage.setText("");

+ 11 - 6
src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -163,6 +163,15 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
         progressListener = null;
     }
 
+    /**
+     * return the reference to the file detail sharing fragment to communicate with it.
+     *
+     * @return reference to the {@link FileDetailSharingFragment}
+     */
+    public FileDetailSharingFragment getFileDetailSharingFragment() {
+        return ((FileDetailTabAdapter)viewPager.getAdapter()).getFileDetailSharingFragment();
+    }
+
     @Override
     public void onResume() {
         super.onResume();
@@ -345,16 +354,12 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
         }
 
         if (getFile().isFolder()) {
-            FileMenuFilter.hideMenuItems(
-                    menu.findItem(R.id.action_send_file)
-            );
+            FileMenuFilter.hideMenuItems(menu.findItem(R.id.action_send_file));
         }
 
         // dual pane restrictions
         if (!getResources().getBoolean(R.bool.large_land_layout)){
-            FileMenuFilter.hideMenuItems(
-                    menu.findItem(R.id.action_sync_account)
-            );
+            FileMenuFilter.hideMenuItems(menu.findItem(R.id.action_sync_account));
         }
     }
 

+ 226 - 20
src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java

@@ -23,17 +23,26 @@ package com.owncloud.android.ui.fragment;
 import android.accounts.Account;
 import android.app.SearchManager;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.v4.app.Fragment;
+import android.support.v7.widget.AppCompatButton;
 import android.support.v7.widget.SearchView;
+import android.support.v7.widget.SwitchCompat;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
+import android.widget.CheckBox;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.ListAdapter;
 import android.widget.ListView;
+import android.widget.PopupMenu;
 import android.widget.TextView;
 
 import com.owncloud.android.R;
@@ -42,14 +51,21 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.adapter.UserListAdapter;
+import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
+import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
 import com.owncloud.android.utils.ThemeUtils;
 
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 
 import butterknife.BindView;
 import butterknife.ButterKnife;
+import butterknife.OnClick;
 import butterknife.Unbinder;
 
 public class FileDetailSharingFragment extends Fragment implements UserListAdapter.ShareeListAdapterListener {
@@ -63,21 +79,11 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
 
     private OCFile file;
     private Account account;
+    private OCCapability capabilities;
+    private OCShare publicShare;
 
     private Unbinder unbinder;
 
-    @BindView(R.id.fdShareTitle)
-    TextView shareTitle;
-
-    @BindView(R.id.fdShareWithUsersTitle)
-    TextView shareWithUsersTitle;
-
-    @BindView(R.id.fdSharebyLink)
-    TextView sharebyLink;
-
-    @BindView(R.id.fdShareLinkIcon)
-    ImageView linkIcon;
-
     @BindView(R.id.searchView)
     SearchView searchView;
 
@@ -87,6 +93,19 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
     @BindView(R.id.fdShareNoUsers)
     TextView noList;
 
+    @BindView(R.id.share_by_link)
+    CheckBox shareByLink;
+
+    @BindView(R.id.overflow_menu_share_link)
+    ImageView overflowMenuShareLink;
+
+    @BindView(R.id.share_by_link_allow_editing)
+    CheckBox shareByLinkAllowEditing;
+
+    @BindView(R.id.share_by_link_container)
+    LinearLayout shareByLinkContainer;
+
+
     public static FileDetailSharingFragment newInstance(OCFile file, Account account) {
         FileDetailSharingFragment fragment = new FileDetailSharingFragment();
         Bundle args = new Bundle();
@@ -96,6 +115,15 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
         return fragment;
     }
 
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        Log_OC.d(TAG, "onActivityCreated");
+
+        // Load known capabilities of the server from DB
+        refreshCapabilitiesFromDB();
+    }
+
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater,
                              ViewGroup container,
@@ -132,9 +160,6 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
     }
 
     private void setupView() {
-        shareTitle.setTextColor(ThemeUtils.primaryAccentColor(getContext()));
-        shareWithUsersTitle.setTextColor(ThemeUtils.primaryAccentColor(getContext()));
-
         setShareByLinkInfo(file.isSharedViaLink());
         setShareWithUserInfo();
         setupSearchView();
@@ -170,15 +195,23 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
     }
 
     /**
-     * Updates Share by link data
+     * Updates Share by link UI
      *
      * @param isShareByLink flag is share by link is enable
      */
     private void setShareByLinkInfo(boolean isShareByLink) {
-        sharebyLink.setText(isShareByLink ? R.string.filedetails_share_link_enable :
-                    R.string.filedetails_share_link_disable);
+        shareByLink.setChecked(isShareByLink);
+        setLinkDetailVisible(isShareByLink);
+    }
 
-        linkIcon.setVisibility(isShareByLink ? View.VISIBLE : View.GONE);
+    private void setLinkDetailVisible(boolean visible) {
+        if (visible) {
+            shareByLinkAllowEditing.setVisibility(View.VISIBLE);
+            overflowMenuShareLink.setVisibility(View.VISIBLE);
+        } else {
+            shareByLinkAllowEditing.setVisibility(View.INVISIBLE);
+            overflowMenuShareLink.setVisibility(View.INVISIBLE);
+        }
     }
 
     /**
@@ -187,7 +220,8 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
     private void setShareWithUserInfo(){
         // Get Users and Groups
         if (((FileActivity) getActivity()).getStorageManager() != null) {
-            FileDataStorageManager fileDataStorageManager = ((FileActivity) getActivity()).getStorageManager();
+            FileDataStorageManager fileDataStorageManager = ((FileActivity) getActivity())
+                    .getStorageManager();
             mShares = fileDataStorageManager.getSharesWithForAFile(
                     file.getRemotePath(),account.name
             );
@@ -241,6 +275,99 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
         listView.requestLayout();
     }
 
+    @OnClick(R.id.share_by_link)
+    public void toggleShareByLink() {
+        if (shareByLink.isChecked()) {
+            if (capabilities != null &&
+                    capabilities.getFilesSharingPublicPasswordEnforced().isTrue()) {
+                // password enforced by server, request to the user before trying to create
+                requestPasswordForShareViaLink(true);
+
+            } else {
+                // create without password if not enforced by server or we don't know if enforced;
+                ((FileActivity) getActivity()).getFileOperationsHelper().shareFileViaLink(file, null);
+
+                // ShareActivity#onCreateShareViaLinkOperationFinish will take care if password
+                // is enforced by the server but app doesn't know, or if server version is
+                // older than OwnCloudVersion#MINIMUM_VERSION_CAPABILITIES_API
+            }
+
+        } else {
+            ((FileActivity) getActivity()).getFileOperationsHelper().unshareFileViaLink(file);
+        }
+    }
+
+    @OnClick(R.id.share_link_label)
+    public void showSendLinkTo() {
+        if (file.isSharedViaLink()) {
+            ((FileActivity) getActivity()).getFileOperationsHelper().getFileWithLink(file);
+        }
+    }
+
+    @OnClick(R.id.share_by_link_allow_editing)
+    public void toggleShareLinkAllowEditing() {
+        if (file.isSharedViaLink()) {
+            ((FileActivity) getActivity()).getFileOperationsHelper().setUploadPermissionsToShare(file, shareByLinkAllowEditing.isChecked());
+        }
+    }
+
+    @OnClick(R.id.overflow_menu_share_link)
+    public void showLinkOverflowMenu() {
+        PopupMenu popup = new PopupMenu(getActivity(), overflowMenuShareLink);
+        popup.inflate(R.menu.file_detail_sharing_menu);
+        prepareOptionsMenu(popup.getMenu());
+        popup.setOnMenuItemClickListener(this::optionsItemSelected);
+        popup.show();
+    }
+
+    private void prepareOptionsMenu(Menu menu) {
+        // TODO implement setting the correct menu item titles based on the share/permissions info
+        Resources res = getResources();
+        setupExpirationDateMenuItem(menu.findItem(R.id.action_share_link_expiration_date), res);
+    }
+
+    private void setupExpirationDateMenuItem(MenuItem expirationDate, Resources res) {
+        long expirationDateValue = publicShare.getExpirationDate();
+        if (expirationDateValue > 0) {
+            String formattedDate =
+                    SimpleDateFormat.getDateInstance().format(
+                            new Date(expirationDateValue)
+                    );
+            expirationDate.setTitle(res.getString(
+                    R.string.share_via_link_menu_expiration_date_label,
+                    formattedDate
+            ));
+        } else {
+            expirationDate.setTitle(res.getString(
+                    R.string.share_via_link_menu_expiration_date_label,
+                    res.getString(R.string.share_via_link_menu_expiration_date_never)
+            ));
+        }
+    }
+
+    private boolean optionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_share_link_permissions: {
+                return true;
+            }
+            case R.id.action_share_link_password: {
+                requestPasswordForShareViaLink(false);
+                return true;
+            }
+            case R.id.action_share_link_expiration_date: {
+                // TODO extend date picker to allow for clearing/unsetting a date
+                ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment.newInstance(file, -1);
+                dialog.show(
+                        getActivity().getSupportFragmentManager(),
+                        ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
+                );
+                return true;
+            }
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
     @Override
     public void unshareWith(OCShare share) {
         ((FileActivity)getActivity()).getFileOperationsHelper()
@@ -271,4 +398,83 @@ public class FileDetailSharingFragment extends Fragment implements UserListAdapt
 
         return permissions;
     }
+
+    /**
+     * Starts a dialog that requests a password to the user to protect a share link.
+     *
+     * @param createShare When 'true', the request for password will be followed by the creation of a new
+     *                    public link; when 'false', a public share is assumed to exist, and the password
+     *                    is bound to it.
+     */
+    public void requestPasswordForShareViaLink(boolean createShare) {
+        SharePasswordDialogFragment dialog = SharePasswordDialogFragment.newInstance(file, createShare);
+        dialog.show(getFragmentManager(), SharePasswordDialogFragment.PASSWORD_FRAGMENT);
+    }
+
+    /**
+     * Get known server capabilities from DB
+     * <p/>
+     * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
+     * instance ready to use. If not ready, does nothing.
+     */
+    public void refreshCapabilitiesFromDB() {
+        if (((FileActivity) getActivity()).getStorageManager() != null) {
+            capabilities = ((FileActivity) getActivity()).getStorageManager().getCapability(account.name);
+        }
+    }
+
+    /**
+     * Get public link from the DB to fill in the "Share link" section in the UI.
+     *
+     * Takes into account server capabilities before reading database.
+     *
+     * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
+     * instance ready to use. If not ready, does nothing.
+     */
+    public void refreshPublicShareFromDB() {
+        if (isPublicShareDisabled()) {
+            hidePublicShare();
+        } else if (((FileActivity) getActivity()).getStorageManager() != null) {
+            // Get public share
+            publicShare = ((FileActivity) getActivity()).getStorageManager().getFirstShareByPathAndType(
+                    file.getRemotePath(),
+                    ShareType.PUBLIC_LINK,
+                    ""
+            );
+
+            // Update public share section
+            updatePublicShareSection();
+        }
+    }
+
+    /**
+     * Updates in the UI the section about public share with the information in the current public share bound to
+     * mFile, if any.
+     */
+    private void updatePublicShareSection() {
+        if (publicShare != null && ShareType.PUBLIC_LINK.equals(publicShare.getShareType())) {
+            shareByLink.setChecked(true);
+
+            if (publicShare.getPermissions() > OCShare.READ_PERMISSION_FLAG) {
+                shareByLinkAllowEditing.setChecked(true);
+            } else {
+                shareByLinkAllowEditing.setChecked(false);
+            }
+        }
+    }
+
+    /**
+     * @return 'True' when public share is disabled in the server.
+     */
+    private boolean isPublicShareDisabled() {
+        return (capabilities != null && capabilities.getFilesSharingPublicEnabled().isFalse()
+        );
+    }
+
+    /**
+     * Hides all the UI elements related to public share.
+     */
+    private void hidePublicShare() {
+        shareByLinkContainer.setVisibility(View.GONE);
+    }
 }

+ 43 - 44
src/main/res/layout/file_details_sharing_fragment.xml

@@ -28,65 +28,64 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
-        android:paddingTop="@dimen/standard_padding">
+        android:paddingTop="@dimen/standard_half_padding">
 
-        <TextView
-            android:id="@+id/fdShareTitle"
-            style="@style/TextAppearance.AppCompat.Body2"
+        <android.support.v7.widget.SearchView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="@dimen/standard_half_margin"
-            android:paddingLeft="@dimen/standard_padding"
-            android:paddingRight="@dimen/standard_padding"
-            android:text="@string/common_share"
-            android:textColor="@color/color_accent" />
+            android:id="@+id/searchView"
+            android:hint="@string/share_search"
+            style="@style/ownCloud.SearchView"/>
 
         <LinearLayout
+            android:id="@+id/share_by_link_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/standard_half_margin"
             android:orientation="horizontal"
             android:paddingLeft="@dimen/standard_padding"
             android:paddingRight="@dimen/standard_padding"
-            tools:ignore="UseCompoundDrawables">
+            android:paddingTop="@dimen/standard_half_padding">
 
-            <ImageView
-                android:id="@+id/fdShareLinkIcon"
-                android:layout_width="@dimen/shared_list_icon_width"
-                android:layout_height="@dimen/shared_list_icon_height"
-                android:layout_gravity="center_vertical"
-                android:layout_marginEnd="@dimen/standard_half_margin"
-                android:layout_marginRight="@dimen/standard_half_margin"
-                android:contentDescription="@string/shared_icon"
-                android:src="@drawable/shared_via_link"
-                android:visibility="gone" />
+            <CheckBox
+                android:id="@+id/share_by_link"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"/>
 
             <TextView
-                android:id="@+id/fdSharebyLink"
-                android:layout_width="match_parent"
+                android:id="@+id/share_link_label"
+                android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:layout_gravity="start"
-                android:text="@string/filedetails_share_link_disable" />
-        </LinearLayout>
+                android:layout_gravity="start|center"
+                android:textColor="@color/black"
+                android:layout_weight="1"
+                android:textSize="@dimen/two_line_secondary_text_size"
+                android:paddingTop="@dimen/standard_half_padding"
+                android:paddingBottom="@dimen/standard_half_padding"
+                android:text="@string/share_via_link_section_title" />
 
-        <TextView
-            android:id="@+id/fdShareWithUsersTitle"
-            style="@style/TextAppearance.AppCompat.Body2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start"
-            android:layout_marginBottom="@dimen/standard_half_margin"
-            android:layout_marginTop="@dimen/standard_half_margin"
-            android:paddingLeft="@dimen/standard_padding"
-            android:paddingRight="@dimen/standard_padding"
-            android:text="@string/filedetails_share_users_with_access"
-            android:textColor="@color/color_accent" />
+            <CheckBox
+                android:id="@+id/share_by_link_allow_editing"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/share_via_link_edit_permission_label"/>
 
-        <android.support.v7.widget.SearchView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:id="@+id/searchView"
-            android:hint="@string/share_search"
-            style="@style/ownCloud.SearchView"/>
+            <ImageView
+                android:id="@+id/overflow_menu_share_link"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="end|center"
+                android:layout_marginLeft="@dimen/standard_half_margin"
+                android:layout_marginStart="@dimen/standard_half_margin"
+                android:contentDescription="@string/overflow_menu"
+                android:paddingEnd="@dimen/zero"
+                android:paddingLeft="@dimen/standard_half_padding"
+                android:paddingRight="@dimen/zero"
+                android:paddingStart="@dimen/standard_half_padding"
+                android:src="@drawable/ic_dots_vertical" />
+        </LinearLayout>
 
         <ListView
             android:id="@+id/fdshareUsersList"
@@ -99,7 +98,7 @@
             android:id="@+id/fdShareNoUsers"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingBottom="@dimen/standard_padding"
+            android:paddingTop="@dimen/standard_half_padding"
             android:paddingLeft="@dimen/standard_padding"
             android:paddingRight="@dimen/standard_padding"
             android:text="@string/share_no_users"

+ 41 - 0
src/main/res/menu/file_detail_sharing_link_menu.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nesxtcloud Android client application
+
+  Copyright (C) 2018 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  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 AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="AppCompatResource">
+
+    <item
+        android:id="@+id/action_share_link_permissions"
+        android:showAsAction="never"
+        android:title="@string/share_via_link_menu_permissions_label"
+        app:showAsAction="never" />
+    <item
+        android:id="@+id/action_share_link_password"
+        android:showAsAction="never"
+        android:title="@string/share_via_link_menu_password_label"
+        app:showAsAction="never" />
+    <item
+        android:id="@+id/action_share_link_expiration_date"
+        android:showAsAction="never"
+        android:title="@string/share_via_link_menu_expiration_date_label"
+        app:showAsAction="never" />
+
+</menu>

+ 0 - 4
src/main/res/menu/file_detail_sharing_menu.xml

@@ -25,28 +25,24 @@
     <item
         android:id="@+id/action_can_edit"
         android:checkable="true"
-        android:icon="@drawable/ic_share"
         android:showAsAction="never"
         android:title="@string/share_privilege_can_edit"
         app:showAsAction="never" />
     <item
         android:id="@+id/action_can_edit_create"
         android:checkable="true"
-        android:icon="@drawable/ic_share"
         android:showAsAction="never"
         android:title="@string/share_privilege_can_edit_create"
         app:showAsAction="never" />
     <item
         android:id="@+id/action_can_edit_change"
         android:checkable="true"
-        android:icon="@drawable/ic_share"
         android:showAsAction="never"
         android:title="@string/share_privilege_can_edit_change"
         app:showAsAction="never" />
     <item
         android:id="@+id/action_can_edit_delete"
         android:checkable="true"
-        android:icon="@drawable/ic_share"
         android:showAsAction="never"
         android:title="@string/share_privilege_can_edit_delete"
         app:showAsAction="never" />

+ 5 - 1
src/main/res/values/strings.xml

@@ -480,11 +480,15 @@
     <string name="share_with_user_section_title">Share with users and groups</string>
     <string name="share_no_users">No data shared with users yet</string>
     <string name="share_add_user_or_group">Add user or group</string>
+    <string name="share_via_link_menu_permissions_label">Permissions (%1$s)</string>
+    <string name="share_via_link_menu_password_label">Password protect (%1$s)</string>
+    <string name="share_via_link_menu_expiration_date_label">Set expiration date (%1$s)</string>
+    <string name="share_via_link_menu_expiration_date_never">never</string>
     <string name="share_via_link_section_title">Share link</string>
     <string name="share_via_link_expiration_date_label">Set expiration date</string>
     <string name="share_via_link_password_label">Protect with password</string>
     <string name="share_via_link_password_title">Secured</string>
-    <string name="share_via_link_edit_permission_label">Allow edits</string>
+    <string name="share_via_link_edit_permission_label">Allow editing</string>
     <string name="share_via_link_hide_file_listing_permission_label">Hide file listing</string>
     <string name="share_get_public_link_button">Get link</string>
     <string name="share_with_title">Share with…</string>