From 82d36f0cab47f10c6042df1c4c768748b4b84835 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Thu, 2 Jul 2020 13:48:13 +0200 Subject: [PATCH 01/20] wip Signed-off-by: tobiasKaminsky --- build.gradle | 30 +++--- .../ui/adapter/PublicShareInterface.java | 33 ------- .../ui/adapter/PublicShareListAdapter.java | 68 -------------- .../ui/adapter/PublicShareViewHolder.java | 2 +- .../android/ui/adapter/ShareeListAdapter.java | 93 +++++++++++++------ .../fragment/FileDetailSharingFragment.java | 41 ++++---- .../layout/file_details_sharing_fragment.xml | 9 +- src/main/res/layout/share_user_item.xml | 74 --------------- 8 files changed, 97 insertions(+), 253 deletions(-) delete mode 100644 src/main/java/com/owncloud/android/ui/adapter/PublicShareInterface.java delete mode 100644 src/main/java/com/owncloud/android/ui/adapter/PublicShareListAdapter.java delete mode 100644 src/main/res/layout/share_user_item.xml diff --git a/build.gradle b/build.gradle index e0d8df8cd6..848933d5f6 100644 --- a/build.gradle +++ b/build.gradle @@ -434,21 +434,21 @@ android.applicationVariants.all { variant -> } } -tasks.register("combinedTestReport", JacocoReport) { - - reports { - xml.enabled true - html.enabled true - csv.enabled false - } - - additionalSourceDirs.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) - sourceDirectories.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) - classDirectories.setFrom files(subprojects.sourceSets.main.output) - executionData.setFrom project.fileTree(dir: project.buildDir, includes: [ - 'jacoco/testGplayDebugUnitTest.exec', 'outputs/code-coverage/connected/flavors/GPLAY/*coverage.ec' - ]) -} +//tasks.register("combinedTestReport", JacocoReport) { +// +// reports { +// xml.enabled true +// html.enabled true +// csv.enabled false +// } +// +// additionalSourceDirs.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) +// sourceDirectories.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) +// classDirectories.setFrom files(subprojects.sourceSets.main.output) +// executionData.setFrom project.fileTree(dir: project.buildDir, includes: [ +// 'jacoco/testGplayDebugUnitTest.exec', 'outputs/code-coverage/connected/flavors/GPLAY/*coverage.ec' +// ]) +//} task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." diff --git a/src/main/java/com/owncloud/android/ui/adapter/PublicShareInterface.java b/src/main/java/com/owncloud/android/ui/adapter/PublicShareInterface.java deleted file mode 100644 index d34d5bb904..0000000000 --- a/src/main/java/com/owncloud/android/ui/adapter/PublicShareInterface.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * 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 . - */ - -package com.owncloud.android.ui.adapter; - -import android.widget.ImageView; - -import com.owncloud.android.lib.resources.shares.OCShare; - -public interface PublicShareInterface { - void copyLink(OCShare share); - - void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink); -} diff --git a/src/main/java/com/owncloud/android/ui/adapter/PublicShareListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/PublicShareListAdapter.java deleted file mode 100644 index abc11ecdea..0000000000 --- a/src/main/java/com/owncloud/android/ui/adapter/PublicShareListAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * 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 . - */ - -package com.owncloud.android.ui.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.ViewGroup; - -import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; -import com.owncloud.android.lib.resources.shares.OCShare; - -import java.util.List; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -public class PublicShareListAdapter extends RecyclerView.Adapter { - private Context context; - private List shares; - private PublicShareInterface listener; - - public PublicShareListAdapter(Context context, List shares, PublicShareInterface listener) { - this.context = context; - this.shares = shares; - this.listener = listener; - } - - @NonNull - @Override - public PublicShareViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - FileDetailsSharePublicLinkItemBinding binding = - FileDetailsSharePublicLinkItemBinding.inflate(LayoutInflater.from(context), parent, false); - - return new PublicShareViewHolder(binding, context); - } - - @Override - public void onBindViewHolder(@NonNull PublicShareViewHolder holder, int position) { - OCShare share = shares.get(position); - - holder.bind(share, listener); - } - - @Override - public int getItemCount() { - return shares.size(); - } -} diff --git a/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java index 98e274a45b..863628b294 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java +++ b/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java @@ -47,7 +47,7 @@ class PublicShareViewHolder extends RecyclerView.ViewHolder { this.context = context; } - public void bind(OCShare publicShare, PublicShareInterface listener) { + public void bind(OCShare publicShare, ShareeListAdapter.ShareeListAdapterListener listener) { if (!TextUtils.isEmpty(publicShare.getLabel())) { binding.publicShareLabel.setText(publicShare.getLabel()); } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index 3faaee5dbd..2d5b429b52 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -38,6 +38,7 @@ import android.widget.PopupMenu; import android.widget.TextView; import com.owncloud.android.R; +import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.resources.shares.OCShare; @@ -65,8 +66,8 @@ import butterknife.ButterKnife; /** * Adapter to show a user/group/email/remote in Sharing list in file details view. */ -public class ShareeListAdapter extends RecyclerView.Adapter - implements DisplayUtils.AvatarGenerationListener { +public class ShareeListAdapter extends RecyclerView.Adapter + implements DisplayUtils.AvatarGenerationListener { private ShareeListAdapterListener listener; private OCCapability capabilities; @@ -92,56 +93,82 @@ public class ShareeListAdapter extends RecyclerView.Adapter position) { - final OCShare share = shares.get(position); + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (shares == null || shares.size() <= position) { + return; + } + final OCShare share = shares.get(position); + + if (holder instanceof PublicShareViewHolder) { + PublicShareViewHolder publicShareViewHolder = (PublicShareViewHolder) holder; + publicShareViewHolder.bind(share, listener); + } else { + UserViewHolder userViewHolder = (UserViewHolder) holder; String name = share.getSharedWithDisplayName(); switch (share.getShareType()) { case GROUP: name = context.getString(R.string.share_group_clarification, name); - setImage(holder, name, R.drawable.ic_group); + setImage(userViewHolder, name, R.drawable.ic_group); break; case EMAIL: name = context.getString(R.string.share_email_clarification, name); - setImage(holder, name, R.drawable.ic_email); + setImage(userViewHolder, name, R.drawable.ic_email); break; case ROOM: name = context.getString(R.string.share_room_clarification, name); - setImage(holder, name, R.drawable.ic_chat_bubble); + setImage(userViewHolder, name, R.drawable.ic_chat_bubble); break; case CIRCLE: - holder.avatar.setImageResource(R.drawable.ic_circles); + userViewHolder.avatar.setImageResource(R.drawable.ic_circles); break; default: - setImage(holder, name, R.drawable.ic_user); + setImage(userViewHolder, name, R.drawable.ic_user); break; } - holder.name.setText(name); + userViewHolder.name.setText(name); if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) { - holder.allowEditing.setVisibility(View.VISIBLE); - holder.editShareButton.setVisibility(View.VISIBLE); + userViewHolder.allowEditing.setVisibility(View.VISIBLE); + userViewHolder.editShareButton.setVisibility(View.VISIBLE); - ThemeUtils.tintCheckbox(holder.allowEditing, accentColor); - holder.allowEditing.setChecked(canEdit(share)); - holder.allowEditing.setOnClickListener(v -> allowEditClick(holder.allowEditing, share)); + ThemeUtils.tintCheckbox(userViewHolder.allowEditing, accentColor); + userViewHolder.allowEditing.setChecked(canEdit(share)); + userViewHolder.allowEditing.setOnClickListener(v -> allowEditClick(userViewHolder.allowEditing, share)); // bind listener to edit privileges - holder.editShareButton.setOnClickListener(v -> onOverflowIconClicked(v, holder.allowEditing, share)); + userViewHolder.editShareButton.setOnClickListener(v -> onOverflowIconClicked(v, userViewHolder.allowEditing, share)); } else { - holder.allowEditing.setVisibility(View.GONE); - holder.editShareButton.setVisibility(View.GONE); + userViewHolder.allowEditing.setVisibility(View.GONE); + userViewHolder.editShareButton.setVisibility(View.GONE); } } } @@ -355,13 +382,17 @@ public class ShareeListAdapter extends RecyclerView.Adapter sharesToAdd) { + shares.addAll(sharesToAdd); } @Override @@ -429,5 +460,9 @@ public class ShareeListAdapter extends RecyclerView.Adapter shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(), user.toPlatformAccount().name); if (shares.size() > 0) { @@ -287,18 +282,18 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda String userId = accountManager.getUserData(user.toPlatformAccount(), com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID); - usersList.setVisibility(View.VISIBLE); - usersList.setAdapter(new ShareeListAdapter(fileActivity.getSupportFragmentManager(), - fileActivity, - shares, - user.toPlatformAccount(), - file, - this, - userId)); - usersList.setLayoutManager(new LinearLayoutManager(getContext())); - usersList.addItemDecoration(new SimpleListItemDividerDecoration(getContext())); + sharesList.setVisibility(View.VISIBLE); + sharesList.setAdapter(new ShareeListAdapter(fileActivity.getSupportFragmentManager(), + fileActivity, + shares, + user.toPlatformAccount(), + file, + this, + userId)); + sharesList.setLayoutManager(new LinearLayoutManager(getContext())); + sharesList.addItemDecoration(new SimpleListItemDividerDecoration(getContext())); } else { - usersList.setVisibility(View.GONE); + sharesList.setVisibility(View.GONE); } } @@ -536,7 +531,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda */ public void refreshPublicShareFromDB() { if (FileDetailSharingFragmentHelper.isPublicShareDisabled(capabilities) || !file.canReshare()) { - publicShareList.setVisibility(View.GONE); return; } @@ -547,7 +541,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda if (shares.isEmpty()) { addPublicShare.setVisibility(View.VISIBLE); - publicShareList.setVisibility(View.GONE); ImageView icon = requireView().findViewById(R.id.copy_internal_link_icon); icon.getBackground().setColorFilter(requireContext() .getResources() @@ -558,10 +551,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda requireView().findViewById(R.id.add_new_public_share_link).setOnClickListener(v -> createShareLink()); } else { addPublicShare.setVisibility(View.GONE); - publicShareList.setVisibility(View.VISIBLE); - publicShareList.setAdapter(new PublicShareListAdapter(getContext(), shares, this)); - publicShareList.setLayoutManager(new LinearLayoutManager(getContext())); - publicShareList.addItemDecoration(new SimpleListItemDividerDecoration(getContext())); + ((ShareeListAdapter) sharesList.getAdapter()).addShares(shares); + } } diff --git a/src/main/res/layout/file_details_sharing_fragment.xml b/src/main/res/layout/file_details_sharing_fragment.xml index 6778c9ecfd..4053296b07 100644 --- a/src/main/res/layout/file_details_sharing_fragment.xml +++ b/src/main/res/layout/file_details_sharing_fragment.xml @@ -98,17 +98,10 @@ - - - - - - - - - - - - - - - - - - From 20d24d8a6d320303056079fcf2c27f7fc1616eee Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 7 Jul 2020 08:15:53 +0200 Subject: [PATCH 02/20] wip Signed-off-by: tobiasKaminsky --- .../ui/adapter/PublicShareViewHolder.java | 6 +- .../android/ui/adapter/ShareeListAdapter.java | 368 ++---------------- .../ui/adapter/ShareeListAdapterListener.java | 35 ++ .../android/ui/adapter/UserViewHolder.java | 103 +++++ .../fragment/FileDetailSharingFragment.java | 220 +++++++++-- .../file_details_share_public_link_item.xml | 5 + .../layout/file_details_share_user_item.xml | 8 - .../fragment_file_detail_sharing_link.xml | 48 +-- .../res/menu/item_user_sharing_settings.xml | 24 +- src/main/res/values/strings.xml | 9 + 10 files changed, 407 insertions(+), 419 deletions(-) create mode 100644 src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java create mode 100644 src/main/java/com/owncloud/android/ui/adapter/UserViewHolder.java diff --git a/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java index 863628b294..24dd2f189a 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java +++ b/src/main/java/com/owncloud/android/ui/adapter/PublicShareViewHolder.java @@ -26,6 +26,7 @@ import android.content.Context; import android.text.TextUtils; import android.view.View; +import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.utils.ThemeUtils; @@ -47,9 +48,10 @@ class PublicShareViewHolder extends RecyclerView.ViewHolder { this.context = context; } - public void bind(OCShare publicShare, ShareeListAdapter.ShareeListAdapterListener listener) { + public void bind(OCShare publicShare, ShareeListAdapterListener listener) { 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); diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index 2d5b429b52..19fd9e17a4 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -25,43 +25,24 @@ package com.owncloud.android.ui.adapter; -import android.accounts.Account; import android.content.Context; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.PopupMenu; -import android.widget.TextView; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.databinding.FileDetailsShareUserItemBinding; import com.owncloud.android.lib.resources.shares.OCShare; 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.ThemeUtils; -import java.security.NoSuchAlgorithmException; +import java.util.Collections; import java.util.List; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.appcompat.widget.AppCompatCheckBox; -import androidx.fragment.app.FragmentManager; 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. @@ -70,27 +51,23 @@ public class ShareeListAdapter extends RecyclerView.Adapter shares; private float avatarRadiusDimension; - private OCFile file; private String userId; - public ShareeListAdapter(FragmentManager fragmentManager, Context context, List shares, Account account, - OCFile file, ShareeListAdapterListener listener, String userId) { + public ShareeListAdapter(Context context, + List shares, + ShareeListAdapterListener listener, + String userId) { this.context = context; - this.fragmentManager = fragmentManager; this.shares = shares; this.listener = listener; - this.file = file; 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); + + sort(this.shares); } @Override @@ -103,18 +80,16 @@ public class ShareeListAdapter extends RecyclerView.Adapter 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); + userViewHolder.bind(share, listener, userId, avatarRadiusDimension); } } @@ -191,208 +120,10 @@ public class ShareeListAdapter extends RecyclerView.Adapter 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 sharesToAdd) { shares.addAll(sharesToAdd); + sort(shares); + notifyDataSetChanged(); } @Override @@ -412,57 +143,18 @@ public class ShareeListAdapter extends RecyclerView.Adapter shares) { + Collections.sort(shares, (o1, o2) -> { + if (o1.getShareType() != o2.getShareType()) { + return o1.getShareType().compareTo(o2.getShareType()); + } - /** - * 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); + return o1.getSharedWithDisplayName().compareTo(o2.getSharedWithDisplayName()); + }); } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java new file mode 100644 index 0000000000..fbd0d9cb37 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java @@ -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 . + */ + +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); +} diff --git a/src/main/java/com/owncloud/android/ui/adapter/UserViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/UserViewHolder.java new file mode 100644 index 0000000000..c41e7deb41 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/adapter/UserViewHolder.java @@ -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 . + */ + +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); + } + } +} diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index e8bb660c93..389aa6d175 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -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.ShareType; 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.FileDisplayActivity; 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.dialog.ExpirationDatePickerDialogFragment; import com.owncloud.android.ui.dialog.NoteDialogFragment; @@ -84,7 +86,7 @@ import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; -public class FileDetailSharingFragment extends Fragment implements ShareeListAdapter.ShareeListAdapterListener, +public class FileDetailSharingFragment extends Fragment implements ShareeListAdapterListener, DisplayUtils.AvatarGenerationListener, Injectable { @@ -283,11 +285,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID); sharesList.setVisibility(View.VISIBLE); - sharesList.setAdapter(new ShareeListAdapter(fileActivity.getSupportFragmentManager(), - fileActivity, + sharesList.setAdapter(new ShareeListAdapter(fileActivity, shares, - user.toPlatformAccount(), - file, this, userId)); 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) { if (ThemeUtils.themingEnabled(requireContext())) { // 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); popup.inflate(R.menu.fragment_file_detail_sharing_link); - prepareOptionsMenu(popup.getMenu(), publicShare); - popup.setOnMenuItemClickListener(menuItem -> optionsItemSelected(menuItem, publicShare)); + prepareLinkOptionsMenu(popup.getMenu(), publicShare); + popup.setOnMenuItemClickListener(menuItem -> linkOptionsItemSelected(menuItem, publicShare)); popup.show(); } - private void prepareOptionsMenu(Menu menu, OCShare publicShare) { + private void prepareLinkOptionsMenu(Menu menu, OCShare publicShare) { Resources res = requireContext().getResources(); - SharingMenuHelper.setupHideFileListingMenuItem(menu.findItem(R.id.action_hide_file_listing), - file.isFolder(), - menu.findItem(R.id.action_allow_editing).isChecked(), - publicShare.getPermissions()); +// SharingMenuHelper.setupHideFileListingMenuItem(menu.findItem(R.id.action_hide_file_listing), +// file.isFolder(), +// menu.findItem(R.id.action_allow_editing).isChecked(), +// publicShare.getPermissions()); SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download), 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()); - if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) { - menu.findItem(R.id.action_allow_editing).setChecked(true); - } else { - menu.findItem(R.id.action_allow_editing).setChecked(false); +// if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) { +// menu.findItem(R.id.action_allow_editing).setChecked(true); +// } else { +// 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()) { - case R.id.action_allow_editing: - if (file.isSharedViaLink()) { - item.setChecked(!item.isChecked()); - fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked()); - } - return true; +// case R.id.action_allow_editing: +// if (file.isSharedViaLink()) { +// item.setChecked(!item.isChecked()); +// fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked()); +// } +// return true; case R.id.action_hide_file_listing: { item.setChecked(!item.isChecked()); fileOperationsHelper.setHideFileListingPermissionsToPublicShare(publicShare, item.isChecked()); @@ -468,24 +574,20 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda setupView(); } - @Override - public void unshareWith(OCShare share) { + private void unshareWith(OCShare share) { fileOperationsHelper.unshareShare(file, share); } - @Override - public int updatePermissionsToShare(OCShare share, - boolean canReshare, - boolean canEdit, - boolean canEditCreate, - boolean canEditChange, - boolean canEditDelete) { + private int updatePermissionsToShare(OCShare share, + boolean canReshare, + boolean canEdit, + boolean canEditCreate, + boolean canEditDelete) { SharePermissionsBuilder spb = new SharePermissionsBuilder(); spb.setSharePermission(canReshare); if (file.isFolder()) { - spb.setUpdatePermission(canEditChange) - .setCreatePermission(canEditCreate) + spb.setCreatePermission(canEditCreate) .setDeletePermission(canEditDelete); } else { spb.setUpdatePermission(canEdit); @@ -552,7 +654,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda } else { addPublicShare.setVisibility(View.GONE); ((ShareeListAdapter) sharesList.getAdapter()).addShares(shares); - } } @@ -573,4 +674,53 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda public boolean shouldCallGeneratedCallback(String tag, Object callContext) { 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; + } } diff --git a/src/main/res/layout/file_details_share_public_link_item.xml b/src/main/res/layout/file_details_share_public_link_item.xml index f473fc1244..3d578f563e 100644 --- a/src/main/res/layout/file_details_share_public_link_item.xml +++ b/src/main/res/layout/file_details_share_public_link_item.xml @@ -45,6 +45,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" 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" /> - - - - + . + */ + +package com.owncloud.android.ui.adapter; + +import android.content.Context; +import android.content.res.Resources; + +import com.owncloud.android.lib.resources.shares.OCShare; +import com.owncloud.android.lib.resources.shares.ShareType; + +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertTrue; + +public class ShareeListAdapterTest { + @Mock + private Context context; + + @Test + public void testSorting() { + MockitoAnnotations.initMocks(this); + Resources resources = Mockito.mock(Resources.class); + Mockito.when(context.getResources()).thenReturn(resources); + + List expectedSortOrder = new ArrayList<>(); + expectedSortOrder.add(new OCShare("/1") + .setShareType(ShareType.EMAIL) + .setSharedDate(1004)); + expectedSortOrder.add(new OCShare("/2") + .setShareType(ShareType.PUBLIC_LINK) + .setSharedDate(1003)); + expectedSortOrder.add(new OCShare("/3") + .setShareType(ShareType.PUBLIC_LINK) + .setSharedDate(1001)); + expectedSortOrder.add(new OCShare("/4") + .setShareType(ShareType.EMAIL) + .setSharedDate(1000)); + expectedSortOrder.add(new OCShare("/5") + .setShareType(ShareType.USER) + .setSharedDate(80)); + expectedSortOrder.add(new OCShare("/6") + .setShareType(ShareType.CIRCLE) + .setSharedDate(20)); + + List randomOrder = new ArrayList<>(expectedSortOrder); + Collections.shuffle(randomOrder); + + ShareeListAdapter sut = new ShareeListAdapter(context, randomOrder, null, null); + + sut.sortShares(); + + // compare + boolean compare = true; + for (int i = 0; i < expectedSortOrder.size() && compare; i++) { + compare = expectedSortOrder.get(i) == sut.getShares().get(i); + } + + if (!compare) { + System.out.println("Expected:"); + + for (OCShare item : expectedSortOrder) { + System.out.println(item.getPath() + " " + item.getShareType() + " " + item.getSharedDate()); + } + + System.out.println(); + System.out.println("Actual:"); + for (OCShare item : sut.getShares()) { + System.out.println(item.getPath() + " " + item.getShareType() + " " + item.getSharedDate()); + } + } + + assertTrue(compare); + } +} From a470bd1f56278c9cc09cd2d5ece7b0d395e45cde Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Wed, 8 Jul 2020 09:25:23 +0200 Subject: [PATCH 04/20] wip Signed-off-by: tobiasKaminsky --- .../datamodel/FileDataStorageManager.java | 10 +- .../owncloud/android/datamodel/OCFile.java | 12 -- .../com/owncloud/android/db/ProviderMeta.java | 5 +- .../CreateShareViaLinkOperation.java | 1 - .../operations/RefreshFolderOperation.java | 1 - .../SynchronizeFolderOperation.java | 1 - .../android/operations/UnshareOperation.java | 1 - .../UpdateShareViaLinkOperation.java | 6 + .../providers/FileContentProvider.java | 26 ++- .../android/services/OperationsService.java | 6 + .../android/ui/activity/FileActivity.java | 8 +- .../android/ui/activity/ShareActivity.java | 2 +- .../ui/adapter/InternalShareViewHolder.java | 74 +++++++ .../ui/adapter/NewLinkShareViewHolder.java | 47 +++++ .../android/ui/adapter/ShareeListAdapter.java | 43 ++++- .../ui/adapter/ShareeListAdapterListener.java | 4 + .../ui/fragment/FileDetailFragment.java | 1 + .../fragment/FileDetailSharingFragment.java | 170 +++++++++-------- .../ui/helpers/FileOperationsHelper.java | 10 + ...file_details_share_internal_share_link.xml | 67 +++++++ ...details_share_public_link_add_new_item.xml | 3 +- .../layout/file_details_share_share_item.xml | 46 ++--- .../layout/file_details_sharing_fragment.xml | 180 ++++++------------ ...ragment_file_detail_sharing_email_link.xml | 68 +++++++ ...gment_file_detail_sharing_public_link.xml} | 11 +- src/main/res/values/dims.xml | 2 +- 26 files changed, 536 insertions(+), 269 deletions(-) create mode 100644 src/main/java/com/owncloud/android/ui/adapter/InternalShareViewHolder.java create mode 100644 src/main/java/com/owncloud/android/ui/adapter/NewLinkShareViewHolder.java create mode 100644 src/main/res/layout/file_details_share_internal_share_link.xml create mode 100644 src/main/res/menu/fragment_file_detail_sharing_email_link.xml rename src/main/res/menu/{fragment_file_detail_sharing_link.xml => fragment_file_detail_sharing_public_link.xml} (90%) diff --git a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 5d73e2ebb2..2e932fcdf7 100644 --- a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -230,7 +230,6 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, ocFile.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, ocFile.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, ocFile.isSharedWithSharee() ? 1 : 0); - cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, ocFile.getPublicLink()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, ocFile.getPermissions()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, ocFile.getRemoteId()); cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, ocFile.isUpdateThumbnailNeeded()); @@ -485,7 +484,6 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, folder.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0); - cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId()); cv.put(ProviderTableMeta.FILE_FAVORITE, folder.isFavorite()); @@ -520,7 +518,6 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0); - cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId()); cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded()); @@ -1006,7 +1003,6 @@ public class FileDataStorageManager { ocFile.setEtagOnServer(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_ETAG_ON_SERVER))); ocFile.setSharedViaLink(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1); ocFile.setSharedWithSharee(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_SHARED_WITH_SHAREE)) == 1); - ocFile.setPublicLink(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK))); ocFile.setPermissions(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS))); ocFile.setRemoteId(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID))); ocFile.setUpdateThumbnailNeeded(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1); @@ -1264,6 +1260,7 @@ public class FileDataStorageManager { contentValues.put(ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD, share.isHideFileDownload()); contentValues.put(ProviderTableMeta.OCSHARES_SHARE_LINK, share.getShareLink()); contentValues.put(ProviderTableMeta.OCSHARES_SHARE_LABEL, share.getLabel()); + contentValues.put(ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION, share.isSendPasswordByTalk()); return contentValues; } @@ -1288,6 +1285,7 @@ public class FileDataStorageManager { share.setHideFileDownload(getInt(cursor, ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD) == 1); share.setShareLink(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_LINK)); share.setLabel(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_LABEL)); + share.setSendPasswordByTalk(getInt(cursor, ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION) == 1); return share; } @@ -1296,7 +1294,6 @@ public class FileDataStorageManager { ContentValues cv = new ContentValues(); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE); - cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, ""); String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; String[] whereArgs = new String[]{account.name}; @@ -1316,7 +1313,6 @@ public class FileDataStorageManager { ContentValues contentValues = new ContentValues(); contentValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE); contentValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE); - contentValues.put(ProviderTableMeta.FILE_PUBLIC_LINK, ""); String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PARENT + " = ?"; String[] whereArgs = new String[]{account.name, String.valueOf(folder.getFileId())}; @@ -1336,7 +1332,6 @@ public class FileDataStorageManager { ContentValues contentValues = new ContentValues(); contentValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE); contentValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE); - contentValues.put(ProviderTableMeta.FILE_PUBLIC_LINK, ""); String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + " = ?"; String[] whereArgs = new String[]{account.name, filePath}; @@ -1447,7 +1442,6 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0); - cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId()); cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite()); diff --git a/src/main/java/com/owncloud/android/datamodel/OCFile.java b/src/main/java/com/owncloud/android/datamodel/OCFile.java index 2bea653ddb..bba165d9d3 100644 --- a/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -75,7 +75,6 @@ public class OCFile implements Parcelable, Comparable, ServerFileInterfa private String etag; private String etagOnServer; private boolean sharedViaLink; - private String publicLink; private String permissions; private String remoteId; // The fileid namespaced by the instance fileId, globally unique private boolean updateThumbnailNeeded; @@ -150,7 +149,6 @@ public class OCFile implements Parcelable, Comparable, ServerFileInterfa etag = source.readString(); etagOnServer = source.readString(); sharedViaLink = source.readInt() == 1; - publicLink = source.readString(); permissions = source.readString(); remoteId = source.readString(); updateThumbnailNeeded = source.readInt() == 1; @@ -184,7 +182,6 @@ public class OCFile implements Parcelable, Comparable, ServerFileInterfa dest.writeString(etag); dest.writeString(etagOnServer); dest.writeInt(sharedViaLink ? 1 : 0); - dest.writeString(publicLink); dest.writeString(permissions); dest.writeString(remoteId); dest.writeInt(updateThumbnailNeeded ? 1 : 0); @@ -450,7 +447,6 @@ public class OCFile implements Parcelable, Comparable, ServerFileInterfa etag = null; etagOnServer = null; sharedViaLink = false; - publicLink = null; permissions = null; remoteId = null; updateThumbnailNeeded = false; @@ -646,10 +642,6 @@ public class OCFile implements Parcelable, Comparable, ServerFileInterfa return this.sharedViaLink; } - public String getPublicLink() { - return this.publicLink; - } - public String getPermissions() { return this.permissions; } @@ -758,10 +750,6 @@ public class OCFile implements Parcelable, Comparable, ServerFileInterfa this.sharedViaLink = sharedViaLink; } - public void setPublicLink(String publicLink) { - this.publicLink = publicLink; - } - public void setPermissions(String permissions) { this.permissions = permissions; } diff --git a/src/main/java/com/owncloud/android/db/ProviderMeta.java b/src/main/java/com/owncloud/android/db/ProviderMeta.java index 591157abb9..7e0fff828a 100644 --- a/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -35,7 +35,7 @@ import java.util.List; */ public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 59; + public static final int DB_VERSION = 60; private ProviderMeta() { // No instance @@ -102,7 +102,6 @@ public class ProviderMeta { public static final String FILE_ETAG_ON_SERVER = "etag_on_server"; public static final String FILE_SHARED_VIA_LINK = "share_by_link"; public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users"; - public static final String FILE_PUBLIC_LINK = "public_link"; public static final String FILE_PERMISSIONS = "permissions"; public static final String FILE_REMOTE_ID = "remote_id"; public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail"; @@ -137,7 +136,6 @@ public class ProviderMeta { FILE_ETAG_ON_SERVER, FILE_SHARED_VIA_LINK, FILE_SHARED_WITH_SHAREE, - FILE_PUBLIC_LINK, FILE_PERMISSIONS, FILE_REMOTE_ID, FILE_UPDATE_THUMBNAIL, @@ -173,6 +171,7 @@ public class ProviderMeta { public static final String OCSHARES_HIDE_DOWNLOAD = "hide_download"; public static final String OCSHARES_SHARE_LINK = "share_link"; public static final String OCSHARES_SHARE_LABEL = "share_label"; + public static final String OCSHARES_VIDEO_VERIFICATION = "video_verification"; public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE + " collate nocase asc"; diff --git a/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java b/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java index adf8370630..f8397c7b15 100644 --- a/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java +++ b/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java @@ -88,7 +88,6 @@ public class CreateShareViaLinkOperation extends SyncOperation { // Update OCFile with data from share: ShareByLink and publicLink OCFile file = getStorageManager().getFileByEncryptedRemotePath(path); if (file != null) { - file.setPublicLink(share.getShareLink()); file.setSharedViaLink(true); getStorageManager().saveFile(file); } diff --git a/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 89d32aac5b..0b6264f252 100644 --- a/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -576,7 +576,6 @@ public class RefreshFolderOperation extends RemoteOperation { Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server"); } - updatedFile.setPublicLink(localFile.getPublicLink()); updatedFile.setSharedViaLink(localFile.isSharedViaLink()); updatedFile.setSharedWithSharee(localFile.isSharedWithSharee()); } else { diff --git a/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index b8cd2377c0..b05c955e72 100644 --- a/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -360,7 +360,6 @@ public class SynchronizeFolderOperation extends SyncOperation { updatedFile.setUpdateThumbnailNeeded(true); Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server"); } - updatedFile.setPublicLink(localFile.getPublicLink()); updatedFile.setSharedViaLink(localFile.isSharedViaLink()); updatedFile.setSharedWithSharee(localFile.isSharedWithSharee()); updatedFile.setEtagInConflict(localFile.getEtagInConflict()); diff --git a/src/main/java/com/owncloud/android/operations/UnshareOperation.java b/src/main/java/com/owncloud/android/operations/UnshareOperation.java index 2d066dced5..3988c920c2 100644 --- a/src/main/java/com/owncloud/android/operations/UnshareOperation.java +++ b/src/main/java/com/owncloud/android/operations/UnshareOperation.java @@ -68,7 +68,6 @@ public class UnshareOperation extends SyncOperation { if (ShareType.PUBLIC_LINK.equals(share.getShareType())) { file.setSharedViaLink(false); - file.setPublicLink(""); } else if (ShareType.USER.equals(share.getShareType()) || ShareType.GROUP.equals(share.getShareType()) || ShareType.FEDERATED.equals(share.getShareType())) { // Check if it is the last share diff --git a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java index 9022952382..bc83a77f47 100644 --- a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java +++ b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java @@ -39,6 +39,7 @@ public class UpdateShareViaLinkOperation extends SyncOperation { */ private boolean publicUpload; private Boolean hideFileDownload; + private Boolean videoVerification; private long expirationDateInMillis; private long shareId; private String label; @@ -56,6 +57,7 @@ public class UpdateShareViaLinkOperation extends SyncOperation { updateOp.setPassword(password); updateOp.setExpirationDate(expirationDateInMillis); updateOp.setHideFileDownload(hideFileDownload); + updateOp.setVideoVerification(videoVerification); updateOp.setLabel(label); if (publicShare.isFolder()) { @@ -102,4 +104,8 @@ public class UpdateShareViaLinkOperation extends SyncOperation { public void setLabel(String label) { this.label = label; } + + public void setVideoVerification(Boolean enabled) { + this.videoVerification = enabled; + } } diff --git a/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/src/main/java/com/owncloud/android/providers/FileContentProvider.java index e8f132d7e5..ab4b7e0fb3 100644 --- a/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -708,7 +708,6 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.FILE_ETAG + TEXT + ProviderTableMeta.FILE_ETAG_ON_SERVER + TEXT + ProviderTableMeta.FILE_SHARED_VIA_LINK + INTEGER - + ProviderTableMeta.FILE_PUBLIC_LINK + TEXT + ProviderTableMeta.FILE_PERMISSIONS + " TEXT null," + ProviderTableMeta.FILE_REMOTE_ID + " TEXT null," + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + INTEGER //boolean @@ -749,7 +748,8 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.OCSHARES_NOTE + TEXT + ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD + INTEGER + ProviderTableMeta.OCSHARES_SHARE_LINK + TEXT - + ProviderTableMeta.OCSHARES_SHARE_LABEL + " TEXT );"); + + ProviderTableMeta.OCSHARES_SHARE_LABEL + TEXT + + ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION + " INTEGER );"); } private void createCapabilitiesTable(SQLiteDatabase db) { @@ -1148,10 +1148,6 @@ public class FileContentProvider extends ContentProvider { ADD_COLUMN + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER " + " DEFAULT 0"); - db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + - ADD_COLUMN + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " + - " DEFAULT NULL"); - // Create table OCShares createOCSharesTable(db); @@ -2271,6 +2267,24 @@ public class FileContentProvider extends ContentProvider { if (!upgraded) { Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); } + + if (oldVersion < 60 && newVersion >= 60) { + Log_OC.i(SQL, "Entering in the #60 add video verification to share table"); + db.beginTransaction(); + try { + db.execSQL(ALTER_TABLE + ProviderTableMeta.OCSHARES_TABLE_NAME + + ADD_COLUMN + ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION + " INTEGER "); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + if (!upgraded) { + Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); + } } } } diff --git a/src/main/java/com/owncloud/android/services/OperationsService.java b/src/main/java/com/owncloud/android/services/OperationsService.java index c615f9c22b..917f238a4b 100644 --- a/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/src/main/java/com/owncloud/android/services/OperationsService.java @@ -106,6 +106,7 @@ public class OperationsService extends Service { public static final String EXTRA_SHARE_PUBLIC_UPLOAD = "SHARE_PUBLIC_UPLOAD"; public static final String EXTRA_SHARE_PUBLIC_LABEL = "SHARE_PUBLIC_LABEL"; public static final String EXTRA_SHARE_HIDE_FILE_DOWNLOAD = "HIDE_FILE_DOWNLOAD"; + public static final String EXTRA_SHARE_VIDEO_VERIFICATION = "VIDEO_VERIFICATION"; public static final String EXTRA_SHARE_ID = "SHARE_ID"; public static final String EXTRA_SHARE_NOTE = "SHARE_NOTE"; public static final String EXTRA_IN_BACKGROUND = "IN_BACKGROUND"; @@ -553,6 +554,11 @@ public class OperationsService extends Service { false); updateLinkOperation.setHideFileDownload(hideFileDownload); + boolean videoVerificationEnabled = + operationIntent.getBooleanExtra(EXTRA_SHARE_VIDEO_VERIFICATION, false); + + updateLinkOperation.setVideoVerification(videoVerificationEnabled); + if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_UPLOAD)) { updateLinkOperation.setPublicUpload(true); } diff --git a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 2e6d5330c9..aed455a138 100644 --- a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -746,7 +746,7 @@ public abstract class FileActivity extends DrawerActivity if (result.isSuccess()) { if (sharingFragment != null) { - sharingFragment.refreshPublicShareFromDB(); + sharingFragment.refreshSharesFromDB(); sharingFragment.onUpdateShareInformation(result, getFile()); } } else { @@ -761,7 +761,7 @@ public abstract class FileActivity extends DrawerActivity if (result.isSuccess()) { updateFileFromDB(); if (sharingFragment != null) { - sharingFragment.refreshPublicShareFromDB(); + sharingFragment.refreshSharesFromDB(); sharingFragment.onUpdateShareInformation(result, getFile()); } } else if (sharingFragment != null && sharingFragment.getView() != null) { @@ -807,7 +807,7 @@ public abstract class FileActivity extends DrawerActivity copyAndShareFileLink(this, file, link); if (sharingFragment != null) { - sharingFragment.refreshPublicShareFromDB(); + sharingFragment.refreshSharesFromDB(); sharingFragment.onUpdateShareInformation(result, getFile()); } } else { @@ -828,7 +828,7 @@ public abstract class FileActivity extends DrawerActivity } else { if (sharingFragment != null) { - sharingFragment.refreshPublicShareFromDB(); + sharingFragment.refreshSharesFromDB(); } Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), ErrorMessageAdapter.getErrorCauseMessage(result, diff --git a/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java b/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java index 7e506f58c8..9a68b0c1d5 100644 --- a/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java @@ -146,7 +146,7 @@ public class ShareActivity extends FileActivity { && shareFileFragment.isAdded()) { // only if added to the view hierarchy!! shareFileFragment.refreshCapabilitiesFromDB(); //shareFileFragment.refrefreshUsersOrGroupsListFromDB(); - shareFileFragment.refreshPublicShareFromDB(); + shareFileFragment.refreshSharesFromDB(); } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/InternalShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/InternalShareViewHolder.java new file mode 100644 index 0000000000..81b77a9d9e --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/adapter/InternalShareViewHolder.java @@ -0,0 +1,74 @@ +/* + * + * 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 . + */ + +package com.owncloud.android.ui.adapter; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.view.View; + +import com.owncloud.android.R; +import com.owncloud.android.databinding.FileDetailsShareInternalShareLinkBinding; +import com.owncloud.android.lib.resources.shares.OCShare; + +import androidx.annotation.NonNull; +import androidx.core.content.res.ResourcesCompat; +import androidx.recyclerview.widget.RecyclerView; + +class InternalShareViewHolder extends RecyclerView.ViewHolder { + private FileDetailsShareInternalShareLinkBinding binding; + private Context context; + + public InternalShareViewHolder(@NonNull View itemView) { + super(itemView); + } + + public InternalShareViewHolder(FileDetailsShareInternalShareLinkBinding binding, Context context) { + this(binding.getRoot()); + this.binding = binding; + this.context = context; + } + + public void bind(OCShare share, ShareeListAdapterListener listener) { + binding.copyInternalLinkIcon + .getBackground() + .setColorFilter(ResourcesCompat.getColor(context.getResources(), + R.color.grey_db, + null), + PorterDuff.Mode.SRC_IN); + binding.copyInternalLinkIcon + .getDrawable() + .mutate() + .setColorFilter(ResourcesCompat.getColor(context.getResources(), + R.color.black, + null), + PorterDuff.Mode.SRC_IN); + + if (share.isFolder()) { + binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_folder_text)); + } else { + binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_file_text)); + } + + binding.copyInternalContainer.setOnClickListener(l -> listener.copyInternalLink()); + } +} diff --git a/src/main/java/com/owncloud/android/ui/adapter/NewLinkShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/NewLinkShareViewHolder.java new file mode 100644 index 0000000000..0da1388fdb --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/adapter/NewLinkShareViewHolder.java @@ -0,0 +1,47 @@ +/* + * + * 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 . + */ + +package com.owncloud.android.ui.adapter; + +import android.view.View; + +import com.owncloud.android.databinding.FileDetailsSharePublicLinkAddNewItemBinding; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +class NewLinkShareViewHolder extends RecyclerView.ViewHolder { + private FileDetailsSharePublicLinkAddNewItemBinding binding; + + public NewLinkShareViewHolder(@NonNull View itemView) { + super(itemView); + } + + public NewLinkShareViewHolder(FileDetailsSharePublicLinkAddNewItemBinding binding) { + this(binding.getRoot()); + this.binding = binding; + } + + public void bind(ShareeListAdapterListener listener) { + binding.addNewPublicShareLink.setOnClickListener(v -> listener.createPublicShareLink()); + } +} diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index c83d476c46..2680b98451 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -32,7 +32,9 @@ import android.view.ViewGroup; import android.widget.ImageView; import com.owncloud.android.R; +import com.owncloud.android.databinding.FileDetailsShareInternalShareLinkBinding; import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding; +import com.owncloud.android.databinding.FileDetailsSharePublicLinkAddNewItemBinding; import com.owncloud.android.databinding.FileDetailsShareShareItemBinding; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; @@ -82,10 +84,21 @@ public class ShareeListAdapter extends RecyclerView.Adapter getShares() { + public List getShares() { return shares; } + + public void removeNewPublicShare() { + for (OCShare share : shares) { + if (share.getShareType() == ShareType.NEW_PUBLIC_LINK) { + shares.remove(share); + break; + } + } + } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java index fbd0d9cb37..91d17af1ca 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java @@ -32,4 +32,8 @@ public interface ShareeListAdapterListener { void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink); void showUserOverflowMenu(OCShare share, ImageView overflowMenu); + + void copyInternalLink(); + + void createPublicShareLink(); } diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 56219f41e9..02263d5372 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -374,6 +374,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener, super.onAttach(context); if (context instanceof ToolbarActivity) { toolbarActivity = (ToolbarActivity) context; + toolbarActivity.hideSortListGroup(); } } diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 33fdd693ae..64b081f65d 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -27,7 +27,6 @@ import android.accounts.AccountManager; import android.app.SearchManager; import android.content.Context; import android.content.res.Resources; -import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.InputType; @@ -69,6 +68,7 @@ import com.owncloud.android.utils.ClipboardUtil; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ThemeUtils; +import java.util.ArrayList; import java.util.List; import javax.inject.Inject; @@ -78,7 +78,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.PopupMenu; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; -import butterknife.OnClick; public class FileDetailSharingFragment extends Fragment implements ShareeListAdapterListener, DisplayUtils.AvatarGenerationListener, @@ -144,7 +143,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda super.onActivityCreated(savedInstanceState); refreshCapabilitiesFromDB(); - refreshPublicShareFromDB(); + refreshSharesFromDB(); } @Override @@ -155,20 +154,19 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda fileOperationsHelper = fileActivity.getFileOperationsHelper(); fileDataStorageManager = fileActivity.getStorageManager(); + AccountManager accountManager = AccountManager.get(getContext()); + String userId = accountManager.getUserData(user.toPlatformAccount(), + com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID); + + binding.sharesList.setAdapter(new ShareeListAdapter(fileActivity, + new ArrayList<>(), + this, + userId)); + binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext())); + binding.sharesList.addItemDecoration(new SimpleListItemDividerDecoration(getContext())); + setupView(); - // todo extract - binding.copyInternalLinkIcon.getBackground().setColorFilter(getResources().getColor(R.color.grey_db), - PorterDuff.Mode.SRC_IN); - binding.copyInternalLinkIcon.getDrawable().mutate().setColorFilter(getResources().getColor(R.color.black), - PorterDuff.Mode.SRC_IN); - - if (file.isFolder()) { - binding.shareInternalLinkText.setText(getString(R.string.share_internal_link_to_folder_text)); - } else { - binding.shareInternalLinkText.setText(getString(R.string.share_internal_link_to_file_text)); - } - return view; } @@ -196,7 +194,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda ThemeUtils.themeSearchView(binding.searchView, requireContext()); if (file.canReshare()) { - setShareWithUserInfo(); + refreshSharesFromDB(); } else { binding.searchView.setQueryHint(getResources().getString(R.string.reshare_not_allowed)); binding.searchView.setInputType(InputType.TYPE_NULL); @@ -243,30 +241,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda } } - private void setShareWithUserInfo() { - // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed - // to show share with users/groups info - // TODO combine this with refreshPublicShareFromDB() - List shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(), - user.toPlatformAccount().name); - if (shares.size() > 0) { - AccountManager accountManager = AccountManager.get(getContext()); - String userId = accountManager.getUserData(user.toPlatformAccount(), - com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID); - - binding.sharesList.setVisibility(View.VISIBLE); - binding.sharesList.setAdapter(new ShareeListAdapter(fileActivity, - shares, - this, - userId)); - binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext())); - binding.sharesList.addItemDecoration(new SimpleListItemDividerDecoration(getContext())); - } else { - binding.sharesList.setVisibility(View.GONE); - } - } - - @OnClick(R.id.copy_internal_container) + @Override public void copyInternalLink() { OwnCloudAccount account = accountManager.getCurrentOwnCloudAccount(); @@ -282,7 +257,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda return account.getBaseUri() + "/index.php/f/" + file.getLocalId(); } - private void createShareLink() { + @Override + public void createPublicShareLink() { if (capabilities != null && (capabilities.getFilesSharingPublicPasswordEnforced().isTrue() || capabilities.getFilesSharingPublicAskForOptionalPassword().isTrue())) { // password enforced by server, request to the user before trying to create @@ -295,22 +271,22 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda } } - private void showSendLinkTo() { + private void showSendLinkTo(OCShare publicShare) { if (file.isSharedViaLink()) { - if (TextUtils.isEmpty(file.getPublicLink())) { + if (TextUtils.isEmpty(publicShare.getShareLink())) { fileOperationsHelper.getFileWithLink(file); } else { - FileDisplayActivity.showShareLinkDialog(fileActivity, file, file.getPublicLink()); + FileDisplayActivity.showShareLinkDialog(fileActivity, file, publicShare.getShareLink()); } } } public void copyLink(OCShare share) { if (file.isSharedViaLink()) { - if (TextUtils.isEmpty(file.getPublicLink())) { + if (TextUtils.isEmpty(share.getShareLink())) { fileOperationsHelper.getFileWithLink(file); } else { - ClipboardUtil.copyToClipboard(getActivity(), file.getPublicLink()); + ClipboardUtil.copyToClipboard(getActivity(), share.getShareLink()); } } } @@ -389,19 +365,31 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda } PopupMenu popup = new PopupMenu(requireContext(), overflowMenuShareLink); - popup.inflate(R.menu.fragment_file_detail_sharing_link); + if (ShareType.EMAIL == publicShare.getShareType()) { + popup.inflate(R.menu.fragment_file_detail_sharing_email_link); + } else { + popup.inflate(R.menu.fragment_file_detail_sharing_public_link); + } prepareLinkOptionsMenu(popup.getMenu(), publicShare); popup.setOnMenuItemClickListener(menuItem -> linkOptionsItemSelected(menuItem, publicShare)); popup.show(); } private void prepareLinkOptionsMenu(Menu menu, OCShare publicShare) { - Resources res = requireContext().getResources(); -// SharingMenuHelper.setupHideFileListingMenuItem(menu.findItem(R.id.action_hide_file_listing), -// file.isFolder(), -// menu.findItem(R.id.action_allow_editing).isChecked(), -// publicShare.getPermissions()); + if (publicShare.isFolder()) { + menu.setGroupVisible(R.id.folder_permission, true); + menu.findItem(R.id.allow_editing).setVisible(false); + // read only / allow upload and editing / file drop + MenuItem readOnly = menu.findItem(R.id.link_share_read_only); + MenuItem uploadAndEditing = menu.findItem(R.id.link_share_allow_upload_and_editing); + MenuItem fileDrop = menu.findItem(R.id.link_share_file_drop); + } else { + menu.setGroupVisible(R.id.folder_permission, false); + menu.findItem(R.id.allow_editing).setVisible(true); + } + + Resources res = requireContext().getResources(); SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download), publicShare.isHideFileDownload(), capabilities); @@ -415,11 +403,18 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); -// if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) { -// menu.findItem(R.id.action_allow_editing).setChecked(true); -// } else { -// menu.findItem(R.id.action_allow_editing).setChecked(false); -// } + MenuItem videoVerification = menu.findItem(R.id.link_share_video_verification); + if (videoVerification != null) { + videoVerification.setChecked(publicShare.isSendPasswordByTalk()); + + +// -When enabling it: +// -If it is for a mail share, you must always set a new password (which is also different from the previous one) +// -If it is for a link share, you only need to set a new password if the share didn't have one yet (but you can repeat the previous password) +// -When disabling it: +// -If it is for a mail share, you must always set a new password (which is also different from the previous one) +// -If it is for a link share, you do not need to set a new password + } } private boolean userOptionsItemSelected(Menu menu, @@ -498,10 +493,10 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda return true; } case R.id.action_share_send_link: { - if (file.isSharedViaLink() && !TextUtils.isEmpty(file.getPublicLink())) { - FileDisplayActivity.showShareLinkDialog(fileActivity, file, file.getPublicLink()); + if (file.isSharedViaLink() && !TextUtils.isEmpty(publicShare.getShareLink())) { + FileDisplayActivity.showShareLinkDialog(fileActivity, file, publicShare.getShareLink()); } else { - showSendLinkTo(); + showSendLinkTo(publicShare); } return true; } @@ -510,11 +505,15 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda noteDialog.show(fileActivity.getSupportFragmentManager(), NoteDialogFragment.NOTE_FRAGMENT); return true; case R.id.action_add_another_public_share_link: - createShareLink(); + createPublicShareLink(); return true; case R.id.action_unshare: fileOperationsHelper.unshareShare(file, publicShare); return true; + case R.id.link_share_video_verification: + item.setChecked(!item.isChecked()); + fileOperationsHelper.setVideoVerificationToPublicShare(publicShare, item.isChecked()); + return true; default: return super.onOptionsItemSelected(item); } @@ -598,33 +597,48 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda /** * Get public link from the DB to fill in the "Share link" section in the UI. - * + *

* Takes into account server capabilities before reading database. */ - public void refreshPublicShareFromDB() { + public void refreshSharesFromDB() { + // TODO check if this is not called too often + ShareeListAdapter adapter = ((ShareeListAdapter) binding.sharesList.getAdapter()); + adapter.getShares().clear(); + + // to show share with users/groups info + List shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(), + user.toPlatformAccount().name); + + adapter.addShares(shares); + if (FileDetailSharingFragmentHelper.isPublicShareDisabled(capabilities) || !file.canReshare()) { return; } // Get public share - List shares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), - ShareType.PUBLIC_LINK, - ""); + List publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), + ShareType.PUBLIC_LINK, + ""); - if (shares.isEmpty()) { - binding.fileDetailsSharePublicLinkAddNewItemInclude.addPublicShare.setVisibility(View.VISIBLE); - ImageView icon = requireView().findViewById(R.id.copy_internal_link_icon); - icon.getBackground().setColorFilter(requireContext() - .getResources() - .getColor(R.color.primary_button_background_color), - PorterDuff.Mode.SRC_IN); - icon.getDrawable().mutate().setColorFilter(requireContext().getResources().getColor(R.color.black), - PorterDuff.Mode.SRC_IN); - requireView().findViewById(R.id.add_new_public_share_link).setOnClickListener(v -> createShareLink()); + + if (publicShares.isEmpty() && containsNoNewPublicShare(adapter.getShares())) { + publicShares.add(new OCShare().setShareType(ShareType.NEW_PUBLIC_LINK)); } else { - binding.fileDetailsSharePublicLinkAddNewItemInclude.addPublicShare.setVisibility(View.GONE); - ((ShareeListAdapter) binding.sharesList.getAdapter()).addShares(shares); + adapter.removeNewPublicShare(); } + + adapter.addShares(publicShares); + } + + + private boolean containsNoNewPublicShare(List shares) { + for (OCShare share : shares) { + if (share.getShareType() == ShareType.NEW_PUBLIC_LINK) { + return false; + } + } + + return true; } @Override diff --git a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index c61e7e3fe1..8dec08a8d8 100755 --- a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -733,6 +733,16 @@ public class FileOperationsHelper { queueShareIntent(updateShareIntent); } + public void setVideoVerificationToPublicShare(OCShare share, boolean videoVerificationEnabled) { + Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); + updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE); + updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId()); + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_VIDEO_VERIFICATION, videoVerificationEnabled); + + queueShareIntent(updateShareIntent); + } + public void updateNoteToShare(OCShare share, String note) { Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_NOTE); diff --git a/src/main/res/layout/file_details_share_internal_share_link.xml b/src/main/res/layout/file_details_share_internal_share_link.xml new file mode 100644 index 0000000000..6dfe2501f4 --- /dev/null +++ b/src/main/res/layout/file_details_share_internal_share_link.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + diff --git a/src/main/res/layout/file_details_share_public_link_add_new_item.xml b/src/main/res/layout/file_details_share_public_link_add_new_item.xml index c4863ae2a2..dd1ed2c92d 100644 --- a/src/main/res/layout/file_details_share_public_link_add_new_item.xml +++ b/src/main/res/layout/file_details_share_public_link_add_new_item.xml @@ -26,8 +26,7 @@ android:id="@+id/add_public_share" android:layout_width="match_parent" android:layout_height="@dimen/standard_list_item_size" - android:orientation="horizontal" - android:visibility="gone"> + android:orientation="horizontal"> @@ -39,29 +39,25 @@ android:contentDescription="@string/user_icon" android:src="@drawable/ic_user" /> - + - + diff --git a/src/main/res/layout/file_details_sharing_fragment.xml b/src/main/res/layout/file_details_sharing_fragment.xml index 7873c3bcd1..a0d38e27f6 100644 --- a/src/main/res/layout/file_details_sharing_fragment.xml +++ b/src/main/res/layout/file_details_sharing_fragment.xml @@ -1,5 +1,4 @@ - - - + android:orientation="vertical" + android:paddingTop="@dimen/standard_eight_padding" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + + + android:layout_marginBottom="@dimen/standard_half_margin" + android:layout_width="match_parent" + android:orientation="horizontal" + android:paddingLeft="@dimen/standard_padding" + android:paddingRight="@dimen/standard_padding" + android:paddingTop="@dimen/standard_padding"> - + + android:paddingRight="@dimen/standard_padding" + android:paddingTop="@dimen/standard_half_padding"> - + + tools:ignore="UseCompoundDrawables"> + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/src/main/res/menu/fragment_file_detail_sharing_email_link.xml b/src/main/res/menu/fragment_file_detail_sharing_email_link.xml new file mode 100644 index 0000000000..6fdd4d40f2 --- /dev/null +++ b/src/main/res/menu/fragment_file_detail_sharing_email_link.xml @@ -0,0 +1,68 @@ + +

+ + + + + + + + + + + + diff --git a/src/main/res/menu/fragment_file_detail_sharing_link.xml b/src/main/res/menu/fragment_file_detail_sharing_public_link.xml similarity index 90% rename from src/main/res/menu/fragment_file_detail_sharing_link.xml rename to src/main/res/menu/fragment_file_detail_sharing_public_link.xml index 6ba8b25d7a..1947846e3e 100644 --- a/src/main/res/menu/fragment_file_detail_sharing_link.xml +++ b/src/main/res/menu/fragment_file_detail_sharing_public_link.xml @@ -20,7 +20,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:ignore="AppCompatResource"> - + @@ -31,6 +33,12 @@ android:id="@+id/link_share_file_drop" android:title="@string/link_share_file_drop" /> + diff --git a/src/main/res/values/dims.xml b/src/main/res/values/dims.xml index ed1a377f7d..092100a9c9 100644 --- a/src/main/res/values/dims.xml +++ b/src/main/res/values/dims.xml @@ -31,7 +31,7 @@ 32dp 8dp 4dp - 2dp + 2dp 16dp 24dp 32dp From 4f8de5731d675d764adde24da1b9b51f62b300e5 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 25 Aug 2020 07:51:10 +0200 Subject: [PATCH 05/20] wip Signed-off-by: tobiasKaminsky --- .../android/datamodel/FileDataStorageManager.java | 4 ++-- .../android/operations/UpdateShareViaLinkOperation.java | 2 +- .../owncloud/android/ui/adapter/LinkShareViewHolder.java | 4 +++- .../com/owncloud/android/ui/adapter/ShareViewHolder.java | 2 +- .../android/ui/adapter/ShareeListAdapterListener.java | 2 ++ .../owncloud/android/ui/fragment/FileDetailFragment.java | 2 +- .../android/ui/fragment/FileDetailSharingFragment.java | 8 ++++---- .../res/layout/file_details_share_internal_share_link.xml | 2 +- .../res/layout/file_details_share_link_share_item.xml | 2 +- .../file_details_share_public_link_add_new_item.xml | 2 +- src/main/res/layout/file_details_share_share_item.xml | 2 +- src/main/res/layout/file_details_sharing_fragment.xml | 5 +++-- src/main/res/layout/toolbar_standard.xml | 2 +- src/main/res/values/dims.xml | 1 + src/main/res/values/strings.xml | 3 ++- 15 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 2e932fcdf7..5919713436 100644 --- a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -1260,7 +1260,7 @@ public class FileDataStorageManager { contentValues.put(ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD, share.isHideFileDownload()); contentValues.put(ProviderTableMeta.OCSHARES_SHARE_LINK, share.getShareLink()); contentValues.put(ProviderTableMeta.OCSHARES_SHARE_LABEL, share.getLabel()); - contentValues.put(ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION, share.isSendPasswordByTalk()); + //contentValues.put(ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION, share.isSendPasswordByTalk()); return contentValues; } @@ -1285,7 +1285,7 @@ public class FileDataStorageManager { share.setHideFileDownload(getInt(cursor, ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD) == 1); share.setShareLink(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_LINK)); share.setLabel(getString(cursor, ProviderTableMeta.OCSHARES_SHARE_LABEL)); - share.setSendPasswordByTalk(getInt(cursor, ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION) == 1); + //share.setSendPasswordByTalk(getInt(cursor, ProviderTableMeta.OCSHARES_VIDEO_VERIFICATION) == 1); return share; } diff --git a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java index bc83a77f47..4b140a0f6e 100644 --- a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java +++ b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java @@ -57,7 +57,7 @@ public class UpdateShareViaLinkOperation extends SyncOperation { updateOp.setPassword(password); updateOp.setExpirationDate(expirationDateInMillis); updateOp.setHideFileDownload(hideFileDownload); - updateOp.setVideoVerification(videoVerification); + //updateOp.setVideoVerification(videoVerification); updateOp.setLabel(label); if (publicShare.isFolder()) { diff --git a/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index 9b5437b42e..790ffb43f4 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -59,8 +59,10 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder { binding.copyLink.setVisibility(View.GONE); } else { if (!TextUtils.isEmpty(publicShare.getLabel())) { - String text = String.format(context.getString(R.string.share_link), publicShare.getLabel()); + String text = String.format(context.getString(R.string.share_link_with_label), publicShare.getLabel()); binding.name.setText(text); + } else { + binding.name.setText(R.string.share_link); } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index 716ef47e9f..27577eeebf 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -95,7 +95,7 @@ class ShareViewHolder extends RecyclerView.ViewHolder { private void setImage(ImageView avatar, String name, @DrawableRes int fallback) { try { avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension)); - } catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException | StringIndexOutOfBoundsException e) { avatar.setImageResource(fallback); } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java index 91d17af1ca..c1e4926cb9 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapterListener.java @@ -36,4 +36,6 @@ public interface ShareeListAdapterListener { void copyInternalLink(); void createPublicShareLink(); + + void requestPasswordForShare(OCShare share, boolean askForPassword); } diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 02263d5372..0cac80a931 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -374,7 +374,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener, super.onAttach(context); if (context instanceof ToolbarActivity) { toolbarActivity = (ToolbarActivity) context; - toolbarActivity.hideSortListGroup(); + //toolbarActivity.hideSortListGroup(); TODO check if needed? } } diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 64b081f65d..1b8cbfd065 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -404,8 +404,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); MenuItem videoVerification = menu.findItem(R.id.link_share_video_verification); - if (videoVerification != null) { - videoVerification.setChecked(publicShare.isSendPasswordByTalk()); +// if (videoVerification != null) { +// videoVerification.setChecked(publicShare.isSendPasswordByTalk()); // -When enabling it: @@ -414,7 +414,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda // -When disabling it: // -If it is for a mail share, you must always set a new password (which is also different from the previous one) // -If it is for a link share, you do not need to set a new password - } +// } } private boolean userOptionsItemSelected(Menu menu, @@ -438,7 +438,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda return true; } case R.id.action_password: { - requestPasswordForShare(share); + requestPasswordForShare(share, capabilities.getFilesSharingPublicAskForOptionalPassword().isTrue()); return true; } case R.id.action_expiration_date: { diff --git a/src/main/res/layout/file_details_share_internal_share_link.xml b/src/main/res/layout/file_details_share_internal_share_link.xml index 6dfe2501f4..707c062dba 100644 --- a/src/main/res/layout/file_details_share_internal_share_link.xml +++ b/src/main/res/layout/file_details_share_internal_share_link.xml @@ -21,7 +21,7 @@ --> diff --git a/src/main/res/layout/file_details_sharing_fragment.xml b/src/main/res/layout/file_details_sharing_fragment.xml index a0d38e27f6..da6757fb94 100644 --- a/src/main/res/layout/file_details_sharing_fragment.xml +++ b/src/main/res/layout/file_details_sharing_fragment.xml @@ -17,7 +17,7 @@ License along with this program. If not, see . --> + android:layout_width="match_parent" + android:layout_marginBottom="72dp" /> diff --git a/src/main/res/layout/toolbar_standard.xml b/src/main/res/layout/toolbar_standard.xml index 066082ba46..481f22579b 100644 --- a/src/main/res/layout/toolbar_standard.xml +++ b/src/main/res/layout/toolbar_standard.xml @@ -39,7 +39,7 @@ android:layout_height="wrap_content" android:layout_marginTop="?attr/actionBarSize" android:background="@color/bg_default" - android:paddingTop="@dimen/standard_eigth_padding" + android:paddingTop="@dimen/standard_eight_padding" android:visibility="gone" tools:visibility="visible"> diff --git a/src/main/res/values/dims.xml b/src/main/res/values/dims.xml index 092100a9c9..2ed44d2923 100644 --- a/src/main/res/values/dims.xml +++ b/src/main/res/values/dims.xml @@ -40,6 +40,7 @@ 2dp 56dp 72dp + 56dp 16sp 12sp 12dp diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 8a17c3981f..a87380288e 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -934,7 +934,8 @@ Add new public share link Change name New name - Share link (%1$s) + Share link (%1$s) + Share link Allow creating Allow deleting Allow resharing From 7b2ed741bd684f98ca5ca1beb5fe62d91571babf Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 25 Aug 2020 10:24:57 +0200 Subject: [PATCH 06/20] wip Signed-off-by: tobiasKaminsky --- .../android/datamodel/OCFileUnitTest.java | 2 - .../fragment/FileDetailSharingFragmentIT.kt | 69 +++++++++++++++++++ .../fragment/FileDetailSharingFragment.java | 5 +- ...file_details_share_internal_share_link.xml | 2 +- 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt diff --git a/src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java b/src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java index 4f7f6e1945..5965906ab4 100644 --- a/src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java +++ b/src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java @@ -88,7 +88,6 @@ public class OCFileUnitTest { mFile.setEtag(ETAG); mFile.setSharedViaLink(true); mFile.setSharedWithSharee(true); - mFile.setPublicLink(PUBLIC_LINK); mFile.setPermissions(PERMISSIONS); mFile.setRemoteId(REMOTE_ID); mFile.setUpdateThumbnailNeeded(true); @@ -122,7 +121,6 @@ public class OCFileUnitTest { assertThat(fileReadFromParcel.getEtag(), is(ETAG)); assertThat(fileReadFromParcel.isSharedViaLink(), is(true)); assertThat(fileReadFromParcel.isSharedWithSharee(), is(true)); - assertThat(fileReadFromParcel.getPublicLink(), is(PUBLIC_LINK)); assertThat(fileReadFromParcel.getPermissions(), is(PERMISSIONS)); assertThat(fileReadFromParcel.getRemoteId(), is(REMOTE_ID)); assertThat(fileReadFromParcel.isUpdateThumbnailNeeded(), is(true)); diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt new file mode 100644 index 0000000000..31b62e9605 --- /dev/null +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -0,0 +1,69 @@ +/* + * + * 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 . + */ +package com.owncloud.android.ui.fragment + +import android.widget.ImageView +import androidx.appcompat.widget.PopupMenu +import com.owncloud.android.AbstractIT +import com.owncloud.android.R +import com.owncloud.android.lib.resources.shares.OCShare +import org.junit.Test + +class FileDetailSharingFragmentIT : AbstractIT() { + @Test + fun listShares_file_none() { + throw NotImplementedError() + } + + @Test + fun listShares_file_all() { + // with multiple public share links + throw NotImplementedError() + } + + @Test + fun listShares_folder_none() { + throw NotImplementedError() + } + + @Test + fun listShares_folder_all() { + // with multiple public share links + throw NotImplementedError() + } + + @Test + fun publicLink_optionMenu() { + val sut = FileDetailSharingFragment() + + val overflowMenuShareLink = ImageView(targetContext) + val popup = PopupMenu(targetContext, overflowMenuShareLink) + popup.inflate(R.menu.fragment_file_detail_sharing_public_link) + val publicShare = OCShare() + + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + + // TODO check all options + + // scenarios: public link, email, …, both for file/folder + } +} diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 1b8cbfd065..d150831ccc 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -75,6 +75,7 @@ import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.appcompat.widget.PopupMenu; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; @@ -375,7 +376,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda popup.show(); } - private void prepareLinkOptionsMenu(Menu menu, OCShare publicShare) { + @VisibleForTesting + public void prepareLinkOptionsMenu(Menu menu, OCShare publicShare) { if (publicShare.isFolder()) { menu.setGroupVisible(R.id.folder_permission, true); menu.findItem(R.id.allow_editing).setVisible(false); @@ -403,6 +405,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); + // TODO move to separate PR MenuItem videoVerification = menu.findItem(R.id.link_share_video_verification); // if (videoVerification != null) { // videoVerification.setChecked(publicShare.isSendPasswordByTalk()); diff --git a/src/main/res/layout/file_details_share_internal_share_link.xml b/src/main/res/layout/file_details_share_internal_share_link.xml index 707c062dba..6dfe2501f4 100644 --- a/src/main/res/layout/file_details_share_internal_share_link.xml +++ b/src/main/res/layout/file_details_share_internal_share_link.xml @@ -21,7 +21,7 @@ --> Date: Fri, 4 Sep 2020 11:51:02 +0200 Subject: [PATCH 07/20] wip Signed-off-by: tobiasKaminsky --- .../ui/fragment/FileDetailSharingFragmentIT.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 31b62e9605..20ff20a227 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -21,17 +21,30 @@ */ package com.owncloud.android.ui.fragment +import android.Manifest import android.widget.ImageView import androidx.appcompat.widget.PopupMenu +import androidx.test.espresso.intent.rule.IntentsTestRule +import androidx.test.rule.GrantPermissionRule +import com.nextcloud.client.TestActivity import com.owncloud.android.AbstractIT import com.owncloud.android.R import com.owncloud.android.lib.resources.shares.OCShare +import org.junit.Rule import org.junit.Test class FileDetailSharingFragmentIT : AbstractIT() { + @get:Rule + val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false) + + @get:Rule + val permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) + @Test fun listShares_file_none() { - throw NotImplementedError() + val sut = testActivityRule.launchActivity(null) + sut.addFragment(FileDetailSharingFragment()) + } @Test From 4dfefee31ad09b7ddf6eff2d7c04ea973ff7ccca Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Fri, 4 Sep 2020 13:10:50 +0200 Subject: [PATCH 08/20] wip Signed-off-by: tobiasKaminsky --- ...agmentIT_listShares_file_allShareTypes.png | Bin 0 -> 36968 bytes ...SharingFragmentIT_listShares_file_none.png | Bin 0 -> 12883 bytes ..._listShares_file_resharing_not_allowed.png | Bin 0 -> 10481 bytes ...FragmentStaticServerIT_showSharedFiles.png | Bin 0 -> 35408 bytes .../fragment/FileDetailSharingFragmentIT.kt | 115 ++++++++++++++++-- .../datamodel/FileDataStorageManager.java | 4 +- .../owncloud/android/datamodel/OCFile.java | 3 +- .../android/ui/adapter/ShareViewHolder.java | 10 +- .../fragment/FileDetailSharingFragment.java | 1 + 9 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_allShareTypes.png create mode 100644 screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_none.png create mode 100644 screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_resharing_not_allowed.png create mode 100644 screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png diff --git a/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_allShareTypes.png b/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_allShareTypes.png new file mode 100644 index 0000000000000000000000000000000000000000..2b68676ebee7e87cd1b2dea6dfa62ddc97909094 GIT binary patch literal 36968 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 R2?76U+}6H@xnUjt{{c!?)gu4^ literal 0 HcmV?d00001 diff --git a/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_none.png b/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_none.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7aa4f55567927719dd47d18ebb67ae7291c72 GIT binary patch literal 12883 zcmeHuXIN9~)@>A(jRp7Ct!|WNMMR1qASDzFNS7|5D*-798VDsokd5WIMFD|8XhEfj z5Tc=(K!}|ZAV`ZC0=gjt2oNEJ03pd;_?>glz0Y^gx%c~?^W0zO?|QP{^{%<*JLVW; z&fL4?XuV_W{;ePoXote{FEs|KdB@}!l~ik!IDDeIyHF|o;SBfG*X0(TB@W{ghQOpg6DMqRn%rsXW!nJ zTR|2jGN6r0pr0o}H!WmADe|D7qW^YnlQBrOXTx8w{q+a`aqa(fQ^3}ZVgY?7LKAdz z?||E^%^UN2^-ks>ErAh%R&xp({8?``SSg)0S|AO`|OK%@&i@}U_ms{Yx|vx zyhM)4(awTh)4BfW_?4j>tx8ow3NNXl`={a9(WC+3es{{+0&QT>JJJ{b;_cRR4!rUL z_=!GSb~sw+4>pP4ZBo^$lH81Q%$81VG>g*CEb2EK$7z;yWV;_p7F zsj@QR)gfpu-Y;Rc{&7Wot5U2R-CVks7S+O{Tlic=2ks0qbO81>d9wjIi9fidTj`OF)wi9b&w z4HFcT7C#L@!twe`5J?ek=7n0}^|Nw<_GxtT9EtN>4VOqHFLY?o?!l+Za*Mfweg26r zn&wi|kiz{-V~y6*^&nHA!TtL_}+^cKC3R z@dBZ#p_$+RbvI^;=zs0;?TN5Gt;XDH*AY>t9zELw0m&hu#chYvvsaGh_3mg{nJCEB znlESgCsU&Dmq)C`IySE)G6T9f2)V;}!mR+*1&lv>!k9-Y>nyz&D2+vjf z;;79%%C@dI29>O!MRg&tm)kO~F zqr-DWi1;xeBk{_p$;S)42vK4=3Ga$&ZeU})y9GlhBT*0X*#*~zm>m+F05_X~Z2q`E ze0zO_xIuVchzm@wGH8t?H>f1cyzDjk>`^c!Pu#(5CXBAa5=?`Xf~noSMcW_-Rp|)&L60tK8LA1X< zezQ}gONga#eevXtdeXw|L+nl}mtJ3lF2Auf6p{;j(QB)b!;R$>C%{QHpG{BI75NRi zI&MWC)!dWTz}06HgtxP+%s~B&%I({@l+IE_}8TIzD{O!OFvuB3Xl`iNA>CUi54^zvVFw4RtdV)ne5`5~x zXdVEg#3bex6mzP9bq6-e2p2c_;&z&^U61!KFA!j8I>>jyxxO)>V&%PGEt~>^t-De_ zYxmdo_49E3x21xIQZXb@_vKhv>`Vk$#ySdZ1JF zd|-PCGxZI9^o5C_N61GW&Zf&>QwKKh^U-14gJvuQQ%ZN$1E(vk=<=6phR-gWZ71K5 z0U+ugIBGo223{%ZPkV*w3_B8$?i1Ce?<;FpW-r$qjO}%Ov|B(=mhg4IhW)%-Q&a*3 zj@0|y-YY>NXow8s!TSybNwJeR^xNi5CL2QaSPjhU888-XJvc+LwfI^}@4~}sT491A zGoseT@*4j~bnHr7gv|~mu?;@Q&dKM`ELXmns9;#(cUmI-Hi|9ynX$k!JYh4jKY$dd^^o~Ey?TTQ) zQ=3&_^v%AsdFs&YaCvGqqus9=U3CRw@GvV(n8O??chK0#U_tAERH&A_TMGBE;(nP?rS-b=@Ou zLXdK%xG-*djylm^Yj%B_>n?Y1@k-Ej7f!o&>hPUUF{|>dvpr#OHlMGY%Ti!nH^6O1SRA8I#zk02|2Rr;7Ld(-kh}4#Asd4Hlpg zCgSMFR$vfJmuAw5QW7jgKTm~a6lbpLbfi?e(c7?VQaO`5ts&c~2 zsipB(!!b8{ZPXmRp7EOb-2>Q=;*~p>oETnK?iFcWS>KO)bC5z``4S&%J6O}o&GhZ( zZ5ffQqBGb&Cr>{|7cXh(jRAfq>e}GiT}_@Ux88gC0T4>|e(07z1{y;Kd<#Q26roqA zppq%*v}t9qpSmjsKa}qf5WHW|Qpni#5bH-tG}@c*`+EJf>P~+5q^`PqjrfgS+~U=M zeL;0vnrFt4VU6EjFv+v4opnU%1SGCI9(mzpV?)`|;;lC2dLs#&$QCND>F?)`9xT?u zbzGv$nWiUn{YBU#`qE*U?_8tM|0q>G zeLhXE`^?kfmOjNdW*t)@Y3Ho!06KCTdOrND+S9vzkS^5zXcTKZ(T{6sT{+1v&CRlL zEPd)%>@xiHp(13vtS~n*XfeU{&Y(w^ngHeCav8VE&JCbgV&n%35xf| zoCuVg^0{JvL6_IwKt~TvfHR?8OHSuba-PK$Gb=!xQjtX!TrYZfiB6%C zJhD^k)O{}-%@6v9%4PNY^li?OwN10F@n&PP{3Q#y?0ociKBOZjD^#<7#*%C(TZG=y zGOpUGBuBcSA$w!X`|+<44HjP<3AsSQN~T|9`PACSBMMx$Or@dX$#}xzG4^>(0)mUN z-SR=OUol&Y+g$9Ofw-b2`-R|brI0yn`jRbGxad9_n5kR#h-rjEKY{Yp_S`kjMjUdC z8(*rJukmj5ZE)tLzss*4Yn)xjtiVPjQ-Bqg-aRcs!kwy`7`r>C%0flO+3Gax3pzTx zBM?2^VGmi@w(#`U=G9+sp&%Y&WyMdkpK^yXql!*iLd+kWkY#Q;5TU~mjfm%BV~Zvp z-&Ounzm5Nw!w=)$jrOszxaijMdW=k&(G&etxXYdS79+eeL1%KYASG*elGv@rPd2z< zYPN9{?Q71Ap;#3wWbCz{_|)uhZ5`J%3*3$^kO~z|G+bC#&7AjzI5f1Q4$<3r&bW6Y zP4}oGSF1aaR-EvHD|*446T#}d8vK|EPek+=t?o>5b(HrKxghY6D3S^LJdq?Gj4Tjf zL+4sVb7f~A*+M0wE5qpqJR7Lto(ytYyx+MkPJ_8u<;|AArfkX41wL)avx){oR`2iF z=LtGo>w=h$`tDnnoOYC3A8&h6!_JIrdXzv$I2GRNtnK9L*efV0b0&=4iYw4{sGD)6 zBzI>|Ik5kFo{l#lfoF@!aG29LI3Dly?c#^WUhzG~`zFEXz$s>XQpbYH(YUfE65snz zKqT?cKXZx(^{gG!k4^X86i~eVhge!yPJb6me^*n$wZE&W%Ox`6;V8N$l@F#6s1g)i z7|-JR3CRqKSq_0-4E8SBd4=ft8|d2OzX`Ixi!VST{j+B*VvqX&iqlS$1x>uMkiJ(l zb4~)ZLe*Zcpv-A@u7AyX=%#P&c6>1a3h?`Bv98S%;B&kFq=SXSpGT={Y;8~Jg0|EJ zELk2KxN=`Jn7iS%{f@ zIY9_6sbTfo&gA1g8}c$GYjkPzni;Txebp9Dc@+mJdYuJQoPM}R{RoQtpuX215K`*e zA*d~Wz(&G8UD&52^6t2?!p`;dj(B;YzEhWGACIkh_2(a9?{*lTyejX4xxE*1ZJ2H! zi`|g7QwEHm?S?OP>!ge3nh15h;dUoqzR$+Y14v)>gA(sZW+55)k(KUPj{-P3RBk2h zy>z+N+)VRZ9H5~*?kc0M$t@0Vxc+*BY_{F6WA66lwVj~OyD7yU!u#4SXFT($-`{Tg zAyj>Vjb0Vv2$ZESS9xBD_M<<9sjJ6FUb0j)ut3xHCtup@pEy4au*u360Y1`QWwqz7 z?JN4P)`~aI*8_BUsA|Ke)&5mLgL%Jg!o28w{c89T2L27unH2K;#{*Ts%HcKiqje9# zOP|%%ubw!-@Qw9VxYgM2VwXcL6D6mEm!82%Y|Kjwr}#)fn`K*uG|G*HqIyzSO)faHF4c^k|xmKBL57R#_U>x*S`x z+%!k73c==UE@da(-s5qcs|ZRN=~$PFzfUtqB}<=^Cgci#U?~}%lw|75@?Yujv^_qs zu4bnJ#ZyEimLpycLc-k{K2Z*&(;3RQJ}2-fG@hq_QvI5lc(Jc)hr#EPTajC4%Icek zf(vpO>*^2K>pOW9x1DCo0mzREA#N(7&#ksMgT1Kp4Q@xJd?=!V@tw1b%cGHl0MWKrlqV3=SgDMg1nxLEVJG1@FopPn$ z?yC6J7;$#JUSdZ2pHQm2d3qLru7L(7+{9z*)l_+bZCtQ|>%`8)uQFFz-zs}bIR^uM z?X=&on-P+td6`iFkgJ4LskkghNsdj^YO3~WiVUwPikXI#mjkZH3%87irVDNAz620I z6?IxvLU8&xDOBIFxcc~1=)i>9L07wQQ~Xl2Cc~GRskL&;3tev98D4o!5!vrNpcFgo z41a1e|9-dKr8%lpa`kCPf$u1e`Bq{B8*>ycM6Tqw{ z^5m2I6R52|8%=pMFsE%Vc!`SAhs}qJ)FJHh5VUH}sdvkoHlKJ#xpPI)N zyD~N;AsdslNpM_^#K$$#HdmrEtvdklzJ^_kp^rHT5GZwOptqR7J4d%5PT;R8l;o61 zILQ*uu1VzU(^PlOZ@F*|Sp#K!WJc@N*WVHMO0>M;f-i~uuF;-9XWcW~IeLE~%*9`{ zqvCEw47QtzW?To~1hto?xw$!-t&HnB26X8&qN6undo09gu}m|d5#?0)icj=)PnW#PgC>q510MQ)mFQ+l1$1^(RM4Djumqjtmjg)2`D6-=hmS zwWJo7-N)a?jm0Y*oIjbX_aIt8UF@}E@0UC)Z9RN-gKoM{trSSlX=CG?7Q9(m^JPnt zm2wrn0YbtI_iJ|Uz5+-=ULB#NE+d&IL=#M3v-vn_;?!0rFCkDi!T<{?@tk2y1vJ;U z!FZikCvoM*x7*rrB`;f*xhq(EbN@XFgI*!-zz==ohJ1FKPnM(}gDS)VHdHSKm$@jb z99P0Cmi>8>rEgsu(&HTkx~vr7pa8;XaVAPgQ`xP(>$emQn@ks)n3{=pGT91c?B z#EGffj^HXLVxTiI4~|lHV?(rDOJkpUGDN3Z75fCE;*NeJdNnU?T-Ktb5yNebzZG6n z8B%hYFLxdJ>d10F-43VjQhpDkanLw3bNpTBZcvJuOMFY*7C*KJe)|y`n5pn9!|0DD zICh&3XaeeLL{74m5!3u72thp|2{t1Q#d0e2I(ILVtagApUt6Sa-$={qoqltp-seC! zEMO;iF$2E=qzCTlTjM9J zy&#CweUXd^FL|s0F;-wdLWTJ z*CAOh0Tl3u4A@fgez#M$PBNfl)lNS!9#=_Tn-2qOA;IHv;N~~-AlF|epZ>Jqh;;;a zZ4&*VQS;118Hl>qZpZKC`bA%hs;AUG^AmF1Jt{{Q%MFL}K|d`zcie0g@u<}8aRm{T zI;9$D;DGeI0G~9S$ToEk^rJQF((4(1-gZjBLR-@TbjrRHuh*}~bNBQe@Yrlovhy%& zGz;0)JiE3JD9E~(<$*|T8Yjm?+WIu1ZQ^NosEkF4)9b70V1q?`sNwMSbI6f+PCbgJ zBL1X;6eoaJ!G}jT0PCoxM<`wJ6anU$?PbGS}!N?n@;#@4YrsAwyTj|-Nk2zlls52c<9D20PFFv$joJJ?CpYQ$ozhD%066=| z8>DkQNeu*WNgxzqwyR_1y306SixbbJji}3d9RpeYI=M1Y=WLsi{5@4gu?n=^yCG0U z3<%vHwk*O%mHr?ds2(qk0T8UhN!K`6Q;O$C?`x5tp}wZbKJPMM&g`(1R{4vcua!2T zg{)YD2PCxYrN@L5dLe5;qCsdTnkt3>h<1X&S~tdl{B|MZ_*l3mS5_tQg}p{!S9Gro zV!+*#@>o%w2}ldSkNZk1j!?EC8)F(*qBR(My(2!wDvxP~d&6=oz3+=d%tc=H>#QLX z%`Z@5-Lz17e_Z8|UWZP)LGH$nS>9g(yepcnuI+wqFns;p%dKynt(Dx-jL~oC;TwR? z0Bm)+584159T;8f8g&DlWF{?Kx=N5jisC1*1CeVVBi$NDP~n0P+US?7jme_MU5_e% zDouz_-C^)7xGUeC!U6NtaW*Tkr2|z*!~%aQQmzItagc$?u?~{EFxe2}sQ-(P6UA zadS5a3sng2N1}UCT~5Cr*^>#MzB@B6oNra}KRXE={#Y-}d<~cLC3zwiz)8A5s1)-# z@GC-?@R|N>La&qPc%GwMwx+-?KDC1s4RpQKRDFBjnH|(plWY>onte~12Kpp3`zPc? zYbKA2MS~T#Xa58aLRkD)2eAX3L&2&$@Fb zwn@@TqOSC_xT$$<#D`};f=aJEVz&vFW=wz=>XAE1yjaB?+#)Bqb|-#3D5>q>-R-|l zK8^coyX7hifGy|?hG-BfpX+wAuJ+@ms|dTqNY zyyT^jWDf{w%B7nkAXz6o!9c<)b#=6!zS#%4_PB)~4~RpP$4P-bP^H_$ws}8GKew8B zh}r%UsGutn-G__@VEB2<9n-DIXNIZG>I^y;F04G^4ao--AwnUek!~i+?y<82`_4{{ zC=p_xC~E>C>6>=AIR{XY0l?B`^7Z7H+KJz`u{W5IJaDRx%fTR~4$y>XoaXvVQKX!c zj90Z0PYdbiG01FPoq3={9cM|rw1C>;km7fD^;z2U2og-g>4+Uo-(2qPEjXUPe=$-r z5sAS;emBSWZ@1to)(y<=k5PIUf8D|A31_Lv&zIL_J@wG@;r2Pvr*yO%%57RO9BEe6 z$MqPr#MIX|QzRoXSYuk&Y|$@EK*%?)YcSpX_+z$1R-x@jb5EM@&isyT`)S71r)*_r zIZ%*4a-5_03A#C8zYLg>9mSis&n9lTX%Tslk90IqYjTxy;uY-#>Mf+(FS5yL2xyEeEOL9Hv^yN;< z*veo{Wd<<~wFm}v3R9FL9$K zt4-*eAM|F9we-E)Y3|cC&HjOlpU?8CzOoui@=;q&z5wXr_LlQ4`Buo#Z}=dO!X zdY!72A5v(w)0It==ta8 z+=a4$PHxoZ)%ERETBNVH_e_x|o!km+6+&_GPIvm(wyaDvBp$SBu`id%M{ddDISK>v zD>HfOZ8kz*9x6BI6IAMbDV-gdn{Wt+YrBCXgmv%J9ZFVH@3{(y;AiU|QzkkoboBP+ zpiEtQWtak+X5ITB3Xsq_H)OCvKt+1{(G6b!SbuH+C}N)EQ?B0CO_{w>H$=0IxzfnG zPgZ4CUQR%j9juxI>;spqPS5tG0&9LyVdNQF$$NW37aoQ6Z}B;%&ulhNPwnD_SGtEN zY$*z9WVbQ?T!PG@5r-~r*5qHSRnDhjh#{APT5M`u$r#s$Ha#vkt2K^Ur_R-KQjM64 zoSLIa3(~u~P#vtjQyZ(j-+FPdk>j5)dKGY!n-}yMFpgw|G&2U{w6R~-U0WELsZtMT zJyIw=DTt{N;)bu}BfZSyb)aqY8P>-ehh&+`YS_pEwqmq*zsP^0FaBgB*l~-Iqe|S@ z6huoWI!7=V@n$Ij&$uxVSybocFYXScEZv_s8x5umaKX9gFWGwRwgjSB7gsmK)y8!g z)fHIMFKnc&QbWQxUz5f&tvl`%*bk|aV*Hcqr-EqRj|eWTzp3w;-+&6W({5JR1RnFc zP^Z@}v&fi7OK{0rlL)E)v+LsBnyxp%pA86Af})I^%V<#msW}jGwYpgt4=kmh}p*22E8b7R}U~<{fT)c=VkvFE3JGekoy>bu1>RJ52`;%p#3M+i2_59_Xrk71q&!f4Im93TF0qFgy%fwAtka{bd@|rwblB9%FQTCb#?OQ{6{f=PqomxJlMD_P-D=Yp z*BaXKC_cnD#NU|TsaG{BW{qm*5YYsINzE!gtASg^G^!p&eE%cn)n)SsFUi3z&fGDD<2k8K`PVoL!R%d=iE=$)G!B0FoCUg#F}db~wK zzEfCaqWN^Dno@c!0Wjg*0ivAj1JN)#9(9u)@XXt5$c+Y&X2WJLoS z$YY&lA%P5O`G#FIdR<$%LS`2F9HNO*Rn|(30cG6^QGrclWl2ISiaf$rTpMGb5T(ibOc``-(SOM> zwrQ*P@@HWZn#E6sP|7isdR9$kf7z!z;sAdtb}0H+&XdgsJ>gS#I``!VS$7*=e;`CY zg`L=1iLda`FG`Pr#Y_b&^yv@U`O%0#<5%g`2o`auvTUI*MtNlhEt>TVTQf2mxVqPc ztH|p;Z-p&yDEQv-<_5s3yOFPVn9wH>bzXDM)m%F*QmN^fsz39~Eb$ym%!sfVKeDji zE-52=IZ?X|y3mclr~u}RWZi}!r*L<>aYTr>c3f>~x6O&bY&v^W5vaQzma%|jT9Y*s zsI#WUfgQa|3zrE*DD}7h$hwI8&dSm;B|R^koWMBXkjPCk$g4-U4#aVTh)ehVe1~^? zMZTM%zAH@KjIxs(sVjH2bD$m5Z?sGWYnbCp6f=gt>N!x^?Us4SOa2MZ2N>VC6j`G= zqRyz_ZSzXs_Qw>J-pT*jHg*K4OGWFhMRhQ}n8kneL5Ht6fJkqw>9g%_Kd3el4U6fp zEVK=XQm8d&N5;c?VEGu!E#f1eqrf_>TdeWYY$!buXj#VvDV6JIYE4Gm5A0w>4kf@i z^9@5f(9kN+p<_g9oo{yo^GbHBG_KViV~C%dAUoO_npbXGL}`BOj|2<6)%0N0No1Ns zU7>4|7DQEs;>EY!VPZZcH_bgcm2bQ4CHlBSOm=kZc&z;Ib*5G;d!D#zstxyd3Wq{) zhKb^^T5cUaI@9m^o6Q3Nx$)kTd47xG12t${2?o|MRK7MY^%qZj+HsG5J3Sr05QE;!&YNqBW*k+V7JO32R~7cu^5%fy z9;mtFQ19~*V6>>UWh6Fl0qMPjW*SLVA`5oZ)=aCNUP8TgqY?+8kqL#{iG{Gn562(G zc9y2NG`{DqRP4cybp8z}>S`*&slUC~5%HpN_xC=th}MNqRNwUhN)#Ko-dYDtbf>FV4ck%<>>ql6w;vlqIQM8MK4-xo9x_j}Lew3On z9ZjQ%mze3%{vE0>I}cl~^Q`EaBn|e(+eaB}gl>8?r>v~V@2RDRyV1dBwq~Td%qO$O z$2$dy{u>Q6@r9jSTdP6q8d-x#jzW1N3zL*LYdS;jFx5pEfn}%s9DV}2Eb?^#JT9J5 z2r^>A@6SJEJ1bXsjkq0iIn}ABg-}-&xqS>i61Pej3RxYIT{|i39yWnn=?v+(_+``UH?k@|MSul70B{RW$G1j9O3^)*yYtaxlI|I{ z_vos}(7`B8jnsPGT`|p&Fe}T7Z5pzWuxe6F9z8u)F6a=yGsU!nt?X2cz-ZN{`E}_x zuAYB1Y81*D7vI)Se7vTK&k3xdm6crwJd?B?m#6o@6(Vv51AH;VkSxE-V9(Lx9SqV8 zrGX!3<&4=r3FyyNg6<$(&e@vaFAs??E)bE1hx~J-~)-}21F@?Kb8dCyV6{GAK(00qr{ABq@ zia}ivo(_M;V`3iDf@9wg}ykIT$T|{WRFGMte6#^NB0!3?vF2Etl}%s+*07pkn-Gm|GJem)z-^Q#2{reMKW3#%mm)BBK&>{ z)A4hBfc#-K#=S&dLRb~0M&vkXYE2q`_uG*cBY5M+{{K}ffv1~4UQMkvq^$K?DNqx{EHl7Aa^{C}K~{NFl= zz|;S}mH$gi@PE3T|Du~3|AmvH|HT;mkdcOZTQT`Ppw*SSz z{X2R7*+BEZljonN>A#cb-^uge{zt&SljmQQJUY15C5I}lM zkWi!qRAy)afg406|E=B$WFyXXeg4=R4oM=bU@)^Uc4TyQ^_-nc)qFedU;%kG`g#~hvf zwee84>xKPdMVjAL zD{cX44WS`xyRqQmM)u-35jow}#p~8ZE_NwXwgfcuZ-thA(r!2-Borkfv^PlTLiSD} zVHu%adP2u~cl@@te^%(h1(Dy@e%tWd+CMn-Kyfc8MS||4BJ@D^-}(yQdn}j+r!Z37 z-CRQ#swt71D_Opabu+j@*N`#a1WWB=dq?QE&U=KsRxcPWzL_*j)j2hw)-YeWTs>Ei zZqL5ortgMI3h%enu~TbYx>Vhx#~NC3^H^+L>0y3ulf!F|c<18i%?DPAGg*;M8JatV z!>2r&R(kYP#_u;RHg9eAIUBLc2xdiXoxyRnkBrA$iq z!_}3fxM7N)?#~OW9mn`pGm@R{m2hu9DFx^D=+0z7iHKLrzAkP@tPMV2M!nm8C{e14 z;^02^Tw*WhT1n{mT$)ZxqoNU+&BF3M-K@zSEw7%a>aA`hSQ|QKM)2ntd3S#J);_gZ z*!M82yw;6}saD0ux{S21cKx{b!3DY3EL=l?@>PN9kKkSw)jCP6dRx}e^M;TwyAQck ztQ$bStj|Y@$e!LJn_j?#6S}o&Vv$<|w$^q!^e`k(2QrwEpn-oYEXQxXYyhBt2Q|rBP<}~%qwdO4q zc|}R1^}D>t8rvEZH#rAal$~RM!IzH@DM&KJ0mHylMm?$_ihzACrs5RXe%~MvBdc9naN#hy5v&;ITT=7|rV<3m_S6A1H8SyDh!nog`_<__6!=k-Je<%yVUtqhq(dxZ@om)ALWJAF` zQ*P^v3C}V4`BFV#JtdjJBgM*U;6vP|gtamjF}(&g=5_g&O&wDz=2Y^{R~hFA!AH@q zn>f(yaDie!pfrPlh*WO(X`k%ZE zY~r;lwC1lRUI|Kv*C@6uJ-@>5Ggnjbu+0i{3FlH6CyzIpTaJIfZ-J%ekuj$>+p#H2DeYs4O@C#S_)~B4uQoOo%d(rqOdg zm-9v7Dsi{~C-AYwJ-T0W?NXxzM_Jy8WNK3bwemzDo_+X!x_YZd;4uiM-4!g<$~m_h zOG0iiuVp{HAeYv)h%*WuSLg+YYJcHU-Hi^O_u19I^qsIutUu-=$f{?*|JaXLqNDmh z7KYr=$@6)%qSI|-8LySVVnTm5Sn1L@c=NfNqx48U7?hTH2=#U#SK84F)6o5_Lr`5@ zs79 zB`44_f=(tP)zhd{VVrS-|HeD7KWN@Qk^_EY%$Y^Tp8f`osdxQ6Of%Ptp3sOCNFaE4Rbkj$EIVGjGXk zJs;}}I~LTSny#LA4hQ9lCRpq%0|)0H0(DclnC5^zDmtt*{H~tM)#Xn-NU47BbsfE} zJpH5Xzt^AzrCyLLz=eVeTy#x4MB&K^Qc3f7=1?<`1FfRd88@dZjW>f+H_qbChgl!Q zE@WH3)U=-~J~goNp~@w#PUCdIchRj1)Dhsm9mJ#Mhi)NuAI!B1)CYeJim*5`B~P z*kdl-HSF^*j1kyolQX+KrK`{Cm^N5HKSn2wu-R|hT^S8>%KE9^+w2Pk@*#jYHSJeW ziHlKmusVwHIS!64S+J1h(i9MQ<(~Eh3T}3Key-o>2=Df7ho6AF-sNhYf z$7_8|8%UJ(m0qklo-FI+Wn5_Zl9~-BgvdJDf3JeVj(d*TTBD7Pp#o#%qoE&u0|l|DJ7LU5!!8{-Z=v4MR)#5>(N)>=2**k6Yw5D_##L`^up`xs z@S!VpjwWLbKQ$^41)3E++Ex4+d5Joc^|R__d>}ia{D*X6Lpxu1u*BM|k}aIf?@mdx zc{5o?2i5DW^erR<6Hy-&6FO@E;#vM&_Q-zt@m4MPWy14B;;>(jsiSJHr|bAqw9eCR z>8z*q0nWH~!;FN-kI+cZV;V!Yux@fLb!0InlXjM!1y6-quAY`W)>~*WfP~kg9S8-Q zCEf9Rv?7!J@<2^pGHrS=&%)Yj?x1tZgLeP9F#0fQ1YSEBtNP5!$JO4cV;O@)4rjg+rx=MD1zlomPn1%ZM+Uwt^yp0O?R02f_!@}uj&rZ4 zwYuZ;V+(Qm)YmHlkItm*$QgY)uQF@KbLPQLiCISz_-acJJoQeI?q$inoU{`I$PJVp zw;tsUQ;U2>>~(ryMW3lLQEBPsO8v}CZ=NE20O4fF3&tjnhbG5lTU^c@wsWmjqaj~p1Rdczqg{#rp4Wb_RmV~LnUAo9B}>97&P#s zB+qm_Lq!J)#Orn*>rLzM{IQX`F8n9P1%USt#{C0=fwf;D*f3T$bpD+4w-3^K-hZX0 z+zTt%w^Io6-?4JSjqGYvc5uge=jSP`ssr8 zGo#NxOP%U+$IRv5Bbvx8#~W?luYN21)s3%I-(=qsc~A_H-!61vqxA+>boGaWPVILM zgoMK@$Irh@9}oIIq;lNo9X9fiYtRSZWJj;pT08d7<|c{;N*XL(NL$h#M!bKP^Cdso z$;?_tD9W%CyK>_Pv+q6SH zw)Klz#I*nxAK-D~dYNU>+V#ji5d%_Fn*#b)vh(2d=5n=*@0W$ZNaqD0u=lHE4;0Zu4`MkQae9pz#N{S**3$Hw9ov*YcVX z-?)Ga*^+k>b)JKusV3>>J04ES-zBLw_@e-dwpYS8E)R*meC<BfW4H=IxusUYts?%?`(SnX&jtJT2*g9#z6R-MAf%Uukm1qF8t!3Z?^fiFpO|z@W5W*|`>0-&^XghKMfh0mSGx0d}qm(xHECTa# z?ws7+w>$1cM)qD5u>&BOHe}kD(!|L>;Nl!m$Jl}wZHW^sg!HGL8S|63RkG+5w^P!f zqA@Ufl$G#2g2bCOG2&MuC}1^W@`qs87>Xa-(nKyih+EsdQNAt!^4Iut@x2@m=nINx z3>wz}+Y^TAjFAZ*O3d>2{Gv_l5+lNrx7}>>!0EJ~9gOySaVZXRq2ah%de}-gV~e+u z6C>+1h9Id>dKP!`4GFdjgPo+2(xYQlj#dPh zhrj+DE$_^T4VJq@VO9hN_31HK0@4ViHu<4Pr0Zz;1YNvi1+GwJ@79leaj5JJ{9 z71#-uo@^#7aT%5zI;}a?w*#o|V#G|XITH7LzDSL-G1P{VBY};t{Zhg6D_f5+hP8%v z2Mz!Vv8bD{+&Ebq)&!wu3%C(}=zT8H6&hcw=rlYAO8P1`J@3#<5MOR{DF)1K;%p?_ zO5!E&7_jvArR{tsl~87atA){l$lKENZk|xf9~wEEBins8UUN_|PaxYw8UAzx=czup zu|{`S2qms$vXv9276I>K0)NG=0u(w3ZHNA#QZw{Q3I`*M^LO2QuOl_2aJ#g;rX&I=B~s#FFr-5U z;fW*=xjyc?f`VHFj{zMrV(kXdMX{G~{G6Y>qRlanHtTZ8I^9 za$tQf-%HqOCa*kzTEV*873-%i1(9oJX>rCIlNPfPo(Ou@*7}V4tLs!`Gb5{l>M^tm_++h zZ(Mb}0ujgxxpAXp(dzb?xjLVYpw6}qW?P0ZV2dWtrjv`%$=smMnUeIZuOrJl#qF2h zP;0=Nq5HWuZv@uICpaK7 zB}!^*+QJJ>WYKvB-e+_OPQJzYUT?T7UBRPGw}l~yhHi_v^x6Ju1$DEtAdz8FaE6W5 zH`{D#k0%>jS0b%u7EF-HBc za&m`u35pCk8K=iA@&&p=N|JAKUV3b?43Y~4=hMze!CP8w1L5(4p0i|EgO%R0QDqij zTdBu;VKtMh-+nv$db^R*5XXq~wN=zuAk23>(`fd}rh=LsoL zD?9RONx6=*J!2ts*J*LjVUkL%3ojh|c6F&m(t&KSVgYLH8omvAn)v();BLgQ=FT&v zi5i{!jb!%-9Iv@TGSm z=AmgDXSjp&?^Xq__{kFY%&KC11pFp`<908-wz#%_9648LscRe8s6bOAnUb3#zT6n; z4Ty$6*@fXot_}3O6KuD}#C6gtFCrG2BC6&*Nj)!2ig8VRCItw#&cRQOHs-7u^XmEm z!EZGWgYw(0GN}wL-Gp_3klo<`enCyh5XwqW1t)Gf!ly`mst({M370D_Ku3!L^!XfR zAH0YLa)q@jTW59>gMR6BNeNaBIItyJdITV`cds8Z@)E4hh%hTiWu#G;c)nOY4YQ^M zQ@!Vzsw}dcjq%ZK$3K+ND+*!EHSa&^q52hByuFg!a zUF(kE|14#l82Sa~UfvQmR2dZK#aN4x#mo*>1^{`v@5jNYalC)aQ81kPHx-P3KRmI?br`-2+s4VIG!9O*{u6OxqUF-O%01>S@VO+FZV|F&+w zwU9zt-)zugj3{0+LX^b8_4Q7@u#qn2h#hF+H2|U`QQ>lPHH#ZHNa5GXh`bNorXfUp zT%mHytV2zhQP;h`U`WjHLCbB?j)%&CGr?OMacPO*ng*Q;457hm5v^IR z#aO~KLeIq%1$B}ptU(li^e9l-&4`JNUQQWyiPvU9eyVQ*R7rwJEDsF^q{uKQn!T(~ z#J1xjxTT0n$L7d%_{)s|05KI|g7m;9G-wa*NKp?p|D8EoZOd9d>1-!GKgvp|@ZOPv zu(8$W0j%*reM$A_l~qK8!BYQWwP;-)t?WAr+%y~fPK8Qq25cjO%6=n# z1DsIp&XN8kYfZHD+{(OqM7h`5Y^gvelQ6*XM@(z`R}?Pyf7Q7oP27+$S8J%d*H(mE zUFZ}p9ykP@q8pG6#BaPm3ATWrbHrw3LPqaV3ep3d768wOs5x4ArsX=ZFQPKt z5YjQ4U7(Tq#E0j>QQfGn&BQE5NJ~IJM@)SV{0_^C0x8TZ#9kkSkWBIF6VLT50#6wC z4j+_KbZ_4FF%dZ7abkYC8}tZy6VNj);K?=Ft%q@GWr3Kn?s_Y09d}*PS#HB4+hz>Y z0jxob_`o`RBv7}oUIk;h2eZNcbn>dbEYFW8?;x8yHzT-6^FM*IqvyP)iWl&c%2h*Ylb)$u z{|1#SKE3A>B+SO7@F`hto>w#k8#wws3f`)(0gKzXeOPKZvakWT?ruzfQPv7Xqa*E> zl|5oLO=HC3ld0qcK#i)#cYQdxhQ)fsLLu!goOVS+1J-W?9Xc&#qHaL3P7dLGFiGh+ zwLMuH>aa~GjDJ=p&@q9HpIha}Qq)bANmqL#W{u@udeF^u5$|8H5I$Y2C2gfU3s<5eJ zEv10X=uo2ufzT)mZYhJ&;OAy<$};Y~$km(e56bz;)nH}%KhAN;g?-MbMsjIMPcajR+gNC^Qmw~$}!LiY`(gSmW0YXF|O zDoqu@Qk4>HBUTAnNiyoxN_9si4G)pbe6NE+(G`en##1e-#LC)3)u^YiG~H(=b>k1G zRAHd&qJ{_4F(Hv1<-Z%Sp=wj=ciHRTc6>DZUBg|Nc7uF3Gc$vxikVm8%6x z@|EDmz6#4^jr#$<_*13lC2C;AO1gT2fxtzY!LPs99Da9bBcC1`8{#acmmHH;t1+8u zs(T%uhR%E(tLxa=y9|s!b(TVi%wqS)$R(0`<2j6L>WqvE)E;8 zHd}R?&b6?S*^JU;8Ae5mgc6K`vOZ_*U8j13o>!nd-_MJHCqHN9>*`xQ9Dtt~+HObS zST7!)fNkntMLg3YW5AVN0Z`ehabhQJJ+fIHrK%x5xG7-Mxf`}|oC4MnSuGNfBK27s zsAq2c?3|IFJ@T=3c#L#G*uz00JvhJ&U%G-IRY2zwA9QVIO?(QVHMkE0VJF&=>{0U_ z(m6ywS!6-U@?l(mR}Hzy%<4YVZwekk#bfytQyPE>(cBTWk@bzUZ8vF%!Q9=%robi` zt>$WWf3-<396WDu7JMR>bssCh5-4ueaIjxmt_%Bd>g>gg)??JQK0ge}d0f3eDewjj z{R&z<)BLp7zhz!c%9Z?CmXvGY#ZQVf;11xeMg|@5+<*pmi>h%2zlI)V`11=fKFNM9 zyrX=elrjnqm%NbOqGS;*Y$O;am+bvx#{I_-99a8x2+mg;2FB3&2Y`+tK1ivo;(N2- zXXd}R3xA)Z|1mS)o}>R?dW^px`hOh0|63FLe|)G^_)kqyKn{NhW&2|PVDSHsKlAHz zg8%-tz`uCtKO*CQOEG_U$o1Ply@}Yq#6PLuzx&Mpx$*qFQT(%qw)g!HDdz7UjFbrd zsl5(#)PFO8zwP>;vLxWY|JUaJzbfPZ8WH~YBbR^L1RQq%>2=NTf#qNS%F1|O&PU!z@ gqI&Dsu_cs$A6*a5Y6KoM3JIBhXLT8O>DKrE3r5}Tp#T5? literal 0 HcmV?d00001 diff --git a/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png b/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png new file mode 100644 index 0000000000000000000000000000000000000000..5eedf72b11751b1a9121131fddf32bf26be53dcf GIT binary patch literal 35408 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

QyodJ{E-6Gp%bkPrQhDKCTRGC-Cs4!Y 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 US!hs64FNybm2O={T{iLmUlUmeHvj+t literal 0 HcmV?d00001 diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 20ff20a227..41a9801036 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -29,7 +29,12 @@ import androidx.test.rule.GrantPermissionRule import com.nextcloud.client.TestActivity import com.owncloud.android.AbstractIT import com.owncloud.android.R +import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.ShareType +import com.owncloud.android.utils.ScreenshotTest +import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test @@ -40,28 +45,111 @@ class FileDetailSharingFragmentIT : AbstractIT() { @get:Rule val permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) + lateinit var file: OCFile + lateinit var folder: OCFile + lateinit var activity: TestActivity + + @Before + fun before() { + activity = testActivityRule.launchActivity(null) + file = OCFile("/test.md").apply { + parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId + permissions = OCFile.PERMISSION_CAN_RESHARE + } + + folder = OCFile("/test").apply { + setFolder() + parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId + permissions = OCFile.PERMISSION_CAN_RESHARE + } + } + @Test + @ScreenshotTest fun listShares_file_none() { - val sut = testActivityRule.launchActivity(null) - sut.addFragment(FileDetailSharingFragment()) + // todo search hint is not shown!? + show(file) } @Test - fun listShares_file_all() { - // with multiple public share links - throw NotImplementedError() + @ScreenshotTest + fun listShares_file_resharing_not_allowed() { + file.permissions = "" + + show(file) } @Test - fun listShares_folder_none() { - throw NotImplementedError() + @ScreenshotTest + fun listShares_file_allShareTypes() { + OCShare(file.decryptedRemotePath).apply { + remoteId = 1 + shareType = ShareType.USER + sharedWithDisplayName = "Admin" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 2 + shareType = ShareType.GROUP + sharedWithDisplayName = "Group" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 3 + shareType = ShareType.EMAIL + sharedWithDisplayName = "admin@nextcloud.server.com" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 4 + shareType = ShareType.PUBLIC_LINK + sharedWithDisplayName = "Customer" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 5 + shareType = ShareType.PUBLIC_LINK + sharedWithDisplayName = "Colleagues" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 6 + shareType = ShareType.FEDERATED + sharedWithDisplayName = "admin@nextcloud.remoteserver.com" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 7 + shareType = ShareType.CIRCLE + sharedWithDisplayName = "Private circle" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 8 + shareType = ShareType.ROOM + sharedWithDisplayName = "Meeting" + activity.storageManager.saveShare(this) + } + + show(file) } - @Test - fun listShares_folder_all() { - // with multiple public share links - throw NotImplementedError() + private fun show(file: OCFile) { + val fragment = FileDetailSharingFragment.newInstance(file, user); + + activity.addFragment(fragment) + + waitForIdleSync() + + screenshot(activity) } @Test @@ -79,4 +167,9 @@ class FileDetailSharingFragmentIT : AbstractIT() { // scenarios: public link, email, …, both for file/folder } + + @After + fun after() { + activity.storageManager.cleanShares() + } } diff --git a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 5919713436..5179f222e6 100644 --- a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -68,6 +68,7 @@ import java.util.Set; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; public class FileDataStorageManager { @@ -1347,7 +1348,8 @@ public class FileDataStorageManager { } } - private void cleanShares() { + @VisibleForTesting + public void cleanShares() { String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"; String[] whereArgs = new String[]{account.name}; diff --git a/src/main/java/com/owncloud/android/datamodel/OCFile.java b/src/main/java/com/owncloud/android/datamodel/OCFile.java index bba165d9d3..721d409033 100644 --- a/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -47,7 +47,8 @@ import third_parties.daveKoeller.AlphanumComparator; public class OCFile implements Parcelable, Comparable, ServerFileInterface { private final static String PERMISSION_SHARED_WITH_ME = "S"; - private final static String PERMISSION_CAN_RESHARE = "R"; + @VisibleForTesting + public final static String PERMISSION_CAN_RESHARE = "R"; private final static String PERMISSION_CAN_WRITE = "CK"; public static final String PATH_SEPARATOR = "/"; diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index 27577eeebf..e15e2ee0ee 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -62,19 +62,23 @@ class ShareViewHolder extends RecyclerView.ViewHolder { switch (share.getShareType()) { case GROUP: name = context.getString(R.string.share_group_clarification, name); - setImage(binding.icon, name, R.drawable.ic_group); + setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_group); break; case EMAIL: name = context.getString(R.string.share_email_clarification, name); - setImage(binding.icon, name, R.drawable.ic_email); + setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_email); break; case ROOM: name = context.getString(R.string.share_room_clarification, name); - setImage(binding.icon, name, R.drawable.ic_chat_bubble); + setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_chat_bubble); break; case CIRCLE: binding.icon.setImageResource(R.drawable.ic_circles); break; + case FEDERATED: + name = context.getString(R.string.share_remote_clarification, name); + setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_user); + break; default: setImage(binding.icon, name, R.drawable.ic_user); break; diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index d150831ccc..68633f9bbd 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -196,6 +196,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda if (file.canReshare()) { refreshSharesFromDB(); + binding.searchView.setQueryHint(getResources().getString(R.string.share_search)); } else { binding.searchView.setQueryHint(getResources().getString(R.string.reshare_not_allowed)); binding.searchView.setInputType(InputType.TYPE_NULL); From 01f27dd08cb079d7a8c1efeb9c99859f5416e6fb Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 8 Sep 2020 06:59:37 +0200 Subject: [PATCH 09/20] wip Signed-off-by: tobiasKaminsky --- .../java/com/owncloud/android/AbstractIT.java | 7 +- .../fragment/FileDetailSharingFragmentIT.kt | 149 +++++++++++++++++- .../com/nextcloud/TestActivity.kt | 8 + .../UpdateShareViaLinkOperation.java | 5 - .../android/services/OperationsService.java | 5 - .../android/ui/activity/FileActivity.java | 4 +- .../fragment/FileDetailSharingFragment.java | 29 ++-- .../ui/helpers/FileOperationsHelper.java | 12 +- src/main/res/layout/file_details_fragment.xml | 3 +- .../layout/file_details_sharing_fragment.xml | 3 +- ...agment_file_detail_sharing_public_link.xml | 6 - 11 files changed, 170 insertions(+), 61 deletions(-) rename src/debug/{kotlin => java}/com/nextcloud/TestActivity.kt (92%) diff --git a/src/androidTest/java/com/owncloud/android/AbstractIT.java b/src/androidTest/java/com/owncloud/android/AbstractIT.java index 5569a35553..8796e0c396 100644 --- a/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -58,6 +58,7 @@ import androidx.test.runner.lifecycle.Stage; import static androidx.test.InstrumentationRegistry.getInstrumentation; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID; import static org.junit.Assert.assertTrue; @@ -96,7 +97,7 @@ public abstract class AbstractIT { Account temp = new Account("test@https://server.com", MainApp.getAccountType(targetContext)); platformAccountManager.addAccountExplicitly(temp, "password", null); platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_BASE_URL, "https://server.com"); - platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_USER_ID, "test"); + platformAccountManager.setUserData(temp, KEY_USER_ID, "test"); final UserAccountManager userAccountManager = UserAccountManagerImpl.fromContext(targetContext); account = userAccountManager.getAccountByName("test@https://server.com"); @@ -381,4 +382,8 @@ public abstract class AbstractIT { return name; } + + public static String getUserId(User user) { + return AccountManager.get(targetContext).getUserData(user.toPlatformAccount(), KEY_USER_ID); + } } diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 41a9801036..dafd23b085 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -34,6 +34,8 @@ import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.utils.ScreenshotTest import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -43,7 +45,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false) @get:Rule - val permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) + val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) lateinit var file: OCFile lateinit var folder: OCFile @@ -67,8 +69,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @ScreenshotTest fun listShares_file_none() { - // todo search hint is not shown!? - show(file) } @@ -87,6 +87,8 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 1 shareType = ShareType.USER sharedWithDisplayName = "Admin" + permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -94,6 +96,8 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 2 shareType = ShareType.GROUP sharedWithDisplayName = "Group" + permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -101,6 +105,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 3 shareType = ShareType.EMAIL sharedWithDisplayName = "admin@nextcloud.server.com" + userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -122,6 +127,8 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 6 shareType = ShareType.FEDERATED sharedWithDisplayName = "admin@nextcloud.remoteserver.com" + permissions = OCShare.FEDERATED_PERMISSIONS_FOR_FILE + userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -129,6 +136,8 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 7 shareType = ShareType.CIRCLE sharedWithDisplayName = "Private circle" + permissions = OCShare.SHARE_PERMISSION_FLAG + userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -136,6 +145,8 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 8 shareType = ShareType.ROOM sharedWithDisplayName = "Meeting" + permissions = OCShare.SHARE_PERMISSION_FLAG + userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -143,28 +154,152 @@ class FileDetailSharingFragmentIT : AbstractIT() { } private fun show(file: OCFile) { - val fragment = FileDetailSharingFragment.newInstance(file, user); + val fragment = FileDetailSharingFragment.newInstance(file, user) activity.addFragment(fragment) waitForIdleSync() screenshot(activity) + + longSleep() } @Test fun publicLink_optionMenu() { - val sut = FileDetailSharingFragment() + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + shortSleep() + sut.refreshCapabilitiesFromDB() val overflowMenuShareLink = ImageView(targetContext) val popup = PopupMenu(targetContext, overflowMenuShareLink) popup.inflate(R.menu.fragment_file_detail_sharing_public_link) - val publicShare = OCShare() + val publicShare = OCShare().apply { + isFolder = true + shareType = ShareType.PUBLIC_LINK + permissions = OCShare.READ_PERMISSION_FLAG + } sut.prepareLinkOptionsMenu(popup.menu, publicShare) - // TODO check all options + // check if items are visible + assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible) + assertTrue(popup.menu.findItem(R.id.action_password).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_send_link).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible) + assertTrue(popup.menu.findItem(R.id.action_edit_label).isVisible) + assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible) + assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible) + assertTrue(popup.menu.findItem(R.id.link_share_read_only).isChecked) + assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) + assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked) + + publicShare.permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked) + assertTrue(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) + assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked) + + // TODO +// publicShare.permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER +// sut.prepareLinkOptionsMenu(popup.menu, publicShare) +// assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked) +// assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) +// assertTrue(popup.menu.findItem(R.id.link_share_file_drop).isChecked) + + // password protection + publicShare.shareWith = "someValue" + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_password_title)) + + publicShare.shareWith = "" + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_no_password_title)) + + // hide download + publicShare.isHideFileDownload = true + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked) + + publicShare.isHideFileDownload = false + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked) + + // TODO expires +// publicShare.expirationDate = 1582019340000 +// sut.prepareLinkOptionsMenu(popup.menu, publicShare) +// assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title.startsWith( +// targetContext.getString(R.string.share_expiration_date_label))) + + publicShare.expirationDate = 0 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title == + targetContext.getString(R.string.share_no_expiration_date_label)) + + // file + publicShare.isFolder = false + publicShare.permissions = OCShare.READ_PERMISSION_FLAG + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + // check if items are visible + assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible) + assertTrue(popup.menu.findItem(R.id.action_password).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_send_link).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible) + assertTrue(popup.menu.findItem(R.id.action_edit_label).isVisible) + assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible) + assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible) + + assertFalse(popup.menu.findItem(R.id.link_share_read_only).isVisible) + assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isVisible) + assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isVisible) + assertTrue(popup.menu.findItem(R.id.allow_editing).isVisible) + + // allow editing + assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked) + + publicShare.permissions = OCShare.UPDATE_PERMISSION_FLAG + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked) + + // hide download + publicShare.isHideFileDownload = true + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked) + + publicShare.isHideFileDownload = false + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked) + + // password protection + publicShare.isPasswordProtected = true + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_password_title)) + + publicShare.isPasswordProtected = false + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertFalse(popup.menu.findItem(R.id.action_password).isChecked) + assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_no_password_title)) + + // expires + publicShare.expirationDate = 1582019340 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title.startsWith( + targetContext.getString(R.string.share_expiration_date_label))) + + publicShare.expirationDate = 0 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_no_expiration_date_label)) + + // TODO check all options // scenarios: public link, email, …, both for file/folder } diff --git a/src/debug/kotlin/com/nextcloud/TestActivity.kt b/src/debug/java/com/nextcloud/TestActivity.kt similarity index 92% rename from src/debug/kotlin/com/nextcloud/TestActivity.kt rename to src/debug/java/com/nextcloud/TestActivity.kt index 60bb1534fa..980763ad40 100644 --- a/src/debug/kotlin/com/nextcloud/TestActivity.kt +++ b/src/debug/java/com/nextcloud/TestActivity.kt @@ -32,6 +32,8 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.FileUploader +import com.owncloud.android.lib.resources.status.OCCapability +import com.owncloud.android.lib.resources.status.OwnCloudVersion import com.owncloud.android.services.OperationsService import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.activity.OnEnforceableRefreshListener @@ -101,6 +103,12 @@ class TestActivity : override fun getStorageManager(): FileDataStorageManager { if (!this::storage.isInitialized) { storage = FileDataStorageManager(account, contentResolver) + + val capability = OCCapability().apply { + versionMayor = OwnCloudVersion.nextcloud_15.getMajorVersionNumber() + } + + storage.saveCapabilities(capability) } return storage diff --git a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java index 4b140a0f6e..97342b89e9 100644 --- a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java +++ b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java @@ -39,7 +39,6 @@ public class UpdateShareViaLinkOperation extends SyncOperation { */ private boolean publicUpload; private Boolean hideFileDownload; - private Boolean videoVerification; private long expirationDateInMillis; private long shareId; private String label; @@ -104,8 +103,4 @@ public class UpdateShareViaLinkOperation extends SyncOperation { public void setLabel(String label) { this.label = label; } - - public void setVideoVerification(Boolean enabled) { - this.videoVerification = enabled; - } } diff --git a/src/main/java/com/owncloud/android/services/OperationsService.java b/src/main/java/com/owncloud/android/services/OperationsService.java index 917f238a4b..e78dab3280 100644 --- a/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/src/main/java/com/owncloud/android/services/OperationsService.java @@ -554,11 +554,6 @@ public class OperationsService extends Service { false); updateLinkOperation.setHideFileDownload(hideFileDownload); - boolean videoVerificationEnabled = - operationIntent.getBooleanExtra(EXTRA_SHARE_VIDEO_VERIFICATION, false); - - updateLinkOperation.setVideoVerification(videoVerificationEnabled); - if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_UPLOAD)) { updateLinkOperation.setPublicUpload(true); } diff --git a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index aed455a138..916ac165bd 100644 --- a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -899,8 +899,8 @@ public abstract class FileActivity extends DrawerActivity if (getFile().isSharedWithMe()) { return OCShare.READ_PERMISSION_FLAG; // minimum permissions } else if (ShareType.FEDERATED.equals(shareType)) { - return getFile().isFolder() ? OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9 : - OCShare.FEDERATED_PERMISSIONS_FOR_FILE_AFTER_OC9; + return getFile().isFolder() ? OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER : + OCShare.FEDERATED_PERMISSIONS_FOR_FILE; } else { return getFile().isFolder() ? OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER : OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 68633f9bbd..dfed50f39e 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -80,6 +80,8 @@ import androidx.appcompat.widget.PopupMenu; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; +import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; + public class FileDetailSharingFragment extends Fragment implements ShareeListAdapterListener, DisplayUtils.AvatarGenerationListener, Injectable { @@ -387,6 +389,12 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda MenuItem readOnly = menu.findItem(R.id.link_share_read_only); MenuItem uploadAndEditing = menu.findItem(R.id.link_share_allow_upload_and_editing); MenuItem fileDrop = menu.findItem(R.id.link_share_file_drop); + + if ((publicShare.getPermissions() & MAXIMUM_PERMISSIONS_FOR_FOLDER) == MAXIMUM_PERMISSIONS_FOR_FOLDER) { + uploadAndEditing.setChecked(true); + } else if ((publicShare.getPermissions() & OCShare.READ_PERMISSION_FLAG) == 1) { + readOnly.setChecked(true); + } } else { menu.setGroupVisible(R.id.folder_permission, false); menu.findItem(R.id.allow_editing).setVisible(true); @@ -405,20 +413,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda res); menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); - - // TODO move to separate PR - MenuItem videoVerification = menu.findItem(R.id.link_share_video_verification); -// if (videoVerification != null) { -// videoVerification.setChecked(publicShare.isSendPasswordByTalk()); - - -// -When enabling it: -// -If it is for a mail share, you must always set a new password (which is also different from the previous one) -// -If it is for a link share, you only need to set a new password if the share didn't have one yet (but you can repeat the previous password) -// -When disabling it: -// -If it is for a mail share, you must always set a new password (which is also different from the previous one) -// -If it is for a link share, you do not need to set a new password -// } } private boolean userOptionsItemSelected(Menu menu, @@ -514,10 +508,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda case R.id.action_unshare: fileOperationsHelper.unshareShare(file, publicShare); return true; - case R.id.link_share_video_verification: - item.setChecked(!item.isChecked()); - fileOperationsHelper.setVideoVerificationToPublicShare(publicShare, item.isChecked()); - return true; default: return super.onOptionsItemSelected(item); } @@ -601,12 +591,11 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda /** * Get public link from the DB to fill in the "Share link" section in the UI. - *

* Takes into account server capabilities before reading database. */ public void refreshSharesFromDB() { // TODO check if this is not called too often - ShareeListAdapter adapter = ((ShareeListAdapter) binding.sharesList.getAdapter()); + ShareeListAdapter adapter = (ShareeListAdapter) binding.sharesList.getAdapter(); adapter.getShares().clear(); // to show share with users/groups info diff --git a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 8dec08a8d8..81440edd1e 100755 --- a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -717,7 +717,7 @@ public class FileOperationsHelper { updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, OCShare.CREATE_PERMISSION_FLAG); } else { updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, - OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9); + OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER); } queueShareIntent(updateShareIntent); @@ -733,16 +733,6 @@ public class FileOperationsHelper { queueShareIntent(updateShareIntent); } - public void setVideoVerificationToPublicShare(OCShare share, boolean videoVerificationEnabled) { - Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); - updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE); - updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); - updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId()); - updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_VIDEO_VERIFICATION, videoVerificationEnabled); - - queueShareIntent(updateShareIntent); - } - public void updateNoteToShare(OCShare share, String note) { Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_NOTE); diff --git a/src/main/res/layout/file_details_fragment.xml b/src/main/res/layout/file_details_fragment.xml index f69a0abd22..e5c3ceb45c 100644 --- a/src/main/res/layout/file_details_fragment.xml +++ b/src/main/res/layout/file_details_fragment.xml @@ -23,7 +23,6 @@ android:id="@+id/detail_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:fillViewport="true" android:orientation="vertical"> + android:layout_height="match_parent" /> diff --git a/src/main/res/layout/file_details_sharing_fragment.xml b/src/main/res/layout/file_details_sharing_fragment.xml index da6757fb94..26f93511dc 100644 --- a/src/main/res/layout/file_details_sharing_fragment.xml +++ b/src/main/res/layout/file_details_sharing_fragment.xml @@ -97,7 +97,6 @@ android:dividerHeight="1dp" android:id="@+id/sharesList" android:layout_height="match_parent" - android:layout_width="match_parent" - android:layout_marginBottom="72dp" /> + android:layout_width="match_parent" /> diff --git a/src/main/res/menu/fragment_file_detail_sharing_public_link.xml b/src/main/res/menu/fragment_file_detail_sharing_public_link.xml index 1947846e3e..5aa14cae89 100644 --- a/src/main/res/menu/fragment_file_detail_sharing_public_link.xml +++ b/src/main/res/menu/fragment_file_detail_sharing_public_link.xml @@ -50,12 +50,6 @@ android:showAsAction="never" android:title="@string/share_via_link_menu_password_label" app:showAsAction="never" /> - Date: Tue, 8 Sep 2020 07:00:00 +0200 Subject: [PATCH 10/20] wip Signed-off-by: tobiasKaminsky --- ...lSharingFragmentIT_publicLink_optionMenu.png | Bin 0 -> 12883 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_publicLink_optionMenu.png diff --git a/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_publicLink_optionMenu.png b/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_publicLink_optionMenu.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7aa4f55567927719dd47d18ebb67ae7291c72 GIT binary patch literal 12883 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 Date: Tue, 8 Sep 2020 12:10:58 +0200 Subject: [PATCH 11/20] wip Signed-off-by: tobiasKaminsky --- .../client/FileDisplayActivityIT.java | 2 +- .../fragment/FileDetailSharingFragmentIT.kt | 324 +++++++++++++++++- .../ui/fragment/OCFileListFragmentIT.kt | 2 +- .../CreateShareViaLinkOperation.java | 2 +- .../UpdateShareViaLinkOperation.java | 11 +- .../android/ui/activity/FileActivity.java | 3 - .../android/ui/activity/ShareActivity.java | 1 - .../android/ui/adapter/ShareViewHolder.java | 4 - .../dialog/SharePasswordDialogFragment.java | 42 ++- .../fragment/FileDetailSharingFragment.java | 187 +++++----- .../ui/fragment/util/SharingMenuHelper.java | 10 +- src/main/res/layout/password_dialog.xml | 34 +- .../res/menu/item_user_sharing_settings.xml | 11 - src/main/res/values/strings.xml | 2 + 14 files changed, 454 insertions(+), 181 deletions(-) diff --git a/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.java b/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.java index 353d2daa1f..186cfb7846 100644 --- a/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.java +++ b/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.java @@ -97,7 +97,7 @@ public class FileDisplayActivityIT extends AbstractOnServerIT { "users", false, "", - OCShare.DEFAULT_PERMISSION) + OCShare.NO_PERMISSION) .execute(client).isSuccess()); // share folder to circle diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index dafd23b085..e71fcfa23d 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -31,6 +31,13 @@ import com.owncloud.android.AbstractIT import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG +import com.owncloud.android.lib.resources.shares.OCShare.DELETE_PERMISSION_FLAG +import com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE +import com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER +import com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION +import com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG +import com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.utils.ScreenshotTest import org.junit.After @@ -166,7 +173,8 @@ class FileDetailSharingFragmentIT : AbstractIT() { } @Test - fun publicLink_optionMenu() { + // public link and email are handled the same way + fun publicLink_optionMenu_Folder() { val sut = FileDetailSharingFragment.newInstance(file, user) activity.addFragment(sut) shortSleep() @@ -178,7 +186,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { val publicShare = OCShare().apply { isFolder = true shareType = ShareType.PUBLIC_LINK - permissions = OCShare.READ_PERMISSION_FLAG + permissions = 17 } sut.prepareLinkOptionsMenu(popup.menu, publicShare) @@ -193,22 +201,24 @@ class FileDetailSharingFragmentIT : AbstractIT() { assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible) assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible) + // read-only assertTrue(popup.menu.findItem(R.id.link_share_read_only).isChecked) assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked) + // upload and editing publicShare.permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked) assertTrue(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked) - // TODO -// publicShare.permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER -// sut.prepareLinkOptionsMenu(popup.menu, publicShare) -// assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked) -// assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) -// assertTrue(popup.menu.findItem(R.id.link_share_file_drop).isChecked) + // file drop + publicShare.permissions = 4 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked) + assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) + assertTrue(popup.menu.findItem(R.id.link_share_file_drop).isChecked) // password protection publicShare.shareWith = "someValue" @@ -230,11 +240,10 @@ class FileDetailSharingFragmentIT : AbstractIT() { sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked) - // TODO expires -// publicShare.expirationDate = 1582019340000 -// sut.prepareLinkOptionsMenu(popup.menu, publicShare) -// assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title.startsWith( -// targetContext.getString(R.string.share_expiration_date_label))) + publicShare.expirationDate = 1582019340000 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title.startsWith( + targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])) publicShare.expirationDate = 0 sut.prepareLinkOptionsMenu(popup.menu, publicShare) @@ -261,9 +270,11 @@ class FileDetailSharingFragmentIT : AbstractIT() { assertTrue(popup.menu.findItem(R.id.allow_editing).isVisible) // allow editing + publicShare.permissions = 17 // from server + sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked) - publicShare.permissions = OCShare.UPDATE_PERMISSION_FLAG + publicShare.permissions = 19 // from server sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked) @@ -278,13 +289,14 @@ class FileDetailSharingFragmentIT : AbstractIT() { // password protection publicShare.isPasswordProtected = true + publicShare.shareWith = "someValue" sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertTrue(popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_password_title)) publicShare.isPasswordProtected = false + publicShare.shareWith = "" sut.prepareLinkOptionsMenu(popup.menu, publicShare) - assertFalse(popup.menu.findItem(R.id.action_password).isChecked) assertTrue(popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_no_password_title)) @@ -292,15 +304,291 @@ class FileDetailSharingFragmentIT : AbstractIT() { publicShare.expirationDate = 1582019340 sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title.startsWith( - targetContext.getString(R.string.share_expiration_date_label))) + targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])) publicShare.expirationDate = 0 sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title == + targetContext.getString(R.string.share_no_expiration_date_label)) + } + + @Test + // public link and email are handled the same way + fun publicLink_optionMenu_File() { + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + shortSleep() + sut.refreshCapabilitiesFromDB() + + val overflowMenuShareLink = ImageView(targetContext) + val popup = PopupMenu(targetContext, overflowMenuShareLink) + popup.inflate(R.menu.fragment_file_detail_sharing_public_link) + val publicShare = OCShare().apply { + isFolder = false + shareType = ShareType.PUBLIC_LINK + permissions = 17 + } + + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + + // check if items are visible + assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible) + assertTrue(popup.menu.findItem(R.id.action_password).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_send_link).isVisible) + assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible) + assertTrue(popup.menu.findItem(R.id.action_edit_label).isVisible) + assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible) + assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible) + + assertFalse(popup.menu.findItem(R.id.link_share_read_only).isVisible) + assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isVisible) + assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isVisible) + assertTrue(popup.menu.findItem(R.id.allow_editing).isVisible) + + // password protection + publicShare.shareWith = "someValue" + sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_password_title)) + + publicShare.shareWith = "" + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_password).title == + targetContext.getString(R.string.share_no_password_title)) + + // hide download + publicShare.isHideFileDownload = true + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked) + + publicShare.isHideFileDownload = false + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked) + + // expiration date + publicShare.expirationDate = 1582019340000 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title.startsWith( + targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])) + + publicShare.expirationDate = 0 + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).title == targetContext.getString(R.string.share_no_expiration_date_label)) - // TODO check all options - // scenarios: public link, email, …, both for file/folder + publicShare.isFolder = false + publicShare.permissions = OCShare.READ_PERMISSION_FLAG + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + + // allow editing + publicShare.permissions = 17 // from server + assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked) + + publicShare.permissions = 19 // from server + sut.prepareLinkOptionsMenu(popup.menu, publicShare) + assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked) + } + + @Test + // also applies for + // group + // conversation + // circle + // federated share + fun user_optionMenu_File() { + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + shortSleep() + sut.refreshCapabilitiesFromDB() + + val overflowMenuShareLink = ImageView(targetContext) + val popup = PopupMenu(targetContext, overflowMenuShareLink) + popup.inflate(R.menu.item_user_sharing_settings) + val userShare = OCShare().apply { + isFolder = false + shareType = ShareType.USER + permissions = 17 + } + + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertFalse(popup.menu.findItem(R.id.allow_creating).isVisible) + assertFalse(popup.menu.findItem(R.id.allow_deleting).isVisible) + + // allow editing + userShare.permissions = 17 // from server + assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked) + + userShare.permissions = 19 // from server + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked) + + // allow reshare + userShare.permissions = 1 // from server + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertFalse(popup.menu.findItem(R.id.allow_resharing).isChecked) + + userShare.permissions = 17 // from server + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.allow_resharing).isChecked) + + // set expiration date + userShare.expirationDate = 1582019340000 + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.action_expiration_date).title.startsWith( + targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])) + + userShare.expirationDate = 0 + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.action_expiration_date).title == + targetContext.getString(R.string.share_no_expiration_date_label)) + + // note + assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible) + } + + @Test + // also applies for + // group + // conversation + // circle + // federated share + fun user_optionMenu_Folder() { + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + shortSleep() + sut.refreshCapabilitiesFromDB() + + val overflowMenuShareLink = ImageView(targetContext) + val popup = PopupMenu(targetContext, overflowMenuShareLink) + popup.inflate(R.menu.item_user_sharing_settings) + val userShare = OCShare().apply { + isFolder = true + shareType = ShareType.USER + permissions = 17 + } + + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.allow_creating).isVisible) + assertTrue(popup.menu.findItem(R.id.allow_deleting).isVisible) + + // allow editing + userShare.permissions = 17 // from server + assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked) + + userShare.permissions = 19 // from server + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked) + + // allow reshare + userShare.permissions = 1 // from server + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertFalse(popup.menu.findItem(R.id.allow_resharing).isChecked) + + userShare.permissions = 17 // from server + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.allow_resharing).isChecked) + + // set expiration date + userShare.expirationDate = 1582019340000 + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.action_expiration_date).title.startsWith( + targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])) + + userShare.expirationDate = 0 + sut.prepareUserOptionsMenu(popup.menu, userShare) + assertTrue(popup.menu.findItem(R.id.action_expiration_date).title == + targetContext.getString(R.string.share_no_expiration_date_label)) + + // note + assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible) + } + + @Test + fun testUploadAndEditingSharePermissions() { + val sut = FileDetailSharingFragment() + + val share = OCShare().apply { + permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER + } + assertTrue(sut.isUploadAndEditingAllowed(share)) + + share.permissions = NO_PERMISSION + assertFalse(sut.isUploadAndEditingAllowed(share)) + + share.permissions = READ_PERMISSION_FLAG + assertFalse(sut.isUploadAndEditingAllowed(share)) + + share.permissions = CREATE_PERMISSION_FLAG + assertFalse(sut.isUploadAndEditingAllowed(share)) + + share.permissions = DELETE_PERMISSION_FLAG + assertFalse(sut.isUploadAndEditingAllowed(share)) + + share.permissions = SHARE_PERMISSION_FLAG + assertFalse(sut.isUploadAndEditingAllowed(share)) + } + + @Test + fun testReadOnlySharePermissions() { + val sut = FileDetailSharingFragment() + + val share = OCShare().apply { + permissions = 17 + } + assertTrue(sut.isReadOnly(share)) + + share.permissions = NO_PERMISSION + assertFalse(sut.isReadOnly(share)) + + share.permissions = READ_PERMISSION_FLAG + assertTrue(sut.isReadOnly(share)) + + share.permissions = CREATE_PERMISSION_FLAG + assertFalse(sut.isReadOnly(share)) + + share.permissions = DELETE_PERMISSION_FLAG + assertFalse(sut.isReadOnly(share)) + + share.permissions = SHARE_PERMISSION_FLAG + assertFalse(sut.isReadOnly(share)) + + share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER + assertFalse(sut.isReadOnly(share)) + + share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE + assertFalse(sut.isReadOnly(share)) + } + + @Test + fun testFileDropSharePermissions() { + val sut = FileDetailSharingFragment() + + val share = OCShare().apply { + permissions = 4 + } + assertTrue(sut.isFileDrop(share)) + + share.permissions = NO_PERMISSION + assertFalse(sut.isFileDrop(share)) + + share.permissions = READ_PERMISSION_FLAG + assertFalse(sut.isFileDrop(share)) + + share.permissions = CREATE_PERMISSION_FLAG + assertTrue(sut.isFileDrop(share)) + + share.permissions = DELETE_PERMISSION_FLAG + assertFalse(sut.isFileDrop(share)) + + share.permissions = SHARE_PERMISSION_FLAG + assertFalse(sut.isFileDrop(share)) + + share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER + assertFalse(sut.isFileDrop(share)) + + share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE + assertFalse(sut.isFileDrop(share)) } @After diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentIT.kt index 0dabe88dc5..7b6786aafa 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentIT.kt @@ -224,7 +224,7 @@ class OCFileListFragmentIT : AbstractOnServerIT() { "users", false, "", - OCShare.DEFAULT_PERMISSION + OCShare.NO_PERMISSION ) .execute(client) .isSuccess diff --git a/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java b/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java index f8397c7b15..30a49f4f39 100644 --- a/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java +++ b/src/main/java/com/owncloud/android/operations/CreateShareViaLinkOperation.java @@ -52,7 +52,7 @@ public class CreateShareViaLinkOperation extends SyncOperation { "", false, password, - OCShare.DEFAULT_PERMISSION); + OCShare.NO_PERMISSION); createOp.setGetShareDetails(true); RemoteOperationResult result = createOp.execute(client); diff --git a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java index 97342b89e9..c4fa37aa18 100644 --- a/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java +++ b/src/main/java/com/owncloud/android/operations/UpdateShareViaLinkOperation.java @@ -56,14 +56,13 @@ public class UpdateShareViaLinkOperation extends SyncOperation { updateOp.setPassword(password); updateOp.setExpirationDate(expirationDateInMillis); updateOp.setHideFileDownload(hideFileDownload); - //updateOp.setVideoVerification(videoVerification); updateOp.setLabel(label); - if (publicShare.isFolder()) { - updateOp.setPublicUploadOnFolder(publicUpload); - } else { - updateOp.setPublicUploadOnFile(publicUpload); - } +// if (publicShare.isFolder()) { +// updateOp.setPublicUploadOnFolder(publicUpload); +// } else { +// updateOp.setPublicUploadOnFile(publicUpload); +// } RemoteOperationResult result = updateOp.execute(client); diff --git a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 916ac165bd..347a720cdc 100644 --- a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -746,7 +746,6 @@ public abstract class FileActivity extends DrawerActivity if (result.isSuccess()) { if (sharingFragment != null) { - sharingFragment.refreshSharesFromDB(); sharingFragment.onUpdateShareInformation(result, getFile()); } } else { @@ -761,7 +760,6 @@ public abstract class FileActivity extends DrawerActivity if (result.isSuccess()) { updateFileFromDB(); if (sharingFragment != null) { - sharingFragment.refreshSharesFromDB(); sharingFragment.onUpdateShareInformation(result, getFile()); } } else if (sharingFragment != null && sharingFragment.getView() != null) { @@ -807,7 +805,6 @@ public abstract class FileActivity extends DrawerActivity copyAndShareFileLink(this, file, link); if (sharingFragment != null) { - sharingFragment.refreshSharesFromDB(); sharingFragment.onUpdateShareInformation(result, getFile()); } } else { diff --git a/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java b/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java index 9a68b0c1d5..4ab713bcce 100644 --- a/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java @@ -145,7 +145,6 @@ public class ShareActivity extends FileActivity { if (shareFileFragment != null && shareFileFragment.isAdded()) { // only if added to the view hierarchy!! shareFileFragment.refreshCapabilitiesFromDB(); - //shareFileFragment.refrefreshUsersOrGroupsListFromDB(); shareFileFragment.refreshSharesFromDB(); } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index e15e2ee0ee..c48b42277b 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -64,10 +64,6 @@ class ShareViewHolder extends RecyclerView.ViewHolder { name = context.getString(R.string.share_group_clarification, name); setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_group); break; - case EMAIL: - name = context.getString(R.string.share_email_clarification, name); - setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_email); - break; case ROOM: name = context.getString(R.string.share_room_clarification, name); setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_chat_bubble); diff --git a/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java b/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java index 359424b56e..04816c21fa 100644 --- a/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java +++ b/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java @@ -27,13 +27,12 @@ import android.os.Bundle; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.EditText; -import android.widget.TextView; import com.owncloud.android.R; +import com.owncloud.android.databinding.PasswordDialogBinding; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; @@ -41,7 +40,6 @@ import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ThemeUtils; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; @@ -58,6 +56,7 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo private static final String ARG_ASK_FOR_PASSWORD = "ASK_FOR_PASSWORD"; public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT"; + private PasswordDialogBinding binding; private OCFile file; private OCShare share; private boolean createShare; @@ -122,12 +121,6 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo return frag; } - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return super.onCreateView(inflater, container, savedInstanceState); - } - @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { @@ -137,17 +130,18 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo askForPassword = getArguments().getBoolean(ARG_ASK_FOR_PASSWORD, false); // Inflate the layout for the dialog - LayoutInflater inflater = getActivity().getLayoutInflater(); - View v = inflater.inflate(R.layout.password_dialog, null); + LayoutInflater inflater = requireActivity().getLayoutInflater(); + binding = PasswordDialogBinding.inflate(inflater, null, false); + View view = binding.getRoot(); // Setup layout - EditText inputText = v.findViewById(R.id.share_password); - inputText.getBackground().setColorFilter( - ThemeUtils.primaryAccentColor(getContext()), - PorterDuff.Mode.SRC_ATOP - ); + EditText inputText = binding.sharePassword; + inputText.setHighlightColor(ThemeUtils.primaryColor(getActivity())); inputText.setText(""); + ThemeUtils.themeEditText(getContext(), inputText, false); inputText.requestFocus(); + inputText.getBackground().setColorFilter(ThemeUtils.primaryAccentColor(getContext()), + PorterDuff.Mode.SRC_ATOP); int title; if (askForPassword) { @@ -157,10 +151,9 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo } // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), - R.style.Theme_ownCloud_Dialog_NoButtonBarStyle); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setView(v) + builder.setView(view) .setPositiveButton(R.string.common_ok, this) .setNegativeButton(R.string.common_cancel, this) .setNeutralButton(R.string.common_delete, this) @@ -178,11 +171,10 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo @Override public void onClick(DialogInterface dialog, int which) { if (which == AlertDialog.BUTTON_POSITIVE) { - String password = ((TextView) (getDialog().findViewById(R.id.share_password))).getText().toString(); + String password = binding.sharePassword.getText().toString(); if (!askForPassword && TextUtils.isEmpty(password)) { - DisplayUtils.showSnackMessage(getActivity().findViewById(android.R.id.content), - R.string.share_link_empty_password); + DisplayUtils.showSnackMessage(binding.getRoot(), R.string.share_link_empty_password); return; } @@ -217,4 +209,10 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo private void setPassword(OCShare share, String password) { ((FileActivity) getActivity()).getFileOperationsHelper().setPasswordToShare(share, password); } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } } diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index dfed50f39e..3cf3a1143f 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -80,7 +80,12 @@ import androidx.appcompat.widget.PopupMenu; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; +import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; +import static com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION; +import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG; public class FileDetailSharingFragment extends Fragment implements ShareeListAdapterListener, DisplayUtils.AvatarGenerationListener, @@ -197,7 +202,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda ThemeUtils.themeSearchView(binding.searchView, requireContext()); if (file.canReshare()) { - refreshSharesFromDB(); binding.searchView.setQueryHint(getResources().getString(R.string.share_search)); } else { binding.searchView.setQueryHint(getResources().getString(R.string.reshare_not_allowed)); @@ -314,45 +318,32 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda * @param menu the menu of the sharee/shared file * @param share the shared file */ - private void prepareUserOptionsMenu(Menu menu, OCShare share) { + @VisibleForTesting + public void prepareUserOptionsMenu(Menu menu, OCShare share) { + MenuItem allowEditingItem = menu.findItem(R.id.allow_editing); 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); + allowEditingItem.setChecked(canEdit(share)); + 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); + if (file.isFolder() || share.isFolder()) { + allowCreatingItem.setChecked(canCreate(share)); + allowDeletingItem.setChecked(canDelete(share)); + } else { 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); - } + if (!capabilities.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_18)) { + expirationDateItem.setVisible(false); } SharingMenuHelper.setupExpirationDateMenuItem(menu.findItem(R.id.action_expiration_date), @@ -386,23 +377,28 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda menu.findItem(R.id.allow_editing).setVisible(false); // read only / allow upload and editing / file drop - MenuItem readOnly = menu.findItem(R.id.link_share_read_only); - MenuItem uploadAndEditing = menu.findItem(R.id.link_share_allow_upload_and_editing); - MenuItem fileDrop = menu.findItem(R.id.link_share_file_drop); - - if ((publicShare.getPermissions() & MAXIMUM_PERMISSIONS_FOR_FOLDER) == MAXIMUM_PERMISSIONS_FOR_FOLDER) { - uploadAndEditing.setChecked(true); - } else if ((publicShare.getPermissions() & OCShare.READ_PERMISSION_FLAG) == 1) { - readOnly.setChecked(true); + if ((isUploadAndEditingAllowed(publicShare))) { + menu.findItem(R.id.link_share_allow_upload_and_editing).setChecked(true); + } else if (isFileDrop(publicShare)) { + menu.findItem(R.id.link_share_file_drop).setChecked(true); + } else if (isReadOnly(publicShare)) { + menu.findItem(R.id.link_share_read_only).setChecked(true); } } else { menu.setGroupVisible(R.id.folder_permission, false); menu.findItem(R.id.allow_editing).setVisible(true); + + if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) { + menu.findItem(R.id.allow_editing).setChecked(true); + } else { + menu.findItem(R.id.allow_editing).setChecked(false); + } } Resources res = requireContext().getResources(); SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download), publicShare.isHideFileDownload(), + isFileDrop(publicShare), capabilities); SharingMenuHelper.setupPasswordMenuItem(menu.findItem(R.id.action_password), @@ -415,10 +411,36 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); } - private boolean userOptionsItemSelected(Menu menu, - MenuItem item, - OCShare share) { + @VisibleForTesting + public boolean isUploadAndEditingAllowed(OCShare share) { + if (share.getPermissions() == NO_PERMISSION) { + return false; + } + + return (share.getPermissions() & MAXIMUM_PERMISSIONS_FOR_FOLDER) == MAXIMUM_PERMISSIONS_FOR_FOLDER; + } + + @VisibleForTesting + public boolean isReadOnly(OCShare share) { + if (share.getPermissions() == NO_PERMISSION) { + return false; + } + + return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == READ_PERMISSION_FLAG; + } + + @VisibleForTesting + public boolean isFileDrop(OCShare share) { + if (share.getPermissions() == NO_PERMISSION) { + return false; + } + + return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG; + } + + private boolean userOptionsItemSelected(Menu menu, MenuItem item, OCShare share) { switch (item.getItemId()) { + case R.id.allow_editing: case R.id.allow_creating: case R.id.allow_deleting: case R.id.allow_resharing: { @@ -432,11 +454,13 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda } case R.id.action_unshare: { unshareWith(share); - ((ShareeListAdapter) binding.sharesList.getAdapter()).remove(share); - return true; - } - case R.id.action_password: { - requestPasswordForShare(share, capabilities.getFilesSharingPublicAskForOptionalPassword().isTrue()); + ShareeListAdapter adapter = ((ShareeListAdapter) binding.sharesList.getAdapter()); + if (adapter == null) { + DisplayUtils.showSnackMessage(getView(), getString(R.string.failed_update_ui)); + return true; + } + adapter.remove(share); + return true; } case R.id.action_expiration_date: { @@ -457,26 +481,32 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda public boolean linkOptionsItemSelected(MenuItem item, OCShare publicShare) { switch (item.getItemId()) { -// case R.id.action_allow_editing: -// if (file.isSharedViaLink()) { -// item.setChecked(!item.isChecked()); -// fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked()); -// } -// return true; - case R.id.action_hide_file_listing: { - item.setChecked(!item.isChecked()); - fileOperationsHelper.setHideFileListingPermissionsToPublicShare(publicShare, item.isChecked()); + case R.id.link_share_read_only: + item.setChecked(true); + fileOperationsHelper.setPermissionsToShare(publicShare, READ_PERMISSION_FLAG); + return true; + case R.id.link_share_allow_upload_and_editing: + item.setChecked(true); + if (publicShare.isFolder()) { + fileOperationsHelper.setPermissionsToShare(publicShare, MAXIMUM_PERMISSIONS_FOR_FOLDER); + } else { + fileOperationsHelper.setPermissionsToShare(publicShare, MAXIMUM_PERMISSIONS_FOR_FILE); + } + return true; + case R.id.link_share_file_drop: { + item.setChecked(true); + fileOperationsHelper.setPermissionsToShare(publicShare, CREATE_PERMISSION_FLAG); return true; } + case R.id.allow_editing: + if (file.isSharedViaLink()) { + item.setChecked(!item.isChecked()); + fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked()); + } + return true; case R.id.action_hide_file_download: item.setChecked(!item.isChecked()); fileOperationsHelper.setHideFileDownloadPermissionsToPublicShare(publicShare, item.isChecked()); - - return true; - case R.id.action_edit_label: - RenamePublicShareDialogFragment renameDialog = RenamePublicShareDialogFragment.newInstance(publicShare); - renameDialog.show(fileActivity.getSupportFragmentManager(), - RenamePublicShareDialogFragment.RENAME_PUBLIC_SHARE_FRAGMENT); return true; case R.id.action_password: { requestPasswordForShare(publicShare, @@ -502,12 +532,17 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda NoteDialogFragment noteDialog = NoteDialogFragment.newInstance(publicShare); noteDialog.show(fileActivity.getSupportFragmentManager(), NoteDialogFragment.NOTE_FRAGMENT); return true; - case R.id.action_add_another_public_share_link: - createPublicShareLink(); + case R.id.action_edit_label: + RenamePublicShareDialogFragment renameDialog = RenamePublicShareDialogFragment.newInstance(publicShare); + renameDialog.show(fileActivity.getSupportFragmentManager(), + RenamePublicShareDialogFragment.RENAME_PUBLIC_SHARE_FRAGMENT); return true; case R.id.action_unshare: fileOperationsHelper.unshareShare(file, publicShare); return true; + case R.id.action_add_another_public_share_link: + createPublicShareLink(); + return true; default: return super.onOptionsItemSelected(item); } @@ -533,6 +568,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda * Get {@link OCShare} instance from DB and updates the UI. */ private void refreshUiFromDB() { + refreshSharesFromDB(); // Updates UI with new state setupView(); } @@ -594,8 +630,12 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda * Takes into account server capabilities before reading database. */ public void refreshSharesFromDB() { - // TODO check if this is not called too often ShareeListAdapter adapter = (ShareeListAdapter) binding.sharesList.getAdapter(); + + if (adapter == null) { + DisplayUtils.showSnackMessage(getView(), getString(R.string.could_not_retrieve_shares)); + return; + } adapter.getShares().clear(); // to show share with users/groups info @@ -657,11 +697,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda (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; @@ -671,32 +706,10 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda 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; } diff --git a/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index b322511e26..9d53ccc52a 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -65,11 +65,15 @@ public final class SharingMenuHelper { /** * Sets checked/visibility state on the given {@link MenuItem} based on the given criteria. - * @param menuItem the {@link MenuItem} to be setup + * + * @param menuItem the {@link MenuItem} to be setup * @param capabilities Capabilities of server to check if hide download is supported */ - public static void setupHideFileDownload(MenuItem menuItem, boolean hideFileDownload, OCCapability capabilities) { - if (!capabilities.getVersion().isHideFileDownloadSupported()) { + public static void setupHideFileDownload(MenuItem menuItem, + boolean hideFileDownload, + boolean isFileDrop, + OCCapability capabilities) { + if (!capabilities.getVersion().isHideFileDownloadSupported() || isFileDrop) { menuItem.setVisible(false); } else { menuItem.setVisible(true); diff --git a/src/main/res/layout/password_dialog.xml b/src/main/res/layout/password_dialog.xml index 4f927a5d87..2b56382084 100644 --- a/src/main/res/layout/password_dialog.xml +++ b/src/main/res/layout/password_dialog.xml @@ -18,32 +18,20 @@ --> + android:layout_height="match_parent" + android:gravity="clip_horizontal" + android:orientation="vertical" + android:padding="@dimen/standard_padding"> - - - - - - + android:ems="10" + android:hint="@string/hint_password" + android:inputType="textPassword" + android:autofillHints="password" + android:textColorHint="@color/bg_fallback_highlight"> diff --git a/src/main/res/menu/item_user_sharing_settings.xml b/src/main/res/menu/item_user_sharing_settings.xml index 7815d6a482..090302a610 100644 --- a/src/main/res/menu/item_user_sharing_settings.xml +++ b/src/main/res/menu/item_user_sharing_settings.xml @@ -46,17 +46,6 @@ android:showAsAction="never" android:title="@string/allow_resharing" app:showAsAction="never" /> - - Allow upload and editing File drop (upload only) Video verification + Could not retrieve shares + Failed to update UI From bd3f22f65dbdbb74bc229f33e32637e1b4f4bf9e Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 8 Sep 2020 12:15:35 +0200 Subject: [PATCH 12/20] wip Signed-off-by: tobiasKaminsky --- ...agmentIT_listShares_file_allShareTypes.png | Bin 36968 -> 37350 bytes .../fragment/FileDetailSharingFragmentIT.kt | 2 -- 2 files changed, 2 deletions(-) diff --git a/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_allShareTypes.png b/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listShares_file_allShareTypes.png index 2b68676ebee7e87cd1b2dea6dfa62ddc97909094..c9634d7fc2231ac25e3fb6debfc5a6f204bba9f9 100644 GIT binary patch literal 37350 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 Xu_YH@CrSVq`Vh4{nzxH@J`Da}3f+yj literal 36968 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 R2?76U+}6H@xnUjt{{c!?)gu4^ diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index e71fcfa23d..fcdcf66537 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -168,8 +168,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { waitForIdleSync() screenshot(activity) - - longSleep() } @Test From 50c7635869e8cd096429555bdd71712710019ced Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 8 Sep 2020 12:26:52 +0200 Subject: [PATCH 13/20] wip Signed-off-by: tobiasKaminsky --- build.gradle | 42 +++++++++---------- settings.gradle | 4 +- .../fragment/FileDetailSharingFragmentIT.kt | 15 +++---- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/build.gradle b/build.gradle index b81f79df66..9cd95ade75 100644 --- a/build.gradle +++ b/build.gradle @@ -63,7 +63,7 @@ ext { markwonVersion = "4.5.1" prismVersion = "2.0.0" butterknifeVersion = "10.2.3" - androidLibraryVersion = "master-SNAPSHOT" + androidLibraryVersion = "sharingPart2-SNAPSHOT" mockitoVersion = "3.5.10" espressoVersion = "3.3.0" @@ -271,11 +271,11 @@ android { dependencies { // dependencies for app building implementation 'androidx.multidex:multidex:2.0.1' - implementation project('nextcloud-android-library') -// genericImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" -// gplayImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" -// versionDevImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" -// qaImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" +// implementation project('nextcloud-android-library') + genericImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" + gplayImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" + versionDevImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" + qaImplementation "com.github.nextcloud:android-library:$androidLibraryVersion" kapt 'javax.xml.bind:jaxb-api:2.3.1' kapt 'org.glassfish.jaxb:jaxb-core:2.3.0.1' @@ -434,21 +434,21 @@ android.applicationVariants.all { variant -> } } -//tasks.register("combinedTestReport", JacocoReport) { -// -// reports { -// xml.enabled true -// html.enabled true -// csv.enabled false -// } -// -// additionalSourceDirs.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) -// sourceDirectories.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) -// classDirectories.setFrom files(subprojects.sourceSets.main.output) -// executionData.setFrom project.fileTree(dir: project.buildDir, includes: [ -// 'jacoco/testGplayDebugUnitTest.exec', 'outputs/code-coverage/connected/flavors/GPLAY/*coverage.ec' -// ]) -//} +tasks.register("combinedTestReport", JacocoReport) { + + reports { + xml.enabled true + html.enabled true + csv.enabled false + } + + additionalSourceDirs.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) + sourceDirectories.setFrom files(subprojects.sourceSets.main.allSource.srcDirs) + classDirectories.setFrom files(subprojects.sourceSets.main.output) + executionData.setFrom project.fileTree(dir: project.buildDir, includes: [ + 'jacoco/testGplayDebugUnitTest.exec', 'outputs/code-coverage/connected/flavors/GPLAY/*coverage.ec' + ]) +} task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." diff --git a/settings.gradle b/settings.gradle index c95103a34f..520b64d902 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -//include ':' -include ':nextcloud-android-library' +include ':' +//include ':nextcloud-android-library' diff --git a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index fcdcf66537..37df25e4c4 100644 --- a/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -94,7 +94,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 1 shareType = ShareType.USER sharedWithDisplayName = "Admin" - permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + permissions = MAXIMUM_PERMISSIONS_FOR_FILE userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -103,7 +103,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 2 shareType = ShareType.GROUP sharedWithDisplayName = "Group" - permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + permissions = MAXIMUM_PERMISSIONS_FOR_FILE userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -143,7 +143,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 7 shareType = ShareType.CIRCLE sharedWithDisplayName = "Private circle" - permissions = OCShare.SHARE_PERMISSION_FLAG + permissions = SHARE_PERMISSION_FLAG userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -152,7 +152,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { remoteId = 8 shareType = ShareType.ROOM sharedWithDisplayName = "Meeting" - permissions = OCShare.SHARE_PERMISSION_FLAG + permissions = SHARE_PERMISSION_FLAG userId = getUserId(user) activity.storageManager.saveShare(this) } @@ -205,7 +205,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked) // upload and editing - publicShare.permissions = OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked) assertTrue(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked) @@ -231,6 +231,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // hide download publicShare.isHideFileDownload = true + publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER sut.prepareLinkOptionsMenu(popup.menu, publicShare) assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked) @@ -250,7 +251,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // file publicShare.isFolder = false - publicShare.permissions = OCShare.READ_PERMISSION_FLAG + publicShare.permissions = READ_PERMISSION_FLAG sut.prepareLinkOptionsMenu(popup.menu, publicShare) // check if items are visible assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible) @@ -376,7 +377,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { targetContext.getString(R.string.share_no_expiration_date_label)) publicShare.isFolder = false - publicShare.permissions = OCShare.READ_PERMISSION_FLAG + publicShare.permissions = READ_PERMISSION_FLAG sut.prepareLinkOptionsMenu(popup.menu, publicShare) // allow editing From a6c898d2a529be9c2434458cfb7beca2a5a99629 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 8 Sep 2020 12:38:44 +0200 Subject: [PATCH 14/20] cleanup Signed-off-by: tobiasKaminsky --- .idea/codeStyles/Project.xml | 11 +++++++++- .../datamodel/FileDataStorageManager.java | 2 -- .../com/owncloud/android/db/ProviderMeta.java | 3 +-- .../UpdateShareViaLinkOperation.java | 6 ------ .../providers/FileContentProvider.java | 21 +------------------ .../android/services/OperationsService.java | 1 - .../ui/fragment/FileDetailFragment.java | 1 - 7 files changed, 12 insertions(+), 33 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index c0f22925f1..ddd7897986 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -56,7 +56,16 @@ +