package com.dozuki.ifixit.ui.gallery; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.widget.*; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.dozuki.ifixit.R; import com.dozuki.ifixit.model.Image; import com.dozuki.ifixit.model.gallery.GalleryImage; import com.dozuki.ifixit.model.gallery.GalleryMediaList; import com.dozuki.ifixit.ui.BaseFragment; import com.dozuki.ifixit.ui.guide.view.FullImageViewActivity; import com.dozuki.ifixit.util.api.Api; import com.dozuki.ifixit.util.CaptureHelper; import com.dozuki.ifixit.util.ImageSizes; import com.dozuki.ifixit.util.api.ApiCall; import java.io.File; import java.io.IOException; import java.util.ArrayList; public abstract class MediaFragment extends BaseFragment implements OnItemClickListener, OnItemLongClickListener { protected static final int IMAGE_PAGE_SIZE = 1000; private static final String CAMERA_PATH = "CAMERA_PATH"; private static final int SELECT_PICTURE = 1; private static final int CAMERA_PIC_REQUEST = 2; private static final String GALLERY_MEDIA_LIST = "GALLERY_MEDIA_LIST"; private static final String IMAGES_DOWNLOADED = "IMAGES_DOWNLOADED"; private static final String HASH_MAP = "HASH_MAP"; private static final String SHOWING_DELETE_KEY = "SHOWING_DELETE_KEY"; private static final int MAX_UPLOAD_COUNT = 4; private static final String RETURNING_VAL = "RETURNING_VAL"; private static final String DELETE_MODE = "DELETE_MODE"; protected MediaAdapter mGalleryAdapter; protected GalleryMediaList mMediaList; protected boolean mNextPageRequestInProgress; protected ArrayList<Image> mAlreadyAttachedImages; private GridView mGridView; private ActionMode mMode; private String mCameraTempFileName; private boolean mShowingDelete = false; private boolean mSelectForReturn; private TextView mNoMediaView; protected abstract void retrieveUserMedia(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mMode = null; mGalleryAdapter = new MediaAdapter(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.gallery_view, container, false); if (savedInstanceState != null) { mShowingDelete = savedInstanceState.getBoolean(SHOWING_DELETE_KEY); mMediaList = (GalleryMediaList) savedInstanceState.getSerializable(GALLERY_MEDIA_LIST); mSelectForReturn = savedInstanceState.getBoolean(RETURNING_VAL); if (mShowingDelete) { createDeleteConfirmDialog().show(); } if (savedInstanceState.getString(CAMERA_PATH) != null) { mCameraTempFileName = savedInstanceState.getString(CAMERA_PATH); } } else { mMediaList = new GalleryMediaList(); } if (mMediaList.size() == 0 && !mNextPageRequestInProgress) { retrieveUserMedia(); } mGridView = (GridView) view.findViewById(R.id.gridview); mNoMediaView = (TextView) view.findViewById(R.id.no_images_text); mGridView.setAdapter(mGalleryAdapter); mGridView.setOnItemClickListener(this); mGridView.setOnItemLongClickListener(this); if (savedInstanceState != null) { if (savedInstanceState.getBoolean(DELETE_MODE)) { setDeleteMode(); } } return view; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.top_camera_button: launchCamera(); return true; case R.id.top_gallery_button: launchImageChooser(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { if (requestCode == SELECT_PICTURE) { Uri selectedImageUri = data.getData(); // check file type String path = getPath(selectedImageUri); if (path == null || !(path.toLowerCase().contains(".jpeg") || path.toLowerCase().contains(".jpg") || path.toLowerCase().contains(".png"))) { Toast.makeText(getActivity(), getString(R.string.non_image_error), Toast.LENGTH_LONG).show(); return; } File file = new File(path); if (file.length() == 0) { Toast.makeText(getActivity(), getString(R.string.empty_image_error), Toast.LENGTH_LONG).show(); return; } if (mMediaList.countUploadingImages() >= MAX_UPLOAD_COUNT) { Toast.makeText(getActivity(), getString(R.string.too_many_image_error), Toast.LENGTH_LONG).show(); return; } String key = mGalleryAdapter.addUri(selectedImageUri); Api.call(getSherlockActivity(), ApiCall.uploadImage(path, key)); } else if (requestCode == CAMERA_PIC_REQUEST) { if (mCameraTempFileName == null) { Log.e("iFixit", "Error cameraTempFile is null!"); return; } String key = mGalleryAdapter.addFile(mCameraTempFileName); Api.call(getSherlockActivity(), ApiCall.uploadImage( mCameraTempFileName, key)); } } } @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putSerializable(GALLERY_MEDIA_LIST, mMediaList); savedInstanceState.putBoolean(SHOWING_DELETE_KEY, mShowingDelete); savedInstanceState.putBoolean(RETURNING_VAL, mSelectForReturn); savedInstanceState.putBoolean(DELETE_MODE, mMode != null); if (mCameraTempFileName != null) { savedInstanceState.putString(CAMERA_PATH, mCameraTempFileName); } } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { if (!mSelectForReturn) setDeleteMode(); return false; } public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { MediaViewItem cell = (MediaViewItem) view; if (mSelectForReturn) { String url = (String) view.getTag(); if (url == null || (url.equals("") || url.indexOf(".") == 0)) { return; } Intent selectResult = new Intent(); selectResult.putExtra(GalleryActivity.MEDIA_RETURN_KEY, mMediaList.get(position)); getSherlockActivity().setResult(Activity.RESULT_OK, selectResult); getSherlockActivity().finish(); } else if (mMode != null) { if (cell == null) { Log.i("iFixit", "Delete cell null!"); return; } mMediaList.get(position).toggleSelected(); view.invalidate(); mGalleryAdapter.invalidatedView(); } else { String url = (String) view.getTag(); if (url == null || (url.equals("") || url.indexOf(".") == 0)) { return; } startActivity(FullImageViewActivity.viewImage(getActivity(), url, false)); } } public void setForReturn(boolean returnItem) { mSelectForReturn = returnItem; } public void setAlreadyAttachedImages(ArrayList<Image> images) { mAlreadyAttachedImages = new ArrayList<Image>(images); } protected void setEmptyListView() { mGridView.setEmptyView(mNoMediaView); } protected void launchImageChooser() { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, getString(R.string.image_chooser_title)), SELECT_PICTURE); } protected void launchCamera() { Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); File file; try { file = createImageFile(); cameraIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST); } catch (IOException e) { Log.e("MediaFragment", "Launch camera", e); Toast.makeText(getActivity(), "Please insert an SD card.", Toast.LENGTH_SHORT).show(); } } private File createImageFile() throws IOException { // Create an image file name String imageFileName = CaptureHelper.getFileName(); File image = File.createTempFile(imageFileName, ".jpg", CaptureHelper.getAlbumDir()); mCameraTempFileName = image.getAbsolutePath(); return image; } private String getPath(Uri uri) { String[] projection = {MediaStore.Images.Media.DATA}; Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, null); if (cursor != null && cursor.moveToFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); return cursor.getString(column_index); } else { return null; } } private void deleteSelectedPhotos() { ArrayList<Integer> deleteList = new ArrayList<Integer>(); for (int i = mMediaList.size() - 1; i >= 0; i--) { if (mMediaList.get(i).isSelected()) { if (mMediaList.get(i).isLocal()) { Toast.makeText(getSherlockActivity(), getString(R.string.delete_loading_image_error), Toast.LENGTH_LONG).show(); } else { deleteList.add(mMediaList.get(i).getId()); mMediaList.remove(i); } } } Api.call(getSherlockActivity(), ApiCall.deleteImage(deleteList)); mMode.finish(); } private void setDeleteMode() { if (mMode == null) { Animation animHide = AnimationUtils.loadAnimation(getSherlockActivity(), R.anim.slide_out_bottom_slow); animHide.setAnimationListener(new AnimationListener() { @Override public void onAnimationEnd(Animation arg0) {} @Override public void onAnimationRepeat(Animation arg0) {} @Override public void onAnimationStart(Animation arg0) {} }); mMode = getSherlockActivity().startActionMode(new ModeCallback()); } } private AlertDialog createDeleteConfirmDialog() { mShowingDelete = true; int selectedCount = mMediaList.countSelected(); AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity()); builder .setTitle(getString(R.string.confirm_delete_title)) .setMessage(getString(R.string.media_delete_body, selectedCount, selectedCount > 1 ? getString(R.string.images) : getString(R.string.image))) .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { mShowingDelete = false; deleteSelectedPhotos(); dialog.cancel(); } }) .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mShowingDelete = false; dialog.cancel(); } }); AlertDialog dialog = builder.create(); dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { mShowingDelete = false; } }); return dialog; } class MediaAdapter extends BaseAdapter { public String addUri(Uri uri) { return addFile(uri.toString()); } public String addFile(String path) { GalleryImage image = new GalleryImage(); image.setLocalImage(path); mMediaList.addItem(0, image); notifyDataSetChanged(); invalidatedView(); return path; } public void invalidatedView() { mGridView.invalidateViews(); } @Override public int getCount() { return mMediaList.getItems().size(); } @Override public Object getItem(int position) { return mMediaList.get(position); } @Override public long getItemId(int id) { return id; } public View getView(int position, View convertView, ViewGroup parent) { MediaViewItem itemView; if (convertView == null) { itemView = new MediaViewItem(getSherlockActivity()); } else { itemView = (MediaViewItem) convertView; } GalleryImage image = (GalleryImage) getItem(position); itemView.clearImage(); // image was added from the local gallery or captured on the phone if (image.isLocal()) { Uri temp = Uri.parse(image.getPath()); image.setLocalImage(temp.toString()); if (image.fromMediaStore()) { // Media Store image itemView.setImageItem(temp.toString()); } else { // image was added locally from camera itemView.setImageItem(new File(temp.toString())); } } else { itemView.setImageItem(image.getPath(ImageSizes.stepThumb)); } itemView.setTag(image.getPath()); itemView.setSelected(image.isSelected()); return itemView; } } private final class ModeCallback implements ActionMode.Callback { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Create the menu from the xml file getSherlockActivity().getSupportMenuInflater().inflate(R.menu.contextual_delete, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (!mMediaList.hasSelected()) { mode.finish(); return true; } createDeleteConfirmDialog().show(); return true; } @Override public void onDestroyActionMode(ActionMode mode) { if (mode == mMode) { mMode = null; } mMediaList.clearSelected(); mGalleryAdapter.invalidatedView(); } } }