Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2020-07-07 08:15:53 +02:00
parent 82d36f0cab
commit 20d24d8a6d
No known key found for this signature in database
GPG key ID: 0E00D4D47D0C5AF7
10 changed files with 407 additions and 419 deletions

View file

@ -26,6 +26,7 @@ import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.utils.ThemeUtils; import com.owncloud.android.utils.ThemeUtils;
@ -47,9 +48,10 @@ class PublicShareViewHolder extends RecyclerView.ViewHolder {
this.context = context; this.context = context;
} }
public void bind(OCShare publicShare, ShareeListAdapter.ShareeListAdapterListener listener) { public void bind(OCShare publicShare, ShareeListAdapterListener listener) {
if (!TextUtils.isEmpty(publicShare.getLabel())) { if (!TextUtils.isEmpty(publicShare.getLabel())) {
binding.publicShareLabel.setText(publicShare.getLabel()); String text = String.format(context.getString(R.string.share_link), publicShare.getLabel());
binding.publicShareLabel.setText(text);
} }
ThemeUtils.colorIconImageViewWithBackground(binding.copyInternalLinkIcon, context); ThemeUtils.colorIconImageViewWithBackground(binding.copyInternalLinkIcon, context);

View file

@ -25,43 +25,24 @@
package com.owncloud.android.ui.adapter; package com.owncloud.android.ui.adapter;
import android.accounts.Account;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.databinding.FileDetailsShareUserItemBinding;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.TextDrawable;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.ui.dialog.NoteDialogFragment;
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ThemeUtils;
import java.security.NoSuchAlgorithmException; import java.util.Collections;
import java.util.List; import java.util.List;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
/** /**
* Adapter to show a user/group/email/remote in Sharing list in file details view. * Adapter to show a user/group/email/remote in Sharing list in file details view.
@ -70,27 +51,23 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
implements DisplayUtils.AvatarGenerationListener { implements DisplayUtils.AvatarGenerationListener {
private ShareeListAdapterListener listener; private ShareeListAdapterListener listener;
private OCCapability capabilities;
private FragmentManager fragmentManager;
private Context context; private Context context;
private int accentColor;
private List<OCShare> shares; private List<OCShare> shares;
private float avatarRadiusDimension; private float avatarRadiusDimension;
private OCFile file;
private String userId; private String userId;
public ShareeListAdapter(FragmentManager fragmentManager, Context context, List<OCShare> shares, Account account, public ShareeListAdapter(Context context,
OCFile file, ShareeListAdapterListener listener, String userId) { List<OCShare> shares,
ShareeListAdapterListener listener,
String userId) {
this.context = context; this.context = context;
this.fragmentManager = fragmentManager;
this.shares = shares; this.shares = shares;
this.listener = listener; this.listener = listener;
this.file = file;
this.userId = userId; this.userId = userId;
accentColor = ThemeUtils.primaryAccentColor(context);
capabilities = new FileDataStorageManager(account, context.getContentResolver()).getCapability(account.name);
avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius); avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius);
sort(this.shares);
} }
@Override @Override
@ -103,18 +80,16 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch (ShareType.fromValue(viewType)) { switch (ShareType.fromValue(viewType)) {
case PUBLIC_LINK: case PUBLIC_LINK:
FileDetailsSharePublicLinkItemBinding binding = case EMAIL:
FileDetailsSharePublicLinkItemBinding.inflate(LayoutInflater.from(context), parent, false); return new PublicShareViewHolder(FileDetailsSharePublicLinkItemBinding.inflate(LayoutInflater.from(context),
parent,
return new PublicShareViewHolder(binding, context); false),
context);
// case USER:
// nothing for now
// break;
default: default:
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.file_details_share_user_item, parent, false); return new UserViewHolder(FileDetailsShareUserItemBinding.inflate(LayoutInflater.from(context),
return new UserViewHolder(v); parent,
false),
context);
} }
} }
@ -131,53 +106,7 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
publicShareViewHolder.bind(share, listener); publicShareViewHolder.bind(share, listener);
} else { } else {
UserViewHolder userViewHolder = (UserViewHolder) holder; UserViewHolder userViewHolder = (UserViewHolder) holder;
String name = share.getSharedWithDisplayName(); userViewHolder.bind(share, listener, userId, avatarRadiusDimension);
switch (share.getShareType()) {
case GROUP:
name = context.getString(R.string.share_group_clarification, name);
setImage(userViewHolder, name, R.drawable.ic_group);
break;
case EMAIL:
name = context.getString(R.string.share_email_clarification, name);
setImage(userViewHolder, name, R.drawable.ic_email);
break;
case ROOM:
name = context.getString(R.string.share_room_clarification, name);
setImage(userViewHolder, name, R.drawable.ic_chat_bubble);
break;
case CIRCLE:
userViewHolder.avatar.setImageResource(R.drawable.ic_circles);
break;
default:
setImage(userViewHolder, name, R.drawable.ic_user);
break;
}
userViewHolder.name.setText(name);
if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
userViewHolder.allowEditing.setVisibility(View.VISIBLE);
userViewHolder.editShareButton.setVisibility(View.VISIBLE);
ThemeUtils.tintCheckbox(userViewHolder.allowEditing, accentColor);
userViewHolder.allowEditing.setChecked(canEdit(share));
userViewHolder.allowEditing.setOnClickListener(v -> allowEditClick(userViewHolder.allowEditing, share));
// bind listener to edit privileges
userViewHolder.editShareButton.setOnClickListener(v -> onOverflowIconClicked(v, userViewHolder.allowEditing, share));
} else {
userViewHolder.allowEditing.setVisibility(View.GONE);
userViewHolder.editShareButton.setVisibility(View.GONE);
}
}
}
private void setImage(UserViewHolder holder, String name, @DrawableRes int fallback) {
try {
holder.avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
} catch (NoSuchAlgorithmException e) {
holder.avatar.setImageResource(fallback);
} }
} }
@ -191,208 +120,10 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
return shares.size(); return shares.size();
} }
private void allowEditClick(AppCompatCheckBox checkBox, @NonNull OCShare share) {
if (!share.isFolder()) {
share.setPermissions(listener.updatePermissionsToShare(
share,
canReshare(share),
checkBox.isChecked(),
false,
false,
false
));
} else {
share.setPermissions(listener.updatePermissionsToShare(
share,
canReshare(share),
checkBox.isChecked(),
checkBox.isChecked(),
checkBox.isChecked(),
checkBox.isChecked()
));
}
}
private void onOverflowIconClicked(View view, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
// use grey as fallback for elements where custom theming is not available
if (ThemeUtils.themingEnabled(context)) {
context.getTheme().applyStyle(R.style.FallbackThemingTheme, true);
}
PopupMenu popup = new PopupMenu(context, view);
popup.inflate(R.menu.item_user_sharing_settings);
prepareOptionsMenu(popup.getMenu(), share);
popup.setOnMenuItemClickListener(item -> optionsItemSelected(popup.getMenu(), item, allowEditsCheckBox, share));
popup.show();
}
/**
* Updates the sharee's menu with the current permissions of the {@link OCShare}
*
* @param menu the menu of the sharee/shared file
* @param share the shared file
*/
private void prepareOptionsMenu(Menu menu, OCShare share) {
MenuItem editCreateItem = menu.findItem(R.id.action_can_edit_create);
MenuItem editChangeItem = menu.findItem(R.id.action_can_edit_change);
MenuItem editDeleteItem = menu.findItem(R.id.action_can_edit_delete);
MenuItem hideFileListingItem = menu.findItem(R.id.action_hide_file_listing);
MenuItem passwordItem = menu.findItem(R.id.action_password);
MenuItem expirationDateItem = menu.findItem(R.id.action_expiration_date);
MenuItem reshareItem = menu.findItem(R.id.action_can_reshare);
MenuItem sendNoteItem = menu.findItem(R.id.action_share_send_note);
if (isReshareForbidden(share)) {
reshareItem.setVisible(false);
}
reshareItem.setChecked(canReshare(share));
if (share.getShareType() == ShareType.EMAIL) {
SharingMenuHelper.setupHideFileListingMenuItem(
hideFileListingItem,
file.isFolder(),
canEdit(share),
share.getPermissions()
);
SharingMenuHelper.setupPasswordMenuItem(passwordItem, share.isPasswordProtected());
reshareItem.setVisible(false);
editCreateItem.setVisible(false);
editChangeItem.setVisible(false);
editDeleteItem.setVisible(false);
} else {
if (file.isFolder() && isEditOptionsAvailable(share)) {
/// TODO change areEditOptionsAvailable in order to delete !isFederated
editCreateItem.setChecked(canCreate(share));
editChangeItem.setChecked(canUpdate(share));
editDeleteItem.setChecked(canDelete(share));
} else {
editCreateItem.setVisible(false);
editChangeItem.setVisible(false);
editDeleteItem.setVisible(false);
}
hideFileListingItem.setVisible(false);
passwordItem.setVisible(false);
if (!capabilities.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_18)) {
expirationDateItem.setVisible(false);
}
}
SharingMenuHelper.setupExpirationDateMenuItem(
menu.findItem(R.id.action_expiration_date), share.getExpirationDate(), context.getResources());
sendNoteItem.setVisible(capabilities.getVersion().isNoteOnShareSupported());
}
private boolean isEditOptionsAvailable(OCShare share) {
return !ShareType.FEDERATED.equals(share.getShareType());
}
private boolean isReshareForbidden(OCShare share) {
return ShareType.FEDERATED.equals(share.getShareType()) ||
(capabilities != null && capabilities.getFilesSharingResharing().isFalse());
}
private boolean canEdit(OCShare share) {
return (share.getPermissions() &
(OCShare.CREATE_PERMISSION_FLAG | OCShare.UPDATE_PERMISSION_FLAG | OCShare.DELETE_PERMISSION_FLAG)) > 0;
}
private boolean canCreate(OCShare share) {
return (share.getPermissions() & OCShare.CREATE_PERMISSION_FLAG) > 0;
}
private boolean canUpdate(OCShare share) {
return (share.getPermissions() & OCShare.UPDATE_PERMISSION_FLAG) > 0;
}
private boolean canDelete(OCShare share) {
return (share.getPermissions() & OCShare.DELETE_PERMISSION_FLAG) > 0;
}
private boolean canReshare(OCShare share) {
return (share.getPermissions() & OCShare.SHARE_PERMISSION_FLAG) > 0;
}
private boolean optionsItemSelected(Menu menu, MenuItem item, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
switch (item.getItemId()) {
case R.id.action_can_edit_create:
case R.id.action_can_edit_change:
case R.id.action_can_edit_delete: {
item.setChecked(!item.isChecked());
if (item.isChecked() && !allowEditsCheckBox.isChecked()) {
allowEditsCheckBox.setChecked(true);
}
share.setPermissions(
updatePermissionsToShare(
share,
menu.findItem(R.id.action_can_reshare).isChecked(),
allowEditsCheckBox.isChecked(),
menu.findItem(R.id.action_can_edit_create).isChecked(),
menu.findItem(R.id.action_can_edit_change).isChecked(),
menu.findItem(R.id.action_can_edit_delete).isChecked())
);
return true;
}
case R.id.action_can_reshare: {
item.setChecked(!item.isChecked());
share.setPermissions(
updatePermissionsToShare(
share,
menu.findItem(R.id.action_can_reshare).isChecked(),
allowEditsCheckBox.isChecked(),
menu.findItem(R.id.action_can_edit_create).isChecked(),
menu.findItem(R.id.action_can_edit_change).isChecked(),
menu.findItem(R.id.action_can_edit_delete).isChecked())
);
return true;
}
case R.id.action_unshare: {
listener.unshareWith(share);
shares.remove(share);
notifyDataSetChanged();
return true;
}
case R.id.action_password: {
listener.requestPasswordForShare(share, false);
return true;
}
case R.id.action_expiration_date: {
ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment
.newInstance(share, share.getExpirationDate());
dialog.show(fragmentManager, ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG);
return true;
}
case R.id.action_share_send_note:
NoteDialogFragment dialog = NoteDialogFragment.newInstance(share);
dialog.show(fragmentManager, NoteDialogFragment.NOTE_FRAGMENT);
return true;
default:
return true;
}
}
private int updatePermissionsToShare(OCShare share, boolean canReshare, boolean canEdit, boolean canEditCreate,
boolean canEditChange, boolean canEditDelete) {
return listener.updatePermissionsToShare(
share,
canReshare,
canEdit,
canEditCreate,
canEditChange,
canEditDelete
);
}
public void addShares(List<OCShare> sharesToAdd) { public void addShares(List<OCShare> sharesToAdd) {
shares.addAll(sharesToAdd); shares.addAll(sharesToAdd);
sort(shares);
notifyDataSetChanged();
} }
@Override @Override
@ -412,57 +143,18 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
return false; return false;
} }
class UserViewHolder extends RecyclerView.ViewHolder { public void remove(OCShare share) {
@BindView(R.id.avatar) shares.remove(share);
ImageView avatar; notifyDataSetChanged();
@BindView(R.id.name)
TextView name;
@BindView(R.id.allowEditing)
AppCompatCheckBox allowEditing;
@BindView(R.id.editShareButton)
ImageView editShareButton;
UserViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
} }
public interface ShareeListAdapterListener { private void sort(List<OCShare> shares) {
/** Collections.sort(shares, (o1, o2) -> {
* unshare with given sharee {@link OCShare}. if (o1.getShareType() != o2.getShareType()) {
* return o1.getShareType().compareTo(o2.getShareType());
* @param share the share }
*/
void unshareWith(OCShare share);
/** return o1.getSharedWithDisplayName().compareTo(o2.getSharedWithDisplayName());
* Updates the permissions of the {@link OCShare}. });
*
* @param share the share to be updated
* @param canReshare reshare permission
* @param canEdit edit permission
* @param canEditCreate create permission (folders only)
* @param canEditChange change permission (folders only)
* @param canEditDelete delete permission (folders only)
* @return permissions value set
*/
int updatePermissionsToShare(OCShare share,
boolean canReshare,
boolean canEdit,
boolean canEditCreate,
boolean canEditChange,
boolean canEditDelete);
/**
* Starts a dialog that requests a password to the user to protect a share.
*
* @param share the share for which a password shall be configured/removed
*/
void requestPasswordForShare(OCShare share, boolean askForPassword);
void copyLink(OCShare share);
void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink);
} }
} }

View file

@ -0,0 +1,35 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) 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 <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.widget.ImageView;
import com.owncloud.android.lib.resources.shares.OCShare;
public interface ShareeListAdapterListener {
void copyLink(OCShare share);
void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink);
void showUserOverflowMenu(OCShare share, ImageView overflowMenu);
}

View file

@ -0,0 +1,103 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) 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 <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsShareUserItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.ui.TextDrawable;
import java.security.NoSuchAlgorithmException;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
class UserViewHolder extends RecyclerView.ViewHolder {
private FileDetailsShareUserItemBinding binding;
private float avatarRadiusDimension;
private Context context;
public UserViewHolder(@NonNull View itemView) {
super(itemView);
}
public UserViewHolder(FileDetailsShareUserItemBinding binding, Context context) {
this(binding.getRoot());
this.binding = binding;
this.context = context;
}
public void bind(OCShare share,
ShareeListAdapterListener listener,
String userId,
float avatarRadiusDimension) {
this.avatarRadiusDimension = avatarRadiusDimension;
String name = share.getSharedWithDisplayName();
switch (share.getShareType()) {
case GROUP:
name = context.getString(R.string.share_group_clarification, name);
setImage(binding.avatar, name, R.drawable.ic_group);
break;
case EMAIL:
name = context.getString(R.string.share_email_clarification, name);
setImage(binding.avatar, name, R.drawable.ic_email);
break;
case ROOM:
name = context.getString(R.string.share_room_clarification, name);
setImage(binding.avatar, name, R.drawable.ic_chat_bubble);
break;
case CIRCLE:
binding.avatar.setImageResource(R.drawable.ic_circles);
break;
default:
setImage(binding.avatar, name, R.drawable.ic_user);
break;
}
binding.name.setText(name);
if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
binding.editShareButton.setVisibility(View.VISIBLE);
// bind listener to edit privileges
binding.editShareButton.setOnClickListener(v -> listener.showUserOverflowMenu(share,
binding.editShareButton));
} else {
binding.editShareButton.setVisibility(View.GONE);
}
}
private void setImage(ImageView avatar, String name, @DrawableRes int fallback) {
try {
avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
} catch (NoSuchAlgorithmException e) {
avatar.setImageResource(fallback);
}
}
}

View file

@ -53,9 +53,11 @@ import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder; import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder;
import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.adapter.ShareeListAdapter; import com.owncloud.android.ui.adapter.ShareeListAdapter;
import com.owncloud.android.ui.adapter.ShareeListAdapterListener;
import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration; import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment; import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.ui.dialog.NoteDialogFragment; import com.owncloud.android.ui.dialog.NoteDialogFragment;
@ -84,7 +86,7 @@ import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.Unbinder; import butterknife.Unbinder;
public class FileDetailSharingFragment extends Fragment implements ShareeListAdapter.ShareeListAdapterListener, public class FileDetailSharingFragment extends Fragment implements ShareeListAdapterListener,
DisplayUtils.AvatarGenerationListener, DisplayUtils.AvatarGenerationListener,
Injectable { Injectable {
@ -283,11 +285,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID); com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
sharesList.setVisibility(View.VISIBLE); sharesList.setVisibility(View.VISIBLE);
sharesList.setAdapter(new ShareeListAdapter(fileActivity.getSupportFragmentManager(), sharesList.setAdapter(new ShareeListAdapter(fileActivity,
fileActivity,
shares, shares,
user.toPlatformAccount(),
file,
this, this,
userId)); userId));
sharesList.setLayoutManager(new LinearLayoutManager(getContext())); sharesList.setLayoutManager(new LinearLayoutManager(getContext()));
@ -346,6 +345,73 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
} }
} }
@Override
public void showUserOverflowMenu(OCShare share, ImageView overflowMenu) {
// use grey as fallback for elements where custom theming is not available
if (ThemeUtils.themingEnabled(requireContext())) {
requireContext().getTheme().applyStyle(R.style.FallbackThemingTheme, true);
}
PopupMenu popup = new PopupMenu(requireContext(), overflowMenu);
popup.inflate(R.menu.item_user_sharing_settings);
prepareUserOptionsMenu(popup.getMenu(), share);
popup.setOnMenuItemClickListener(item -> userOptionsItemSelected(popup.getMenu(), item, share));
popup.show();
}
/**
* Updates the sharee's menu with the current permissions of the {@link OCShare}
*
* @param menu the menu of the sharee/shared file
* @param share the shared file
*/
private void prepareUserOptionsMenu(Menu menu, OCShare share) {
MenuItem allowCreatingItem = menu.findItem(R.id.allow_creating);
MenuItem allowDeletingItem = menu.findItem(R.id.allow_deleting);
MenuItem hideFileListingItem = menu.findItem(R.id.action_hide_file_listing);
MenuItem passwordItem = menu.findItem(R.id.action_password);
MenuItem expirationDateItem = menu.findItem(R.id.action_expiration_date);
MenuItem reshareItem = menu.findItem(R.id.allow_resharing);
MenuItem sendNoteItem = menu.findItem(R.id.action_share_send_note);
if (isReshareForbidden(share)) {
reshareItem.setVisible(false);
}
reshareItem.setChecked(canReshare(share));
if (share.getShareType() == ShareType.EMAIL) {
SharingMenuHelper.setupHideFileListingMenuItem(hideFileListingItem,
file.isFolder(),
canEdit(share),
share.getPermissions());
SharingMenuHelper.setupPasswordMenuItem(passwordItem, share.isPasswordProtected());
reshareItem.setVisible(false);
allowCreatingItem.setVisible(false);
allowDeletingItem.setVisible(false);
} else {
if (file.isFolder() && isEditOptionsAvailable(share)) {
allowCreatingItem.setChecked(canCreate(share));
allowDeletingItem.setChecked(canDelete(share));
} else {
allowCreatingItem.setVisible(false);
allowDeletingItem.setVisible(false);
}
hideFileListingItem.setVisible(false);
passwordItem.setVisible(false);
if (!capabilities.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_18)) {
expirationDateItem.setVisible(false);
}
}
SharingMenuHelper.setupExpirationDateMenuItem(menu.findItem(R.id.action_expiration_date),
share.getExpirationDate(),
getResources());
sendNoteItem.setVisible(capabilities.getVersion().isNoteOnShareSupported());
}
public void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink) { public void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink) {
if (ThemeUtils.themingEnabled(requireContext())) { if (ThemeUtils.themingEnabled(requireContext())) {
// use grey as fallback for elements where custom theming is not available // use grey as fallback for elements where custom theming is not available
@ -354,17 +420,17 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
PopupMenu popup = new PopupMenu(requireContext(), overflowMenuShareLink); PopupMenu popup = new PopupMenu(requireContext(), overflowMenuShareLink);
popup.inflate(R.menu.fragment_file_detail_sharing_link); popup.inflate(R.menu.fragment_file_detail_sharing_link);
prepareOptionsMenu(popup.getMenu(), publicShare); prepareLinkOptionsMenu(popup.getMenu(), publicShare);
popup.setOnMenuItemClickListener(menuItem -> optionsItemSelected(menuItem, publicShare)); popup.setOnMenuItemClickListener(menuItem -> linkOptionsItemSelected(menuItem, publicShare));
popup.show(); popup.show();
} }
private void prepareOptionsMenu(Menu menu, OCShare publicShare) { private void prepareLinkOptionsMenu(Menu menu, OCShare publicShare) {
Resources res = requireContext().getResources(); Resources res = requireContext().getResources();
SharingMenuHelper.setupHideFileListingMenuItem(menu.findItem(R.id.action_hide_file_listing), // SharingMenuHelper.setupHideFileListingMenuItem(menu.findItem(R.id.action_hide_file_listing),
file.isFolder(), // file.isFolder(),
menu.findItem(R.id.action_allow_editing).isChecked(), // menu.findItem(R.id.action_allow_editing).isChecked(),
publicShare.getPermissions()); // publicShare.getPermissions());
SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download), SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download),
publicShare.isHideFileDownload(), publicShare.isHideFileDownload(),
@ -379,21 +445,61 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported());
if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) { // if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) {
menu.findItem(R.id.action_allow_editing).setChecked(true); // menu.findItem(R.id.action_allow_editing).setChecked(true);
} else { // } else {
menu.findItem(R.id.action_allow_editing).setChecked(false); // menu.findItem(R.id.action_allow_editing).setChecked(false);
// }
}
private boolean userOptionsItemSelected(Menu menu,
MenuItem item,
OCShare share) {
switch (item.getItemId()) {
case R.id.allow_creating:
case R.id.allow_deleting:
case R.id.allow_resharing: {
item.setChecked(!item.isChecked());
share.setPermissions(updatePermissionsToShare(share,
menu.findItem(R.id.allow_resharing).isChecked(),
menu.findItem(R.id.allow_editing).isChecked(),
menu.findItem(R.id.allow_creating).isChecked(),
menu.findItem(R.id.allow_deleting).isChecked()));
return true;
}
case R.id.action_unshare: {
unshareWith(share);
((ShareeListAdapter) sharesList.getAdapter()).remove(share);
return true;
}
case R.id.action_password: {
requestPasswordForShare(share);
return true;
}
case R.id.action_expiration_date: {
ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment
.newInstance(share, share.getExpirationDate());
dialog.show(fileActivity.getSupportFragmentManager(),
ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG);
return true;
}
case R.id.action_share_send_note:
NoteDialogFragment dialog = NoteDialogFragment.newInstance(share);
dialog.show(fileActivity.getSupportFragmentManager(), NoteDialogFragment.NOTE_FRAGMENT);
return true;
default:
return true;
} }
} }
public boolean optionsItemSelected(MenuItem item, OCShare publicShare) { public boolean linkOptionsItemSelected(MenuItem item, OCShare publicShare) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_allow_editing: // case R.id.action_allow_editing:
if (file.isSharedViaLink()) { // if (file.isSharedViaLink()) {
item.setChecked(!item.isChecked()); // item.setChecked(!item.isChecked());
fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked()); // fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked());
} // }
return true; // return true;
case R.id.action_hide_file_listing: { case R.id.action_hide_file_listing: {
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
fileOperationsHelper.setHideFileListingPermissionsToPublicShare(publicShare, item.isChecked()); fileOperationsHelper.setHideFileListingPermissionsToPublicShare(publicShare, item.isChecked());
@ -468,24 +574,20 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
setupView(); setupView();
} }
@Override private void unshareWith(OCShare share) {
public void unshareWith(OCShare share) {
fileOperationsHelper.unshareShare(file, share); fileOperationsHelper.unshareShare(file, share);
} }
@Override private int updatePermissionsToShare(OCShare share,
public int updatePermissionsToShare(OCShare share, boolean canReshare,
boolean canReshare, boolean canEdit,
boolean canEdit, boolean canEditCreate,
boolean canEditCreate, boolean canEditDelete) {
boolean canEditChange,
boolean canEditDelete) {
SharePermissionsBuilder spb = new SharePermissionsBuilder(); SharePermissionsBuilder spb = new SharePermissionsBuilder();
spb.setSharePermission(canReshare); spb.setSharePermission(canReshare);
if (file.isFolder()) { if (file.isFolder()) {
spb.setUpdatePermission(canEditChange) spb.setCreatePermission(canEditCreate)
.setCreatePermission(canEditCreate)
.setDeletePermission(canEditDelete); .setDeletePermission(canEditDelete);
} else { } else {
spb.setUpdatePermission(canEdit); spb.setUpdatePermission(canEdit);
@ -552,7 +654,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
} else { } else {
addPublicShare.setVisibility(View.GONE); addPublicShare.setVisibility(View.GONE);
((ShareeListAdapter) sharesList.getAdapter()).addShares(shares); ((ShareeListAdapter) sharesList.getAdapter()).addShares(shares);
} }
} }
@ -573,4 +674,53 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
public boolean shouldCallGeneratedCallback(String tag, Object callContext) { public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
return false; return false;
} }
private boolean isReshareForbidden(OCShare share) {
return ShareType.FEDERATED.equals(share.getShareType()) ||
(capabilities != null && capabilities.getFilesSharingResharing().isFalse());
}
private boolean isEditOptionsAvailable(OCShare share) {
return !ShareType.FEDERATED.equals(share.getShareType());
}
private boolean canEdit(OCShare share) {
return (share.getPermissions() &
(OCShare.CREATE_PERMISSION_FLAG | OCShare.UPDATE_PERMISSION_FLAG | OCShare.DELETE_PERMISSION_FLAG)) > 0;
}
private boolean canCreate(OCShare share) {
return (share.getPermissions() & OCShare.CREATE_PERMISSION_FLAG) > 0;
}
private boolean canUpdate(OCShare share) {
return (share.getPermissions() & OCShare.UPDATE_PERMISSION_FLAG) > 0;
}
private boolean canDelete(OCShare share) {
return (share.getPermissions() & OCShare.DELETE_PERMISSION_FLAG) > 0;
}
// private void allowEditClick(AppCompatCheckBox checkBox, @NonNull OCShare share) {
// if (!share.isFolder()) {
// share.setPermissions(updatePermissionsToShare(share,
// canReshare(share),
// checkBox.isChecked(),
// false,
// false,
// false));
// } else {
// share.setPermissions(updatePermissionsToShare(share,
// canReshare(share),
// checkBox.isChecked(),
// checkBox.isChecked(),
// checkBox.isChecked(),
// checkBox.isChecked()));
// }
// }
private boolean canReshare(OCShare share) {
return (share.getPermissions() & OCShare.SHARE_PERMISSION_FLAG) > 0;
}
} }

View file

@ -45,6 +45,11 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:textColor="@color/text_color"
android:ellipsize="end"
android:singleLine="true"
android:gravity="center_vertical"
android:textSize="@dimen/file_details_username_text_size"
android:text="@string/share_via_link_section_title" /> android:text="@string/share_via_link_section_title" />
<ImageView <ImageView

View file

@ -52,14 +52,6 @@
android:textColor="@color/text_color" android:textColor="@color/text_color"
android:textSize="@dimen/file_details_username_text_size" /> android:textSize="@dimen/file_details_username_text_size" />
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/allowEditing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="16sp"
android:text="@string/edit_permission_label" />
<ImageView <ImageView
android:id="@+id/editShareButton" android:id="@+id/editShareButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<!-- Nextcloud Android client application
Nesxtcloud Android client application
Copyright (C) 2018 Andy Scherzinger Copyright (C) 2018 Andy Scherzinger
@ -21,37 +20,33 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource"> tools:ignore="AppCompatResource">
<group android:checkableBehavior="single">
<item <item
android:id="@+id/action_allow_editing" android:id="@+id/link_share_read_only"
android:showAsAction="never" android:title="@string/link_share_read_only" />
android:title="@string/allow_editing" <item
android:checkable="true" android:id="@+id/link_share_allow_upload_and_editing"
android:textSize="16sp" android:title="@string/link_share_allow_upload_and_editing" />
app:showAsAction="never" /> <item
android:id="@+id/link_share_file_drop"
<item android:title="@string/link_share_file_drop" />
android:id="@+id/action_hide_file_listing" </group>
android:showAsAction="never"
android:title="@string/share_via_link_hide_file_listing_permission_label"
android:checkable="true"
app:showAsAction="never" />
<item <item
android:id="@+id/action_hide_file_download" android:id="@+id/action_hide_file_download"
android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_via_link_hide_download" android:title="@string/share_via_link_hide_download"
android:checkable="true"
app:showAsAction="never" />
<item
android:id="@+id/action_edit_label"
android:showAsAction="never"
android:title="@string/edit_label"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_password" android:id="@+id/action_password"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_via_link_menu_password_label" android:title="@string/share_via_link_menu_password_label"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/link_share_video_verification"
android:showAsAction="never"
android:title="@string/link_share_video_verification"
app:showAsAction="never" />
<item <item
android:id="@+id/action_share_expiration_date" android:id="@+id/action_share_expiration_date"
android:showAsAction="never" android:showAsAction="never"
@ -67,6 +62,11 @@
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_send_note" android:title="@string/share_send_note"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_edit_label"
android:showAsAction="never"
android:title="@string/edit_label"
app:showAsAction="never" />
<item <item
android:id="@+id/action_unshare" android:id="@+id/action_unshare"
android:showAsAction="never" android:showAsAction="never"

View file

@ -21,30 +21,30 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource"> tools:ignore="AppCompatResource">
<item
android:id="@+id/allow_editing"
android:checkable="true"
android:showAsAction="never"
android:title="@string/allow_editing"
app:showAsAction="never" />
<item <item
android:id="@+id/action_can_edit_create" android:id="@+id/allow_creating"
android:checkable="true" android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_privilege_can_edit_create" android:title="@string/allow_creating"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_can_edit_change" android:id="@+id/allow_deleting"
android:checkable="true" android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_privilege_can_edit_change" android:title="@string/allow_deleting"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_can_edit_delete" android:id="@+id/allow_resharing"
android:checkable="true" android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_privilege_can_edit_delete" android:title="@string/allow_resharing"
app:showAsAction="never" />
<item
android:id="@+id/action_can_reshare"
android:checkable="true"
android:showAsAction="never"
android:title="@string/share_privilege_can_share"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_hide_file_listing" android:id="@+id/action_hide_file_listing"

View file

@ -483,6 +483,7 @@
<string name="share_known_remote_clarification">%1$s ( at %2$s )</string> <string name="share_known_remote_clarification">%1$s ( at %2$s )</string>
<string name="share_privilege_unshare">Unshare</string> <string name="share_privilege_unshare">Unshare</string>
<string name="share_privilege_can_edit">can edit</string>
<string name="share_privilege_can_share">can share</string> <string name="share_privilege_can_share">can share</string>
<string name="share_privilege_can_edit_create">can create</string> <string name="share_privilege_can_edit_create">can create</string>
<string name="share_privilege_can_edit_change">can change</string> <string name="share_privilege_can_edit_change">can change</string>
@ -933,4 +934,12 @@
<string name="add_new_public_share">Add new public share link</string> <string name="add_new_public_share">Add new public share link</string>
<string name="edit_label">Change name</string> <string name="edit_label">Change name</string>
<string name="public_share_name">New name</string> <string name="public_share_name">New name</string>
<string name="share_link">Share link (%1$s)</string>
<string name="allow_creating">Allow creating</string>
<string name="allow_deleting">Allow deleting</string>
<string name="allow_resharing">Allow resharing</string>
<string name="link_share_read_only">Read only</string>
<string name="link_share_allow_upload_and_editing">Allow upload and editing</string>
<string name="link_share_file_drop">File drop (upload only)</string>
<string name="link_share_video_verification">Video verification</string>
</resources> </resources>