package org.wordpress.android.ui.photopicker; import android.app.Fragment; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ActionMode; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.PopupMenu; import org.wordpress.android.R; import org.wordpress.android.ui.photopicker.PhotoPickerAdapter.PhotoPickerAdapterListener; import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; public class PhotoPickerFragment extends Fragment { static final int NUM_COLUMNS = 3; public enum PhotoPickerIcon { ANDROID_CHOOSE_PHOTO, ANDROID_CHOOSE_VIDEO, ANDROID_CAPTURE_PHOTO, ANDROID_CAPTURE_VIDEO, WP_MEDIA } public enum PhotoPickerOption { ALLOW_MULTI_SELECT, // allow selecting more than one item PHOTOS_ONLY, // show only photos (no videos) DEVICE_ONLY // no WP media } /* * parent activity must implement this listener */ public interface PhotoPickerListener { void onPhotoPickerMediaChosen(@NonNull List<Uri> uriList); void onPhotoPickerIconClicked(@NonNull PhotoPickerIcon icon); } private RecyclerView mRecycler; private PhotoPickerAdapter mAdapter; private View mBottomBar; private ActionMode mActionMode; private GridLayoutManager mGridManager; private Parcelable mRestoreState; private PhotoPickerListener mListener; private boolean mAllowMultiSelect; private boolean mPhotosOnly; private boolean mDeviceOnly; private static final String ARG_ALLOW_MULTI_SELECT = "allow_multi_select"; private static final String ARG_PHOTOS_ONLY = "photos_only"; private static final String ARG_DEVICE_ONLY = "device_only"; public static PhotoPickerFragment newInstance(@NonNull PhotoPickerListener listener, EnumSet<PhotoPickerOption> options) { Bundle args = new Bundle(); PhotoPickerFragment fragment = new PhotoPickerFragment(); fragment.setPhotoPickerListener(listener); if (options != null) { args.putBoolean(ARG_ALLOW_MULTI_SELECT, options.contains(PhotoPickerOption.ALLOW_MULTI_SELECT)); args.putBoolean(ARG_PHOTOS_ONLY, options.contains(PhotoPickerOption.PHOTOS_ONLY)); args.putBoolean(ARG_DEVICE_ONLY, options.contains(PhotoPickerOption.DEVICE_ONLY)); } fragment.setArguments(args); return fragment; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mAllowMultiSelect = savedInstanceState.getBoolean(ARG_ALLOW_MULTI_SELECT, false); mPhotosOnly = savedInstanceState.getBoolean(ARG_PHOTOS_ONLY, false); mDeviceOnly = savedInstanceState.getBoolean(ARG_DEVICE_ONLY, false); } } @Override public void setArguments(Bundle args) { super.setArguments(args); mAllowMultiSelect = args != null && args.getBoolean(ARG_ALLOW_MULTI_SELECT); mPhotosOnly = args != null && args.getBoolean(ARG_PHOTOS_ONLY); mDeviceOnly = args != null && args.getBoolean(ARG_DEVICE_ONLY); } @Override public void onSaveInstanceState(Bundle outState) { outState.putBoolean(ARG_ALLOW_MULTI_SELECT, mAllowMultiSelect); outState.putBoolean(ARG_PHOTOS_ONLY, mPhotosOnly); outState.putBoolean(ARG_DEVICE_ONLY, mDeviceOnly); super.onSaveInstanceState(outState); } public void setOptions(EnumSet<PhotoPickerOption> options) { mAllowMultiSelect = options != null && options.contains(PhotoPickerOption.ALLOW_MULTI_SELECT); mPhotosOnly = options != null && options.contains(PhotoPickerOption.PHOTOS_ONLY); if (hasAdapter()) { getAdapter().setAllowMultiSelect(mAllowMultiSelect); getAdapter().setShowPhotosOnly(mPhotosOnly); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.photo_picker_fragment, container, false); mRecycler = (RecyclerView) view.findViewById(R.id.recycler); mRecycler.setHasFixedSize(true); mBottomBar = view.findViewById(R.id.bottom_bar); mBottomBar.findViewById(R.id.icon_camera).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mPhotosOnly) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.ANDROID_CAPTURE_PHOTO); } } else { showCameraPopupMenu(v); } } }); mBottomBar.findViewById(R.id.icon_picker).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mPhotosOnly) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.ANDROID_CHOOSE_PHOTO); } } else { showPickerPopupMenu(v); } } }); View wpMediaIcon = mBottomBar.findViewById(R.id.icon_wpmedia); if (mDeviceOnly) { wpMediaIcon.setVisibility(View.GONE); } else { wpMediaIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.WP_MEDIA); } } }); } reload(); return view; } private void showPickerPopupMenu(@NonNull View view) { PopupMenu popup = new PopupMenu(getActivity(), view); MenuItem itemPhoto = popup.getMenu().add(R.string.photo_picker_choose_photo); itemPhoto.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.ANDROID_CHOOSE_PHOTO); } return true; } }); MenuItem itemVideo = popup.getMenu().add(R.string.photo_picker_choose_video); itemVideo.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.ANDROID_CHOOSE_VIDEO); } return true; } }); popup.show(); } private void showCameraPopupMenu(@NonNull View view) { PopupMenu popup = new PopupMenu(getActivity(), view); MenuItem itemPhoto = popup.getMenu().add(R.string.photo_picker_capture_photo); itemPhoto.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.ANDROID_CAPTURE_PHOTO); } return true; } }); MenuItem itemVideo = popup.getMenu().add(R.string.photo_picker_capture_video); itemVideo.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (mListener != null) { mListener.onPhotoPickerIconClicked(PhotoPickerIcon.ANDROID_CAPTURE_VIDEO); } return true; } }); popup.show(); } void setPhotoPickerListener(PhotoPickerListener listener) { mListener = listener; } private void showBottomBar() { if (!isBottomBarShowing()) { AniUtils.animateBottomBar(mBottomBar, true); } } private void hideBottomBar() { if (isBottomBarShowing()) { AniUtils.animateBottomBar(mBottomBar, false); } } private boolean isBottomBarShowing() { return mBottomBar.getVisibility() == View.VISIBLE; } private final PhotoPickerAdapterListener mAdapterListener = new PhotoPickerAdapterListener() { @Override public void onItemTapped(Uri mediaUri) { if (mListener != null) { List<Uri> uriList = new ArrayList<>(); uriList.add(mediaUri); mListener.onPhotoPickerMediaChosen(uriList); } } @Override public void onSelectedCountChanged(int count) { if (count == 0) { finishActionMode(); } else { if (mActionMode == null) { ((AppCompatActivity) getActivity()).startSupportActionMode(new ActionModeCallback()); } updateActionModeTitle(); } } @Override public void onAdapterLoaded(boolean isEmpty) { showEmptyView(isEmpty); if (mRestoreState != null) { mGridManager.onRestoreInstanceState(mRestoreState); mRestoreState = null; } } }; private void showEmptyView(boolean show) { if (isAdded()) { getView().findViewById(R.id.text_empty).setVisibility(show ? View.VISIBLE : View.GONE); } } private boolean hasAdapter() { return mAdapter != null; } private PhotoPickerAdapter getAdapter() { if (mAdapter == null) { mAdapter = new PhotoPickerAdapter(getActivity(), mAdapterListener); mAdapter.setAllowMultiSelect(mAllowMultiSelect); mAdapter.setShowPhotosOnly(mPhotosOnly); } return mAdapter; } /* * populates the adapter with media stored on the device */ public void reload() { if (!isAdded()) { AppLog.w(AppLog.T.POSTS, "Photo picker > can't reload when not added"); return; } // save the current state so we can restore it after loading if (mGridManager != null) { mRestoreState = mGridManager.onSaveInstanceState(); } mGridManager = new GridLayoutManager(getActivity(), NUM_COLUMNS); mRecycler.setLayoutManager(mGridManager); mRecycler.setAdapter(getAdapter()); getAdapter().refresh(true); } /* * similar to the above but only repopulates if changes are detected */ public void refresh() { if (!isAdded()) { AppLog.w(AppLog.T.POSTS, "Photo picker > can't refresh when not added"); return; } if (mGridManager == null || mAdapter == null) { reload(); } else { getAdapter().refresh(false); } } public void finishActionMode() { if (mActionMode != null) { mActionMode.finish(); } } private void updateActionModeTitle() { if (mActionMode == null) return; int numSelected = getAdapter().getNumSelected(); String title = String.format(getString(R.string.cab_selected), numSelected); mActionMode.setTitle(title); } private final class ActionModeCallback implements ActionMode.Callback { @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { mActionMode = actionMode; MenuInflater inflater = actionMode.getMenuInflater(); inflater.inflate(R.menu.photo_picker_action_mode, menu); hideBottomBar(); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == R.id.mnu_confirm_selection && mListener != null) { ArrayList<Uri> uriList = getAdapter().getSelectedURIs(); mListener.onPhotoPickerMediaChosen(uriList); return true; } return false; } @Override public void onDestroyActionMode(ActionMode mode) { getAdapter().setMultiSelectEnabled(false); mActionMode = null; showBottomBar(); } } }