package com.simplemobiletools.filemanager.fragments; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.res.Resources; import android.graphics.Color; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.Nullable; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.webkit.MimeTypeMap; import android.widget.AdapterView; import android.widget.ListView; import com.simplemobiletools.filemanager.Config; import com.simplemobiletools.filemanager.Constants; import com.simplemobiletools.filemanager.R; import com.simplemobiletools.filemanager.Utils; import com.simplemobiletools.filemanager.adapters.ItemsAdapter; import com.simplemobiletools.filemanager.asynctasks.CopyTask; import com.simplemobiletools.filemanager.dialogs.CopyDialog; import com.simplemobiletools.filemanager.dialogs.CreateNewItemDialog; import com.simplemobiletools.filemanager.dialogs.PropertiesDialog; import com.simplemobiletools.filemanager.dialogs.RenameItemDialog; import com.simplemobiletools.filepicker.models.FileDirItem; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class ItemsFragment extends android.support.v4.app.Fragment implements AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener, ListView.MultiChoiceModeListener, ListView.OnTouchListener, CopyTask.CopyListener { @BindView(R.id.items_list) ListView mListView; @BindView(R.id.items_swipe_refresh) SwipeRefreshLayout mSwipeRefreshLayout; @BindView(R.id.items_holder) CoordinatorLayout mCoordinatorLayout; private static Map mStates; private List mItems; private ItemInteractionListener mListener; private List mToBeDeleted; private String mPath; private Snackbar mSnackbar; private Config mConfig; private boolean mShowHidden; private int mSelectedItemsCnt; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.items_fragment, container, false); ButterKnife.bind(this, view); return view; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (mStates == null) mStates = new HashMap<>(); mConfig = Config.newInstance(getContext()); mShowHidden = mConfig.getShowHidden(); mItems = new ArrayList<>(); mToBeDeleted = new ArrayList<>(); fillItems(); mSwipeRefreshLayout.setOnRefreshListener(this); } @Override public void onResume() { super.onResume(); if (mShowHidden != mConfig.getShowHidden()) { mShowHidden = !mShowHidden; mStates.remove(mPath); fillItems(); } } @Override public void onPause() { super.onPause(); deleteItems(); mStates.put(mPath, mListView.onSaveInstanceState()); } private void fillItems() { mPath = getArguments().getString(Constants.PATH); final List newItems = getItems(mPath); Collections.sort(newItems); if (mItems != null && newItems.toString().equals(mItems.toString())) { return; } mItems = newItems; final ItemsAdapter adapter = new ItemsAdapter(getContext(), mItems); mListView.setAdapter(adapter); mListView.setOnItemClickListener(this); mListView.setMultiChoiceModeListener(this); mListView.setOnTouchListener(this); if (mStates != null && mStates.get(mPath) != null) { mListView.onRestoreInstanceState(mStates.get(mPath)); } } public void setListener(ItemInteractionListener listener) { mListener = listener; } private List getItems(String path) { final List items = new ArrayList<>(); final File base = new File(path); File[] files = base.listFiles(); if (files != null) { for (File file : files) { final String curPath = file.getAbsolutePath(); final String curName = Utils.getFilename(curPath); if (!mShowHidden && curName.startsWith(".")) continue; if (mToBeDeleted.contains(curPath)) continue; int children = getChildren(file); long size = file.length(); items.add(new FileDirItem(curPath, curName, file.isDirectory(), children, size)); } } return items; } private int getChildren(File file) { if (file.listFiles() == null) return 0; if (file.isDirectory()) { if (mShowHidden) { return file.listFiles().length; } else { return file.listFiles(new FileFilter() { @Override public boolean accept(File file) { return !file.isHidden(); } }).length; } } return 0; } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { final FileDirItem item = mItems.get(position); if (item.isDirectory()) { if (mListener != null) mListener.itemClicked(item); } else { final String path = item.getPath(); final File file = new File(path); String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(Utils.getFileExtension(path)); if (mimeType == null) mimeType = "text/plain"; final Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), mimeType); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(intent); } catch (ActivityNotFoundException e) { if (!tryGenericMimeType(intent, mimeType, file)) { Utils.showToast(getContext(), R.string.no_app_found); } } } } private boolean tryGenericMimeType(Intent intent, String mimeType, File file) { final String genericMimeType = getGenericMimeType(mimeType); intent.setDataAndType(Uri.fromFile(file), genericMimeType); try { startActivity(intent); return true; } catch (ActivityNotFoundException e) { return false; } } @OnClick(R.id.items_fab) public void fabClicked(View view) { new CreateNewItemDialog(getContext(), mPath, new CreateNewItemDialog.OnCreateNewItemListener() { @Override public void onSuccess() { fillItems(); } }); } @Override public void onRefresh() { fillItems(); mSwipeRefreshLayout.setRefreshing(false); } private String getGenericMimeType(String mimeType) { if (!mimeType.contains("/")) return mimeType; final String type = mimeType.substring(0, mimeType.indexOf("/")); return type + "/*"; } @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { mSelectedItemsCnt++; } else { mSelectedItemsCnt--; } if (mSelectedItemsCnt > 0) { mode.setTitle(String.valueOf(mSelectedItemsCnt)); } mode.invalidate(); } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.cab, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { MenuItem menuItem = menu.findItem(R.id.cab_rename); menuItem.setVisible(mSelectedItemsCnt == 1); return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.cab_rename: displayRenameDialog(); mode.finish(); break; case R.id.cab_properties: displayPropertiesDialog(); break; case R.id.cab_share: shareFiles(); break; case R.id.cab_copy: displayCopyDialog(); mode.finish(); break; case R.id.cab_delete: prepareForDeleting(); mode.finish(); break; default: return false; } return true; } private void shareFiles() { final List itemIndexes = getSelectedItemIndexes(); if (itemIndexes.isEmpty()) return; final ArrayList uris = new ArrayList<>(itemIndexes.size()); for (int i : itemIndexes) { final File file = new File(mItems.get(i).getPath()); if (!file.isDirectory()) uris.add(Uri.fromFile(file)); } if (uris.isEmpty()) { Utils.showToast(getContext(), R.string.no_files_selected); return; } final String shareTitle = getResources().getString(R.string.share_via); final Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE); sendIntent.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.shared_files)); sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); sendIntent.setType("*/*"); startActivity(Intent.createChooser(sendIntent, shareTitle)); } private void displayPropertiesDialog() { final List itemIndexes = getSelectedItemIndexes(); if (itemIndexes.isEmpty()) return; if (itemIndexes.size() == 1) { showOneItemProperties(); } else { showMultipleItemProperties(itemIndexes); } } private void showOneItemProperties() { final FileDirItem item = getSelectedItem(); if (item == null) return; new PropertiesDialog(getContext(), item.getPath(), mConfig.getShowHidden()); } private void showMultipleItemProperties(List itemIndexes) { final List paths = new ArrayList<>(itemIndexes.size()); for (int i : itemIndexes) { paths.add(mItems.get(i).getPath()); } new PropertiesDialog(getContext(), paths, mConfig.getShowHidden()); } private void displayRenameDialog() { final FileDirItem item = getSelectedItem(); if (item == null) return; new RenameItemDialog(getContext(), mPath, item, new RenameItemDialog.OnRenameItemListener() { @Override public void onSuccess() { fillItems(); } }); } private void displayCopyDialog() { final List itemIndexes = getSelectedItemIndexes(); if (itemIndexes.isEmpty()) return; final List itemsToCopy = new ArrayList<>(itemIndexes.size()); for (Integer i : itemIndexes) { FileDirItem item = mItems.get(i); itemsToCopy.add(new File(item.getPath())); } new CopyDialog(getActivity(), itemsToCopy, mPath, this, new CopyDialog.OnCopyListener() { @Override public void onSuccess() { fillItems(); } }); } private FileDirItem getSelectedItem() { final List itemIndexes = getSelectedItemIndexes(); if (itemIndexes.isEmpty()) return null; final int itemIndex = itemIndexes.get(0); return mItems.get(itemIndex); } private List getSelectedItemIndexes() { final List selectedItems = new ArrayList<>(); final SparseBooleanArray items = mListView.getCheckedItemPositions(); int cnt = items.size(); for (int i = 0; i < cnt; i++) { if (items.valueAt(i)) { selectedItems.add(items.keyAt(i)); } } return selectedItems; } private void prepareForDeleting() { mToBeDeleted.clear(); final SparseBooleanArray items = mListView.getCheckedItemPositions(); final int cnt = items.size(); int deletedCnt = 0; for (int i = 0; i < cnt; i++) { if (items.valueAt(i)) { final int id = items.keyAt(i); final String path = mItems.get(id).getPath(); mToBeDeleted.add(path); deletedCnt++; } } notifyDeletion(deletedCnt); } private void notifyDeletion(int cnt) { final Resources res = getResources(); final String msg = res.getQuantityString(R.plurals.items_deleted, cnt, cnt); mSnackbar = Snackbar.make(mCoordinatorLayout, msg, Snackbar.LENGTH_INDEFINITE); mSnackbar.setAction(res.getString(R.string.undo), undoDeletion); mSnackbar.setActionTextColor(Color.WHITE); mSnackbar.show(); fillItems(); } @Override public boolean onTouch(View v, MotionEvent event) { if (mSnackbar != null && mSnackbar.isShown()) { deleteItems(); } return false; } private void deleteItems() { if (mToBeDeleted == null || mToBeDeleted.isEmpty()) return; if (mSnackbar != null) { mSnackbar.dismiss(); } for (String delPath : mToBeDeleted) { final File file = new File(delPath); if (file.exists()) { deleteItem(file); } } mToBeDeleted.clear(); } private void rescanItem(File item) { if (item.isDirectory()) { for (File child : item.listFiles()) { rescanItem(child); } } MediaScannerConnection.scanFile(getContext(), new String[]{item.getAbsolutePath()}, null, null); } private void deleteItem(File item) { if (item.isDirectory()) { for (File child : item.listFiles()) { deleteItem(child); } } item.delete(); MediaScannerConnection.scanFile(getContext(), new String[]{item.getAbsolutePath()}, null, null); } private View.OnClickListener undoDeletion = new View.OnClickListener() { @Override public void onClick(View v) { mToBeDeleted.clear(); mSnackbar.dismiss(); fillItems(); } }; @Override public void onDestroyActionMode(ActionMode mode) { mSelectedItemsCnt = 0; } @Override public void copySucceeded(File file) { rescanItem(file); fillItems(); } @Override public void copyFailed() { Utils.showToast(getContext(), R.string.copy_failed); } public interface ItemInteractionListener { void itemClicked(FileDirItem item); } }