package kr.kdev.dg1s.biowiki.ui.media;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.MenuItem.OnActionExpandListener;
import com.actionbarsherlock.widget.SearchView;
import com.actionbarsherlock.widget.SearchView.OnQueryTextListener;
import org.xmlrpc.android.ApiHelper;
import org.xmlrpc.android.ApiHelper.GetFeatures.Callback;
import java.util.ArrayList;
import java.util.List;
import kr.kdev.dg1s.biowiki.BioWiki;
import kr.kdev.dg1s.biowiki.Constants;
import kr.kdev.dg1s.biowiki.R;
import kr.kdev.dg1s.biowiki.models.FeatureSet;
import kr.kdev.dg1s.biowiki.ui.BWActionBarActivity;
import kr.kdev.dg1s.biowiki.ui.media.MediaAddFragment.MediaAddFragmentCallback;
import kr.kdev.dg1s.biowiki.ui.media.MediaEditFragment.MediaEditFragmentCallback;
import kr.kdev.dg1s.biowiki.ui.media.MediaItemFragment.MediaItemFragmentCallback;
import kr.kdev.dg1s.biowiki.ui.posts.EditPostActivity;
import kr.kdev.dg1s.biowiki.ui.posts.EditPostContentFragment;
import kr.kdev.dg1s.biowiki.util.BWAlertDialogFragment;
import kr.kdev.dg1s.biowiki.util.MediaDeleteService;
import kr.kdev.dg1s.biowiki.util.MediaUtils;
import kr.kdev.dg1s.biowiki.util.Utils;
/**
* The main activity in which the user can browse their media.
* Accessible via the menu drawer as "Media"
*/
public class MediaBrowserActivity extends BWActionBarActivity implements MediaGridFragment.MediaGridListener,
MediaItemFragmentCallback,
OnQueryTextListener, OnActionExpandListener, MediaEditFragmentCallback,
MediaAddFragmentCallback,
com.actionbarsherlock.view.ActionMode.Callback {
private static final String SAVED_QUERY = "SAVED_QUERY";
private final FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
setupBaseLayout();
}
};
private MediaGridFragment mMediaGridFragment;
private MediaItemFragment mMediaItemFragment;
private MediaEditFragment mMediaEditFragment;
private MediaAddFragment mMediaAddFragment;
private PopupWindow mAddMediaPopup;
private SearchView mSearchView;
private MenuItem mSearchMenuItem;
private Menu mMenu;
private FeatureSet mFeatureSet;
private ActionMode mActionMode;
private int mMultiSelectCount;
private String mQuery;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (BioWiki.wpDB == null) {
Toast.makeText(this, R.string.fatal_db_error, Toast.LENGTH_LONG).show();
finish();
return;
}
setTitle(R.string.media);
createMenuDrawer(R.layout.media_browser_activity);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(true);
FragmentManager fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(mOnBackStackChangedListener);
FragmentTransaction ft = fm.beginTransaction();
setupBaseLayout();
mMediaAddFragment = (MediaAddFragment) fm.findFragmentById(R.id.mediaAddFragment);
mMediaGridFragment = (MediaGridFragment) fm.findFragmentById(R.id.mediaGridFragment);
mMediaItemFragment = (MediaItemFragment) fm.findFragmentByTag(MediaItemFragment.TAG);
if (mMediaItemFragment != null)
ft.hide(mMediaGridFragment);
mMediaEditFragment = (MediaEditFragment) fm.findFragmentByTag(MediaEditFragment.TAG);
if (mMediaEditFragment != null && !mMediaEditFragment.isInLayout())
ft.hide(mMediaItemFragment);
ft.commit();
setupAddMenuPopup();
String action = getIntent().getAction();
if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
// We arrived here from a share action
uploadSharedFiles();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVED_QUERY, mQuery);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mQuery = savedInstanceState.getString(SAVED_QUERY);
}
private void uploadSharedFiles() {
Intent intent = getIntent();
String action = intent.getAction();
final List<Uri> multi_stream;
if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
multi_stream = intent.getParcelableArrayListExtra((Intent.EXTRA_STREAM));
} else {
multi_stream = new ArrayList<Uri>();
multi_stream.add((Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM));
}
mMediaAddFragment.uploadList(multi_stream);
// clear the intent's action, so that in case the user rotates, we don't re-upload the same
// files
getIntent().setAction(null);
}
private void setupBaseLayout() {
// hide access to the drawer when there are fragments in the back stack
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
mMenuDrawer.setDrawerIndicatorEnabled(true);
} else {
mMenuDrawer.setDrawerIndicatorEnabled(false);
}
}
/**
* Setup the popup that allows you to add new media from camera, video camera or local files *
*/
private void setupAddMenuPopup() {
String capturePhoto = getResources().getString(R.string.media_add_popup_capture_photo);
String captureVideo = getResources().getString(R.string.media_add_popup_capture_video);
String pickPhotoFromGallery = getResources().getString(
R.string.select_photo);
String pickVideoFromGallery = getResources().getString(
R.string.select_video);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(MediaBrowserActivity.this,
R.layout.actionbar_add_media_cell,
new String[]{
capturePhoto, captureVideo, pickPhotoFromGallery, pickVideoFromGallery
}
);
View layoutView = getLayoutInflater().inflate(R.layout.actionbar_add_media, null, false);
ListView listView = (ListView) layoutView.findViewById(R.id.actionbar_add_media_listview);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.notifyDataSetChanged();
// Support video only if you are self-hosted or are a dot-com blog with the video
// press upgrade
boolean selfHosted = !BioWiki.getCurrentBlog().isDotcomFlag();
boolean isVideoEnabled = selfHosted
|| (mFeatureSet != null && mFeatureSet.isVideopressEnabled());
if (position == 0) {
mMediaAddFragment.launchCamera();
} else if (position == 1) {
if (isVideoEnabled) {
mMediaAddFragment.launchVideoCamera();
} else {
showVideoPressUpgradeDialog();
}
} else if (position == 2) {
mMediaAddFragment.launchPictureLibrary();
} else if (position == 3) {
if (isVideoEnabled) {
mMediaAddFragment.launchVideoLibrary();
} else {
showVideoPressUpgradeDialog();
}
}
mAddMediaPopup.dismiss();
}
});
int width = getResources().getDimensionPixelSize(R.dimen.action_bar_spinner_width);
mAddMediaPopup = new PopupWindow(layoutView, width, ViewGroup.LayoutParams.WRAP_CONTENT, true);
mAddMediaPopup.setBackgroundDrawable(new ColorDrawable());
}
private void showVideoPressUpgradeDialog() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
String title = getString(R.string.media_no_video_title);
String message = getString(R.string.media_no_video_message);
String infoTitle = getString(R.string.learn_more);
String infoURL = Constants.videoPressURL;
BWAlertDialogFragment alert = BWAlertDialogFragment.newUrlInfoDialog(title, message, infoTitle, infoURL);
ft.add(alert, "alert");
ft.commitAllowingStateLoss();
}
@Override
protected void onResume() {
super.onResume();
startMediaDeleteService();
getFeatureSet();
}
/**
* Get the feature set for a wordpress.com hosted blog *
*/
private void getFeatureSet() {
if (BioWiki.getCurrentBlog() == null || !BioWiki.getCurrentBlog().isDotcomFlag())
return;
ApiHelper.GetFeatures task = new ApiHelper.GetFeatures(new Callback() {
@Override
public void onResult(FeatureSet featureSet) {
mFeatureSet = featureSet;
}
});
List<Object> apiArgs = new ArrayList<Object>();
apiArgs.add(BioWiki.getCurrentBlog());
task.execute(apiArgs);
}
@Override
protected void onPause() {
super.onPause();
if (mSearchMenuItem != null)
mSearchMenuItem.collapseActionView();
}
@Override
public void onBlogChanged() {
super.onBlogChanged();
// clear edit fragment
if (mMediaEditFragment != null) {
mMediaEditFragment.loadMedia(null);
// hide if in phone
if (!mMediaEditFragment.isInLayout() && mMediaEditFragment.isVisible()) {
getSupportFragmentManager().popBackStack();
}
}
getSupportFragmentManager().executePendingTransactions();
// clear item fragment (only visible on phone)
if (mMediaItemFragment != null && mMediaItemFragment.isVisible()) {
getSupportFragmentManager().popBackStack();
}
// reset the media fragment
if (mMediaGridFragment != null) {
mMediaGridFragment.reset();
mMediaGridFragment.refreshSpinnerAdapter();
if (!mMediaGridFragment.hasRetrievedAllMediaFromServer()) {
mMediaGridFragment.refreshMediaFromServer(0, false);
mMediaGridFragment.setRefreshing(true);
}
}
// check what features (e.g. video) the user has
getFeatureSet();
}
@Override
public void onMediaItemSelected(String mediaId) {
if (mSearchView != null)
mSearchView.clearFocus();
// collapse the search menu on phone
if (mSearchMenuItem != null && !Utils.isTablet())
mSearchMenuItem.collapseActionView();
FragmentManager fm = getSupportFragmentManager();
if (mMediaEditFragment == null || !mMediaEditFragment.isInLayout()) {
// phone: hide the grid and show the item details
if (fm.getBackStackEntryCount() == 0) {
FragmentTransaction ft = fm.beginTransaction();
ft.hide(mMediaGridFragment);
mMediaGridFragment.clearCheckedItems();
setupBaseLayout();
mMediaItemFragment = MediaItemFragment.newInstance(mediaId);
ft.add(R.id.media_browser_container, mMediaItemFragment, MediaItemFragment.TAG);
ft.addToBackStack(null);
ft.commit();
mMenuDrawer.setDrawerIndicatorEnabled(false);
}
} else {
// tablet: update the edit fragment with the new item
mMediaEditFragment.loadMedia(mediaId);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
mMenu = menu;
getSupportMenuInflater().inflate(R.menu.media, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
setupBaseLayout();
return true;
}
} else if (itemId == R.id.menu_new_media) {
View view = findViewById(R.id.menu_new_media);
if (view != null) {
int y_offset = getResources().getDimensionPixelSize(R.dimen.action_bar_spinner_y_offset);
int[] loc = new int[2];
view.getLocationOnScreen(loc);
mAddMediaPopup.showAtLocation(view, Gravity.TOP | Gravity.LEFT, loc[0],
loc[1] + view.getHeight() + y_offset);
} else {
// In case menu button is not on screen (declared showAsAction="ifRoom"), center the popup in the view.
View gridView = findViewById(R.id.media_gridview);
mAddMediaPopup.showAtLocation(gridView, Gravity.CENTER, 0, 0);
}
return true;
} else if (itemId == R.id.menu_search) {
mSearchMenuItem = item;
mSearchMenuItem.setOnActionExpandListener(this);
mSearchMenuItem.expandActionView();
mSearchView = (SearchView) item.getActionView();
mSearchView.setOnQueryTextListener(this);
// load last saved query
if (!TextUtils.isEmpty(mQuery)) {
onQueryTextSubmit(mQuery);
mSearchView.setQuery(mQuery, true);
}
return true;
} else if (itemId == R.id.menu_edit_media) {
String mediaId = mMediaItemFragment.getMediaId();
FragmentManager fm = getSupportFragmentManager();
if (mMediaEditFragment == null || !mMediaEditFragment.isInLayout()) {
// phone layout: hide item details, show and update edit fragment
FragmentTransaction ft = fm.beginTransaction();
if (mMediaItemFragment.isVisible())
ft.hide(mMediaItemFragment);
mMediaEditFragment = MediaEditFragment.newInstance(mediaId);
ft.add(R.id.media_browser_container, mMediaEditFragment, MediaEditFragment.TAG);
ft.addToBackStack(null);
ft.commit();
mMenuDrawer.setDrawerIndicatorEnabled(false);
} else {
// tablet layout: update edit fragment
mMediaEditFragment.loadMedia(mediaId);
}
if (mSearchView != null)
mSearchView.clearFocus();
} else if (itemId == R.id.menu_delete) {
if (mMediaEditFragment != null && mMediaEditFragment.isInLayout()) {
String mediaId = mMediaEditFragment.getMediaId();
launchConfirmDeleteDialog(mediaId);
}
}
return super.onOptionsItemSelected(item);
}
private void launchConfirmDeleteDialog(final String mediaId) {
if (mediaId == null)
return;
Builder builder = new AlertDialog.Builder(this)
.setMessage(R.string.confirm_delete_media)
.setCancelable(true)
.setPositiveButton(R.string.delete, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ArrayList<String> ids = new ArrayList<String>(1);
ids.add(mediaId);
onDeleteMedia(ids);
}
})
.setNegativeButton(R.string.cancel, null);
AlertDialog dialog = builder.create();
dialog.show();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.menu_delete).setVisible(Utils.isTablet());
return super.onPrepareOptionsMenu(menu);
}
@Override
public void onMediaItemListDownloaded() {
if (mMediaItemFragment != null) {
mMediaGridFragment.setRefreshing(false);
if (mMediaItemFragment.isInLayout()) {
mMediaItemFragment.loadDefaultMedia();
}
}
}
@Override
public void onMediaItemListDownloadStart() {
mMediaGridFragment.setRefreshing(true);
}
@Override
public boolean onQueryTextSubmit(String query) {
if (mMediaGridFragment != null) {
mMediaGridFragment.search(query);
}
mQuery = query;
mSearchView.clearFocus();
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
if (mMediaGridFragment != null)
mMediaGridFragment.search(newText);
mQuery = newText;
return true;
}
@Override
public void onResume(Fragment fragment) {
invalidateOptionsMenu();
}
@Override
public void onPause(Fragment fragment) {
invalidateOptionsMenu();
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
// currently we don't support searching from within a filter, so hide it
if (mMediaGridFragment != null) {
mMediaGridFragment.setFilterVisibility(View.GONE);
mMediaGridFragment.setFilter(MediaGridFragment.Filter.ALL);
}
// load last search query
if (!TextUtils.isEmpty(mQuery))
onQueryTextChange(mQuery);
mMenu.findItem(R.id.menu_new_media).setVisible(false);
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// preserve the previous query
String tmpQuery = mQuery;
onQueryTextChange("");
mQuery = tmpQuery;
if (mMediaGridFragment != null) {
mMediaGridFragment.setFilterVisibility(View.VISIBLE);
mMediaGridFragment.setFilter(MediaGridFragment.Filter.ALL);
}
mMenu.findItem(R.id.menu_new_media).setVisible(true);
return true;
}
@Override
public void onDeleteMedia(final List<String> ids) {
final String blogId = String.valueOf(BioWiki.getCurrentBlog().getLocalTableBlogId());
List<String> sanitizedIds = new ArrayList<String>(ids.size());
if (mMediaItemFragment != null && mMediaItemFragment.isVisible()) {
// phone layout: pop the item fragment if it's visible
getSupportFragmentManager().popBackStack();
}
//Make sure there are no media in "uploading"
for (String currentID : ids) {
if (MediaUtils.canDeleteMedia(blogId, currentID))
sanitizedIds.add(currentID);
}
if (sanitizedIds.size() != ids.size()) {
if (ids.size() == 1)
Toast.makeText(this, R.string.wait_until_upload_completes, Toast.LENGTH_LONG).show();
else
Toast.makeText(this, R.string.cannot_delete_multi_media_items, Toast.LENGTH_LONG).show();
}
// mark items for delete without actually deleting items yet,
// and then refresh the grid
BioWiki.wpDB.setMediaFilesMarkedForDelete(blogId, sanitizedIds);
if (mMediaEditFragment != null) {
String mediaId = mMediaEditFragment.getMediaId();
for (String id : sanitizedIds) {
if (id.equals(mediaId)) {
mMediaEditFragment.loadMedia(null);
break;
}
}
}
mMediaGridFragment.clearCheckedItems();
mMediaGridFragment.refreshMediaFromDB();
startMediaDeleteService();
}
public void onSavedEdit(String mediaId, boolean result) {
if (mMediaEditFragment != null && mMediaEditFragment.isVisible() && result) {
FragmentManager fm = getSupportFragmentManager();
fm.popBackStack();
// refresh media item details (phone-only)
if (mMediaItemFragment != null)
mMediaItemFragment.loadMedia(mediaId);
// refresh grid
mMediaGridFragment.refreshMediaFromDB();
}
}
private void startMediaDeleteService() {
startService(new Intent(this, MediaDeleteService.class));
}
@Override
public void onMultiSelectChange(int count) {
mMultiSelectCount = count;
if (count > 0 && mActionMode == null) {
mActionMode = getSherlock().startActionMode(this);
} else if (count == 0 && mActionMode != null) {
mActionMode.finish();
}
// update contextual action bar title
if (count > 0 && mActionMode != null)
mActionMode.setTitle(count + " selected");
// update contextual action bar menu items
if (mActionMode != null)
mActionMode.invalidate();
invalidateOptionsMenu();
}
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (mMenuDrawer.isMenuVisible()) {
super.onBackPressed();
} else if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
setupBaseLayout();
} else {
super.onBackPressed();
}
}
@Override
public void onMediaAdded(String mediaId) {
if (BioWiki.getCurrentBlog() == null || mediaId == null) {
return;
}
String blogId = String.valueOf(BioWiki.getCurrentBlog().getLocalTableBlogId());
Cursor cursor = BioWiki.wpDB.getMediaFile(blogId, mediaId);
if (cursor == null || !cursor.moveToFirst()) {
mMediaGridFragment.removeFromMultiSelect(mediaId);
if (mMediaEditFragment != null && mMediaEditFragment.isVisible()
&& mediaId.equals(mMediaEditFragment.getMediaId())) {
if (mMediaEditFragment.isInLayout()) {
mMediaEditFragment.loadMedia(null);
} else {
getSupportFragmentManager().popBackStack();
}
}
} else {
mMediaGridFragment.refreshMediaFromDB();
}
if (cursor != null) {
cursor.close();
}
}
@Override
public void onRetryUpload(String mediaId) {
mMediaAddFragment.addToQueue(mediaId);
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.media_multiselect, menu);
mMediaGridFragment.setPullToRefreshEnabled(false);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
if (mActionMode != null) {
if (mMultiSelectCount == 1) {
menu.findItem(R.id.media_multiselect_actionbar_post).setVisible(true);
menu.findItem(R.id.media_multiselect_actionbar_gallery).setVisible(false);
} else if (mMultiSelectCount > 1) {
menu.findItem(R.id.media_multiselect_actionbar_post).setVisible(false);
menu.findItem(R.id.media_multiselect_actionbar_gallery).setVisible(true);
} else {
menu.findItem(R.id.media_multiselect_actionbar_post).setVisible(false);
menu.findItem(R.id.media_multiselect_actionbar_gallery).setVisible(false);
}
}
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.media_multiselect_actionbar_post:
handleNewPost();
return true;
case R.id.media_multiselect_actionbar_gallery:
handleMultiSelectPost();
return true;
case R.id.media_multiselect_actionbar_trash:
handleMultiSelectDelete();
return true;
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
mMediaGridFragment.setPullToRefreshEnabled(true);
cancelMultiSelect();
}
private void cancelMultiSelect() {
mMediaGridFragment.clearCheckedItems();
}
private void handleNewPost() {
if (mMediaGridFragment == null)
return;
ArrayList<String> ids = mMediaGridFragment.getCheckedItems();
Intent i = new Intent(this, EditPostActivity.class);
i.setAction(EditPostContentFragment.NEW_MEDIA_POST);
i.putExtra(EditPostContentFragment.NEW_MEDIA_POST_EXTRA, ids.get(0));
startActivity(i);
}
private void handleMultiSelectDelete() {
Builder builder = new AlertDialog.Builder(this)
.setMessage(R.string.confirm_delete_multi_media)
.setCancelable(true)
.setPositiveButton(R.string.delete, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ArrayList<String> ids = mMediaGridFragment.getCheckedItems();
onDeleteMedia(ids);
mMediaGridFragment.refreshSpinnerAdapter();
}
})
.setNegativeButton(R.string.cancel, null);
AlertDialog dialog = builder.create();
dialog.show();
}
private void handleMultiSelectPost() {
if (mMediaGridFragment == null)
return;
ArrayList<String> ids = mMediaGridFragment.getCheckedItems();
Intent i = new Intent(this, EditPostActivity.class);
i.setAction(EditPostContentFragment.NEW_MEDIA_GALLERY);
i.putExtra(EditPostContentFragment.NEW_MEDIA_GALLERY_EXTRA_IDS, ids);
startActivity(i);
}
}