Merge pull request #1613 from rhari991/file-list-actions

Add options for operations on single files
This commit is contained in:
Andy Scherzinger 2017-10-18 22:22:13 +02:00 committed by GitHub
commit 620f9db9b5
23 changed files with 185 additions and 70 deletions

View file

@ -52,6 +52,7 @@ public class FileMenuFilter {
private ComponentsGetter mComponentsGetter;
private Account mAccount;
private Context mContext;
private boolean mOverflowMenu;
/**
* Constructor
@ -61,14 +62,16 @@ public class FileMenuFilter {
* @param account ownCloud {@link Account} holding targetFile.
* @param cg Accessor to app components, needed to access synchronization services
* @param context Android {@link Context}, needed to access build setup resources.
* @param overflowMenu true if the overflow menu items are being filtered
*/
public FileMenuFilter(int numberOfAllFiles, Collection<OCFile> targetFiles, Account account,
ComponentsGetter cg, Context context) {
ComponentsGetter cg, Context context, boolean overflowMenu) {
mNumberOfAllFiles = numberOfAllFiles;
mFiles = targetFiles;
mAccount = account;
mComponentsGetter = cg;
mContext = context;
mOverflowMenu = overflowMenu;
}
/**
@ -78,9 +81,11 @@ public class FileMenuFilter {
* @param account ownCloud {@link Account} holding targetFile.
* @param cg Accessor to app components, needed to access synchronization services
* @param context Android {@link Context}, needed to access build setup resources.
* @param overflowMenu true if the overflow menu items are being filtered
*/
public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context) {
this(1, Collections.singletonList(targetFile), account, cg, context);
public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context,
boolean overflowMenu) {
this(1, Collections.singletonList(targetFile), account, cg, context, overflowMenu);
}
/**
@ -178,7 +183,7 @@ public class FileMenuFilter {
// SELECT ALL
if (!inSingleFileFragment) {
// Show only if at least one item isn't selected.
if (mFiles.size() >= mNumberOfAllFiles) {
if (mFiles.size() >= mNumberOfAllFiles || mOverflowMenu) {
toHide.add(R.id.action_select_all_action_menu);
} else {
toShow.add(R.id.action_select_all_action_menu);
@ -191,7 +196,7 @@ public class FileMenuFilter {
// DESELECT ALL
if (!inSingleFileFragment) {
// Show only if at least one item is selected.
if (mFiles.isEmpty()) {
if (mFiles.isEmpty() || mOverflowMenu) {
toHide.add(R.id.action_deselect_all_action_menu);
} else {
toShow.add(R.id.action_deselect_all_action_menu);
@ -235,7 +240,8 @@ public class FileMenuFilter {
(capability.getFilesSharingApiEnabled().isTrue() ||
capability.getFilesSharingApiEnabled().isUnknown()
);
if ((!shareViaLinkAllowed && !shareWithUsersAllowed) || !isSingleSelection() || !shareApiEnabled) {
if ((!shareViaLinkAllowed && !shareWithUsersAllowed) ||
!isSingleSelection() || !shareApiEnabled || mOverflowMenu) {
toHide.add(R.id.action_share_file);
} else {
toShow.add(R.id.action_share_file);

View file

@ -26,7 +26,6 @@ package com.owncloud.android.ui.adapter;
import android.accounts.Account;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Handler;
@ -62,8 +61,6 @@ import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.operations.RemoteOperationFailedException;
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
import com.owncloud.android.ui.activity.ComponentsGetter;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.ShareActivity;
import com.owncloud.android.ui.fragment.ExtendedListFragment;
import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface;
import com.owncloud.android.utils.DisplayUtils;
@ -234,10 +231,6 @@ public class FileListListAdapter extends BaseAdapter {
if (file != null) {
ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);
if (file.isSharedWithSharee() || file.isSharedWithMe()) {
sharedIconV.setImageResource(R.drawable.shared_via_users);
}
fileIcon.setTag(file.getFileId());
TextView fileName;
@ -258,21 +251,6 @@ public class FileListListAdapter extends BaseAdapter {
fileSizeV.setVisibility(View.VISIBLE);
fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
// Shared icon clickable
if (file.isSharedViaLink() || file.isSharedWithSharee()) {
final OCFile temp = file;
sharedIconV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, ShareActivity.class);
intent.putExtra(FileActivity.EXTRA_FILE, temp);
intent.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
mContext.startActivity(intent);
}
});
}
case GRID_ITEM:
// filename
fileName = (TextView) view.findViewById(R.id.Filename);
@ -284,16 +262,6 @@ public class FileListListAdapter extends BaseAdapter {
}
case GRID_IMAGE:
// sharedIcon
if (file.isSharedViaLink()) {
sharedIconV.setVisibility(View.VISIBLE);
sharedIconV.bringToFront();
} else if (file.isSharedWithSharee() || file.isSharedWithMe()) {
sharedIconV.setVisibility(View.VISIBLE);
sharedIconV.bringToFront();
} else {
sharedIconV.setVisibility(View.GONE);
}
// local state
ImageView localStateView = (ImageView) view.findViewById(R.id.localFileIndicator);
@ -340,7 +308,6 @@ public class FileListListAdapter extends BaseAdapter {
}
ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
checkBoxV.setVisibility(View.GONE);
view.setBackgroundColor(Color.WHITE);
AbsListView parentList = (AbsListView) parent;
@ -355,6 +322,12 @@ public class FileListListAdapter extends BaseAdapter {
checkBoxV.setImageResource(R.drawable.ic_checkbox_blank_outline);
}
checkBoxV.setVisibility(View.VISIBLE);
hideShareIcon(view);
hideOverflowMenuIcon(view, viewType);
} else {
checkBoxV.setVisibility(View.GONE);
showShareIcon(view, file);
showOverflowMenuIcon(view, file, viewType);
}
// this if-else is needed even though kept-in-sync icon is visible by default
@ -430,6 +403,48 @@ public class FileListListAdapter extends BaseAdapter {
return view;
}
private void showShareIcon(View view, OCFile file) {
ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);
sharedIconV.setVisibility(View.VISIBLE);
if (file.isSharedWithSharee() || file.isSharedWithMe()) {
sharedIconV.setImageResource(R.drawable.shared_via_users);
} else if (file.isSharedViaLink()) {
sharedIconV.setImageResource(R.drawable.shared_via_link);
} else {
sharedIconV.setImageResource(R.drawable.ic_unshared);
}
sharedIconV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
OCFileListFragmentInterface.onShareIconClick(file);
}
});
}
private void hideShareIcon(View view) {
view.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
}
private void showOverflowMenuIcon(View view, OCFile file, ViewType viewType) {
if (ViewType.LIST_ITEM.equals(viewType)) {
ImageView overflowIndicatorV = (ImageView) view.findViewById(R.id.overflow_menu);
overflowIndicatorV.setVisibility(View.VISIBLE);
overflowIndicatorV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
OCFileListFragmentInterface.onOverflowIconClick(v, file);
}
});
}
}
private void hideOverflowMenuIcon(View view, ViewType viewType) {
if (ViewType.LIST_ITEM.equals(viewType)) {
ImageView overflowIndicatorV = (ImageView) view.findViewById(R.id.overflow_menu);
overflowIndicatorV.setVisibility(View.GONE);
}
}
@Override
public int getViewTypeCount() {
return 1;

View file

@ -178,6 +178,7 @@ public class LocalFileListAdapter extends BaseAdapter implements FilterableListA
TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
lastModV.setVisibility(View.VISIBLE);
lastModV.setText(DisplayUtils.getRelativeTimestamp(mContext, file.lastModified()));
view.findViewById(R.id.overflow_menu).setVisibility(View.GONE);
}
if (!file.isDirectory()) {

View file

@ -216,7 +216,8 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
getActivity()
getActivity(),
false
);
mf.filter(menu, true);
}

View file

@ -53,6 +53,7 @@ import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
@ -107,6 +108,7 @@ import org.parceler.Parcels;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -513,6 +515,34 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
updateFooter();
}
@Override
public void onShareIconClick(OCFile file) {
shareFile(file);
}
@Override
public void onOverflowIconClick(View view, OCFile file) {
PopupMenu popup = new PopupMenu(getActivity(), view);
popup.inflate(R.menu.file_actions_menu);
FileMenuFilter mf = new FileMenuFilter(
mAdapter.getFiles().size(),
Collections.singleton(file),
((FileActivity) getActivity()).getAccount(),
mContainerActivity,
getActivity(),
true
);
mf.filter(popup.getMenu(), true);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
ArrayList<OCFile> checkedFiles = new ArrayList<>(Collections.singletonList(file));
return onFileActionChosen(item.getItemId(), checkedFiles);
}
});
popup.show();
}
/**
* Handler for multiple selection mode.
*
@ -632,7 +662,8 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
checkedFiles,
((FileActivity) getActivity()).getAccount(),
mContainerActivity,
getActivity()
getActivity(),
false
);
mf.filter(menu, false);
return true;
@ -643,7 +674,8 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
*/
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return onFileActionChosen(item.getItemId());
ArrayList<OCFile> checkedFiles = mAdapter.getCheckedItems(getListView());
return onFileActionChosen(item.getItemId(), checkedFiles);
}
/**
@ -902,10 +934,10 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
* Start the appropriate action(s) on the currently selected files given menu selected by the user.
*
* @param menuId Identifier of the action menu selected by the user
* @param checkedFiles List of files selected by the user on which the action should be performed
* @return 'true' if the menu selection started any action, 'false' otherwise.
*/
public boolean onFileActionChosen(int menuId) {
final ArrayList<OCFile> checkedFiles = mAdapter.getCheckedItems(getListView());
public boolean onFileActionChosen(int menuId, ArrayList<OCFile> checkedFiles) {
if (checkedFiles.size() <= 0) {
return false;
}
@ -915,11 +947,7 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
OCFile singleFile = checkedFiles.get(0);
switch (menuId) {
case R.id.action_share_file: {
if(singleFile.isSharedWithMe() && !singleFile.canReshare()){
Snackbar.make(getView(), R.string.resharing_is_not_allowed, Snackbar.LENGTH_LONG).show();
} else {
mContainerActivity.getFileOperationsHelper().showShareFile(singleFile);
}
shareFile(singleFile);
return true;
}
case R.id.action_open_file_with: {
@ -1019,6 +1047,14 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
}
}
private void shareFile(OCFile file) {
if(file.isSharedWithMe() && !file.canReshare()){
Snackbar.make(getView(), R.string.resharing_is_not_allowed, Snackbar.LENGTH_LONG).show();
} else {
mContainerActivity.getFileOperationsHelper().showShareFile(file);
}
}
/**
* Use this to query the {@link OCFile} that is currently
* being displayed by this fragment

View file

@ -20,12 +20,21 @@
*/
package com.owncloud.android.ui.interfaces;
import android.view.View;
import com.owncloud.android.datamodel.OCFile;
/**
* Interface for signaling filter finish
* Interface for communication between {@link com.owncloud.android.ui.fragment.OCFileListFragment}
* and {@link com.owncloud.android.ui.adapter.FileListListAdapter}
*/
public interface OCFileListFragmentInterface {
void finishedFiltering();
int getColumnSize();
void onShareIconClick(OCFile file);
void onOverflowIconClick(View view, OCFile file);
}

View file

@ -275,7 +275,8 @@ public class PreviewImageFragment extends FileFragment {
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
getActivity()
getActivity(),
false
);
mf.filter(menu, true);
}

View file

@ -375,7 +375,8 @@ public class PreviewMediaFragment extends FileFragment implements
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
getActivity()
getActivity(),
false
);
mf.filter(menu, true);
}

View file

@ -285,7 +285,8 @@ public class PreviewTextFragment extends FileFragment {
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
getActivity()
getActivity(),
false
);
mf.filter(menu, true);
}

View file

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 940 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 992 B

View file

Before

Width:  |  Height:  |  Size: 634 B

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 B

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16.0"
android:viewportHeight="16.0">
<path
android:fillColor="#FF000000"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.2"
android:strokeMiterLimit="4"
android:pathData="M5.99 5.318a3.332 3.332 0 0 0 0 4.693c 0.116 0.118 0.226 0.22 0.355 0.315l1.383-1.383A1.4 1.4 0 0 1 7.33 6.66l3.352-3.352c 0.568-0.57 1.442-0.57 2.01 0s 0.57 1.442 0 2.01l-1.13 1.132c 0.34 0.725 0.464 1.518 0.377 2.304l2.094-2.095c1.288-1.29 1.288-3.406 0-4.694s-3.405-1.288-4.693 0L5.99 5.318z"/>
<path
android:fillColor="#FF000000"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.2"
android:strokeMiterLimit="4"
android:pathData="M10.01 10.68a3.332 3.332 0 0 0 0-4.692 3.126 3.126 0 0 0-0.355-0.314L8.272 7.057A1.4 1.4 0 0 1 8.67 9.34l-3.35 3.35c-0.57 0.57-1.444 0.57-2.013 0.002s-0.568-1.442 0-2.01L4.44 9.55a4.288 4.288 0 0 1-0.38-2.305L1.967 9.34c-1.288 1.29-1.288 3.405 0 4.693s3.405 1.29 4.693 0l3.35-3.352z"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16.0"
android:viewportHeight="16.0">
<path
android:fillColor="#FF000000"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.2"
android:strokeMiterLimit="4"
android:pathData="M12.228 1a2.457 2.457 0 0 0-2.46 2.454c0 0.075 0.01 0.15 0.016 0.224L5.05 6.092a2.445 2.445 0 0 0-1.596-0.586A2.453 2.453 0 0 0 1 7.96a2.453 2.453 0 0 0 2.454 2.455 2.45 2.45 0 0 0 1.46-0.477l4.865 2.474c-0.004 0.044-0.01 0.09-0.01 0.134a2.457 2.457 0 1 0 0.804-1.818l-4.696-2.4c 0.02-0.123 0.035-0.25 0.035-0.378 0-0.072-0.01-0.144-0.015-0.214l4.74-2.414A2.457 2.457 0 1 0 12.228 0.99z"/>
</vector>

View file

@ -30,7 +30,6 @@
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="72dp"
android:layout_height="@dimen/standard_list_item_size"
@ -53,9 +52,8 @@
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginRight="4dp"
android:src="@drawable/ic_favorite"
/>
android:contentDescription="@string/favorite_switch"
android:src="@drawable/ic_favorite" />
<ImageView
android:id="@+id/keptOfflineIcon"
@ -74,6 +72,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:scaleType="fitCenter"
android:contentDescription="@string/downloader_download_succeeded_ticker"
android:layout_marginRight="4dp"/>
</RelativeLayout>
@ -141,36 +140,50 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="@dimen/standard_padding">
android:paddingLeft="@dimen/alternate_padding"
android:paddingRight="@dimen/alternate_padding">
<ImageView
android:id="@+id/sharedIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/standard_quarter_margin"
android:layout_marginLeft="@dimen/standard_quarter_margin"
android:layout_marginBottom="@dimen/standard_quarter_margin"
android:layout_marginRight="@dimen/standard_quarter_margin"
android:src="@drawable/shared_via_link" />
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/list_item_share_right_margin"
android:padding="@dimen/standard_quarter_padding"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_unshared" />
<ImageView
android:id="@+id/custom_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/standard_quarter_margin"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/standard_half_margin"
android:layout_marginRight="@dimen/standard_half_margin"
android:layout_toRightOf="@id/sharedIcon"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_checkbox_blank_outline" />
<ImageView
android:id="@+id/overflow_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/standard_half_margin"
android:layout_toRightOf="@id/custom_checkbox"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_dots_vertical" />
android:src="@drawable/ic_checkbox_blank_outline"
android:layout_toRightOf="@id/sharedIcon"/>
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/list_divider_background"></View>
android:background="@color/list_divider_background" />
</LinearLayout>

View file

@ -47,6 +47,7 @@
<dimen name="two_line_secondary_text_size">14sp</dimen>
<dimen name="list_item_avatar_icon_margin">20dp</dimen>
<dimen name="list_item_avatar_text_margin">20dp</dimen>
<dimen name="list_item_share_right_margin">10dp</dimen>
<dimen name="account_action_layout_height">72dp</dimen>
<dimen name="zero">0dp</dimen>
<dimen name="account_item_layout_height">72dp</dimen>