package com.boardgamegeek.ui;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.DatePicker;
import android.widget.ListView;
import android.widget.TextView;
import com.boardgamegeek.R;
import com.boardgamegeek.events.PlaySelectedEvent;
import com.boardgamegeek.events.PlaysCountChangedEvent;
import com.boardgamegeek.events.PlaysFilterChangedEvent;
import com.boardgamegeek.events.PlaysSortChangedEvent;
import com.boardgamegeek.events.UpdateCompleteEvent;
import com.boardgamegeek.events.UpdateEvent;
import com.boardgamegeek.provider.BggContract;
import com.boardgamegeek.provider.BggContract.Buddies;
import com.boardgamegeek.provider.BggContract.Games;
import com.boardgamegeek.provider.BggContract.PlayPlayers;
import com.boardgamegeek.provider.BggContract.Plays;
import com.boardgamegeek.service.SyncService;
import com.boardgamegeek.service.UpdateService;
import com.boardgamegeek.sorter.PlaysSorterFactory;
import com.boardgamegeek.sorter.Sorter;
import com.boardgamegeek.ui.model.PlayModel;
import com.boardgamegeek.util.ActivityUtils;
import com.boardgamegeek.util.CursorUtils;
import com.boardgamegeek.util.DateTimeUtils;
import com.boardgamegeek.util.DialogUtils;
import com.boardgamegeek.util.HelpUtils;
import com.boardgamegeek.util.PreferencesUtils;
import com.boardgamegeek.util.PresentationUtils;
import com.boardgamegeek.util.ResolverUtils;
import com.boardgamegeek.util.StringUtils;
import com.boardgamegeek.util.UIUtils;
import com.boardgamegeek.util.fabric.FilterEvent;
import com.boardgamegeek.util.fabric.SortEvent;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.ShowcaseView.Builder;
import com.github.amlcurran.showcaseview.targets.Target;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedHashSet;
import butterknife.BindView;
import butterknife.ButterKnife;
import hugo.weaving.DebugLog;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
import timber.log.Timber;
public class PlaysFragment extends StickyHeaderListFragment implements LoaderManager.LoaderCallbacks<Cursor>, MultiChoiceModeListener {
public static final String KEY_MODE = "MODE";
public static final int FILTER_TYPE_STATUS_ALL = -2;
public static final int FILTER_TYPE_STATUS_UPDATE = 1;
public static final int FILTER_TYPE_STATUS_DIRTY = 2;
public static final int FILTER_TYPE_STATUS_DELETE = 3;
public static final int FILTER_TYPE_STATUS_PENDING = 4;
private static final int MODE_ALL = 0;
private static final int MODE_GAME = 1;
public static final int MODE_BUDDY = 2;
public static final int MODE_PLAYER = 3;
public static final int MODE_LOCATION = 4;
private static final int PLAY_QUERY_TOKEN = 0x21;
private static final int HELP_VERSION = 2;
private PlayAdapter adapter;
private Uri uri;
private int gameId;
private String gameName;
private String thumbnailUrl;
private String imageUrl;
private boolean arePlayersCustomSorted;
private String buddyName;
private String playerName;
private String locationName;
private int filterType = FILTER_TYPE_STATUS_ALL;
private Sorter sorter;
private boolean hasAutoSyncTriggered;
private int mode = MODE_ALL;
private final LinkedHashSet<Integer> selectedPlaysPositions = new LinkedHashSet<>();
private MenuItem sendMenuItem;
private MenuItem editMenuItem;
private ShowcaseView showcaseView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
int sortType = PlaysSorterFactory.TYPE_DEFAULT;
sorter = PlaysSorterFactory.create(getActivity(), sortType);
uri = Plays.CONTENT_URI;
final Intent intent = UIUtils.fragmentArgumentsToIntent(getArguments());
Uri uri = intent.getData();
int iconColor = intent.getIntExtra(ActivityUtils.KEY_ICON_COLOR, 0);
mode = MODE_ALL;
gameId = BggContract.INVALID_ID;
buddyName = "";
if (uri != null) {
if (Games.isGameUri(uri)) {
mode = MODE_GAME;
} else if (Buddies.isBuddyUri(uri)) {
mode = MODE_BUDDY;
}
} else {
mode = getArguments().getInt(PlaysFragment.KEY_MODE, mode);
}
showFab(mode == MODE_GAME);
if (fabView != null && iconColor != 0) {
fabView.setBackgroundTintList(ColorStateList.valueOf(iconColor));
}
switch (mode) {
case MODE_GAME:
gameId = Games.getGameId(uri);
gameName = getArguments().getString(ActivityUtils.KEY_GAME_NAME);
thumbnailUrl = getArguments().getString(ActivityUtils.KEY_THUMBNAIL_URL);
imageUrl = getArguments().getString(ActivityUtils.KEY_IMAGE_URL);
arePlayersCustomSorted = getArguments().getBoolean(ActivityUtils.KEY_CUSTOM_PLAYER_SORT);
getLoaderManager().restartLoader(GameQuery._TOKEN, getArguments(), this);
break;
case MODE_BUDDY:
buddyName = getArguments().getString(ActivityUtils.KEY_BUDDY_NAME);
this.uri = Plays.buildPlayersByPlayUri();
break;
case MODE_PLAYER:
buddyName = "";
playerName = getArguments().getString(ActivityUtils.KEY_PLAYER_NAME);
this.uri = Plays.buildPlayersByPlayUri();
break;
case MODE_LOCATION:
locationName = getArguments().getString(ActivityUtils.KEY_LOCATION);
break;
}
setEmptyText(getString(getEmptyStringResource()));
requery();
final StickyListHeadersListView listView = getListView();
if (listView != null) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(this);
}
maybeShowHelp();
}
@Override
public void onListItemClick(View view, int position, long id) {
Cursor cursor = (Cursor) adapter.getItem(position);
if (cursor != null) {
long internalId = cursor.getInt(cursor.getColumnIndex(Plays._ID));
PlayModel play = PlayModel.fromCursor(cursor, getActivity());
EventBus.getDefault().postSticky(new PlaySelectedEvent(internalId, play.getGameId(), play.getName(), play.getThumbnailUrl(), play.getImageUrl()));
}
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
switch (filterType) {
case FILTER_TYPE_STATUS_DIRTY:
UIUtils.checkMenuItem(menu, R.id.menu_filter_in_progress);
break;
case FILTER_TYPE_STATUS_PENDING:
UIUtils.checkMenuItem(menu, R.id.menu_filter_pending);
break;
case FILTER_TYPE_STATUS_ALL:
default:
UIUtils.checkMenuItem(menu, R.id.menu_filter_all);
break;
}
if (sorter != null) {
switch (sorter.getType()) {
case PlaysSorterFactory.TYPE_PLAY_DATE:
UIUtils.checkMenuItem(menu, R.id.menu_sort_date);
break;
case PlaysSorterFactory.TYPE_PLAY_GAME:
UIUtils.checkMenuItem(menu, R.id.menu_sort_game);
break;
case PlaysSorterFactory.TYPE_PLAY_LENGTH:
UIUtils.checkMenuItem(menu, R.id.menu_sort_length);
break;
case PlaysSorterFactory.TYPE_PLAY_LOCATION:
UIUtils.checkMenuItem(menu, R.id.menu_sort_location);
break;
default:
UIUtils.checkMenuItem(menu, R.id.menu_sort_date);
break;
}
}
super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
String title = item.getTitle().toString();
switch (item.getItemId()) {
case R.id.menu_sort_date:
setSort(PlaysSorterFactory.TYPE_PLAY_DATE);
return true;
case R.id.menu_sort_location:
setSort(PlaysSorterFactory.TYPE_PLAY_LOCATION);
return true;
case R.id.menu_sort_game:
setSort(PlaysSorterFactory.TYPE_PLAY_GAME);
return true;
case R.id.menu_sort_length:
setSort(PlaysSorterFactory.TYPE_PLAY_LENGTH);
return true;
case R.id.menu_filter_all:
filter(FILTER_TYPE_STATUS_ALL, title);
return true;
case R.id.menu_filter_in_progress:
filter(FILTER_TYPE_STATUS_DIRTY, title);
return true;
case R.id.menu_filter_pending:
filter(FILTER_TYPE_STATUS_PENDING, title);
return true;
case R.id.menu_refresh_on:
new DatePickerFragment().show(getActivity().getSupportFragmentManager(), "datePicker");
return true;
case R.id.menu_help:
showHelp();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected boolean dividerShown() {
return true;
}
@SuppressWarnings("unused")
@DebugLog
@Subscribe
public void onEvent(PlaySelectedEvent event) {
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEvent(UpdateEvent event) {
isSyncing((event.getType() == UpdateService.SYNC_TYPE_GAME_PLAYS) || (event.getType() == UpdateService.SYNC_TYPE_PLAYS_DATE));
}
@SuppressWarnings({ "UnusedParameters", "unused" })
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEvent(UpdateCompleteEvent event) {
isSyncing(false);
}
@Override
protected boolean isRefreshable() {
return super.isRefreshable() || (mode == MODE_GAME);
}
@DebugLog
private void showHelp() {
final Builder builder = HelpUtils.getShowcaseBuilder(getActivity());
if (builder != null) {
showcaseView = builder
.setContentText(R.string.help_plays)
.setTarget(Target.NONE)
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showcaseView.hide();
HelpUtils.updateHelp(getContext(), HelpUtils.HELP_PLAYS_KEY, HELP_VERSION);
}
})
.build();
showcaseView.show();
}
}
@DebugLog
private void maybeShowHelp() {
if (HelpUtils.shouldShowHelp(getContext(), HelpUtils.HELP_PLAYS_KEY, HELP_VERSION)) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
showHelp();
}
}, 100);
}
}
private void requery() {
if (mode == MODE_ALL || mode == MODE_LOCATION || mode == MODE_GAME) {
getLoaderManager().restartLoader(SumQuery._TOKEN, getArguments(), this);
} else if (mode == MODE_PLAYER || mode == MODE_BUDDY) {
getLoaderManager().restartLoader(PlayerSumQuery._TOKEN, getArguments(), this);
}
getLoaderManager().restartLoader(PLAY_QUERY_TOKEN, getArguments(), this);
}
@SuppressWarnings("unused")
@Subscribe(sticky = true)
public void onEvent(PlaysSortChangedEvent event) {
setSort(event.getType());
}
@SuppressWarnings("unused")
@Subscribe(sticky = true)
public void onEvent(PlaysFilterChangedEvent event) {
filter(event.getType(), event.getDescription());
}
private void setSort(int sortType) {
if (sorter != null && sortType == sorter.getType()) {
return;
}
if (sortType == PlaysSorterFactory.TYPE_UNKNOWN) {
sortType = PlaysSorterFactory.TYPE_DEFAULT;
}
SortEvent.log("Plays", String.valueOf(sortType));
sorter = PlaysSorterFactory.create(getActivity(), sortType);
resetScrollState();
requery();
}
public static class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
// HACK prevent onDateSet from firing twice
private boolean alreadyCalled = false;
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Calendar calendar = Calendar.getInstance();
return new DatePickerDialog(getActivity(), this, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH));
}
public void onDateSet(DatePicker view, int year, int month, int day) {
if (alreadyCalled) {
return;
}
alreadyCalled = true;
String date = DateTimeUtils.formatDateForApi(year, month, day);
UpdateService.start(getActivity(), UpdateService.SYNC_TYPE_PLAYS_DATE, date);
}
}
private int getEmptyStringResource() {
switch (mode) {
case MODE_BUDDY:
return R.string.empty_plays_buddy;
case MODE_PLAYER:
return R.string.empty_plays_player;
case MODE_LOCATION:
return R.string.empty_plays_location;
case MODE_GAME:
return R.string.empty_plays_game;
case MODE_ALL:
default:
switch (filterType) {
case FILTER_TYPE_STATUS_DIRTY:
return R.string.empty_plays_draft;
case FILTER_TYPE_STATUS_UPDATE:
return R.string.empty_plays_update;
case FILTER_TYPE_STATUS_DELETE:
return R.string.empty_plays_delete;
case FILTER_TYPE_STATUS_PENDING:
return R.string.empty_plays_pending;
case FILTER_TYPE_STATUS_ALL:
default:
if (PreferencesUtils.getSyncPlays(getActivity())) {
return R.string.empty_plays_sync_off;
} else {
return R.string.empty_plays_sync_off;
}
}
}
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle data) {
CursorLoader loader = null;
if (id == PLAY_QUERY_TOKEN) {
loader = new CursorLoader(getActivity(),
uri,
sorter == null ? PlayModel.PROJECTION : StringUtils.unionArrays(PlayModel.PROJECTION, sorter.getColumns()),
selection(),
selectionArgs(),
sorter == null ? null : sorter.getOrderByClause());
loader.setUpdateThrottle(2000);
} else if (id == GameQuery._TOKEN) {
loader = new CursorLoader(getActivity(), Games.buildGameUri(gameId), GameQuery.PROJECTION, null, null, null);
loader.setUpdateThrottle(0);
} else if (id == SumQuery._TOKEN) {
loader = new CursorLoader(getActivity(), Plays.CONTENT_SIMPLE_URI, SumQuery.PROJECTION, selection(), selectionArgs(), null);
loader.setUpdateThrottle(0);
} else if (id == PlayerSumQuery._TOKEN) {
Uri uri = Plays.buildPlayersByUniquePlayerUri();
if (mode == MODE_BUDDY) {
uri = Plays.buildPlayersByUniqueUserUri();
}
loader = new CursorLoader(getActivity(), uri, PlayerSumQuery.PROJECTION, selection(), selectionArgs(), null);
loader.setUpdateThrottle(0);
}
return loader;
}
private String selection() {
switch (mode) {
case MODE_ALL:
if (filterType == FILTER_TYPE_STATUS_ALL) {
return null;
} else if (filterType == FILTER_TYPE_STATUS_PENDING) {
return String.format("%s>0 OR %s>0", Plays.DELETE_TIMESTAMP, Plays.UPDATE_TIMESTAMP);
} else {
return String.format("%s>0", Plays.DIRTY_TIMESTAMP);
}
case MODE_GAME:
return Plays.OBJECT_ID + "=?";
case MODE_BUDDY:
return PlayPlayers.USER_NAME + "=?";
case MODE_PLAYER:
return PlayPlayers.USER_NAME + "=? AND play_players." + PlayPlayers.NAME + "=?";
case MODE_LOCATION:
return Plays.LOCATION + "=?";
}
return null;
}
private String[] selectionArgs() {
switch (mode) {
case MODE_ALL:
if (filterType == FILTER_TYPE_STATUS_ALL) {
return null;
} else if (filterType == FILTER_TYPE_STATUS_PENDING) {
return null;
} else {
return null;
}
case MODE_GAME:
return new String[] { String.valueOf(gameId) };
case MODE_BUDDY:
return new String[] { buddyName };
case MODE_PLAYER:
return new String[] { buddyName, playerName };
case MODE_LOCATION:
return new String[] { locationName };
}
return null;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (getActivity() == null) {
return;
}
int token = loader.getId();
if (token == PLAY_QUERY_TOKEN) {
if (adapter == null) {
adapter = new PlayAdapter(getActivity());
setListAdapter(adapter);
}
adapter.changeCursor(cursor);
restoreScrollState();
PlaysSortChangedEvent event;
if (sorter == null) {
event = new PlaysSortChangedEvent(PlaysSorterFactory.TYPE_UNKNOWN, "");
} else {
event = new PlaysSortChangedEvent(sorter.getType(), sorter.getDescription());
}
EventBus.getDefault().postSticky(event);
} else if (token == GameQuery._TOKEN) {
if (!hasAutoSyncTriggered && cursor != null && cursor.moveToFirst()) {
hasAutoSyncTriggered = true;
long updated = cursor.getLong(GameQuery.UPDATED_PLAYS);
if (updated == 0 || DateTimeUtils.howManyDaysOld(updated) > 2) {
triggerRefresh();
}
}
} else if (token == SumQuery._TOKEN) {
int count = 0;
if (cursor != null && cursor.moveToFirst()) {
count = cursor.getInt(SumQuery.TOTAL_COUNT);
}
EventBus.getDefault().postSticky(new PlaysCountChangedEvent(count));
} else if (token == PlayerSumQuery._TOKEN) {
int count = 0;
if (cursor != null && cursor.moveToFirst()) {
count = cursor.getInt(PlayerSumQuery.SUM_QUANTITY);
}
EventBus.getDefault().postSticky(new PlaysCountChangedEvent(count));
} else {
Timber.d("Query complete, Not Actionable: %s", token);
cursor.close();
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
if (loader.getId() == PLAY_QUERY_TOKEN) {
adapter.changeCursor(null);
}
}
@Override
protected int getSyncType() {
return mode == MODE_GAME ? SyncService.FLAG_SYNC_NONE : SyncService.FLAG_SYNC_PLAYS;
}
@DebugLog
@Override
public void triggerRefresh() {
switch (mode) {
case MODE_ALL:
case MODE_BUDDY:
case MODE_PLAYER:
case MODE_LOCATION:
SyncService.sync(getActivity(), SyncService.FLAG_SYNC_PLAYS);
break;
case MODE_GAME:
SyncService.sync(getActivity(), SyncService.FLAG_SYNC_PLAYS_UPLOAD);
UpdateService.start(getActivity(), UpdateService.SYNC_TYPE_GAME_PLAYS, gameId);
break;
}
}
@Override
protected void onFabClicked() {
Intent intent = ActivityUtils.createEditPlayIntent(getActivity(), gameId, gameName, thumbnailUrl, imageUrl);
intent.putExtra(ActivityUtils.KEY_CUSTOM_PLAYER_SORT, arePlayersCustomSorted);
startActivity(intent);
}
public void filter(int type, String description) {
if (type != filterType && mode == MODE_ALL) {
filterType = type;
FilterEvent.log("Plays", String.valueOf(type));
EventBus.getDefault().postSticky(new PlaysFilterChangedEvent(filterType, description));
setEmptyText(getString(getEmptyStringResource()));
requery();
}
}
class PlayAdapter extends CursorAdapter implements StickyListHeadersAdapter {
private final LayoutInflater inflater;
public PlayAdapter(Context context) {
super(context, null, false);
inflater = getActivity().getLayoutInflater();
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View row = inflater.inflate(R.layout.row_play, parent, false);
ViewHolder holder = new ViewHolder(row);
row.setTag(holder);
return row;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
PlayModel play = PlayModel.fromCursor(cursor, getActivity());
String info = PresentationUtils.describePlayDetails(getActivity(),
mode != MODE_GAME ? play.getDate() : null,
play.getLocation(), play.getQuantity(), play.getLength(), play.getPlayerCount());
if (mode != MODE_GAME) {
holder.title.setText(play.getName());
} else {
holder.title.setText(play.getDate());
}
PresentationUtils.setTextOrHide(holder.text1, info);
PresentationUtils.setTextOrHide(holder.text2, play.getComments());
int statusMessageId = 0;
if (play.getDeleteTimestamp() > 0) {
statusMessageId = R.string.sync_pending_delete;
} else if (play.getUpdateTimestamp() > 0) {
statusMessageId = R.string.sync_pending_update;
} else if (play.getDirtyTimestamp() > 0) {
if (play.getPlayId() > 0) {
statusMessageId = R.string.sync_editing;
} else {
statusMessageId = R.string.sync_draft;
}
}
if (statusMessageId == 0) {
holder.status.setVisibility(View.GONE);
} else {
holder.status.setVisibility(View.VISIBLE);
holder.status.setText(statusMessageId);
}
}
@Override
public long getHeaderId(int position) {
if (position < 0 || sorter == null) {
return 0;
}
return sorter.getHeaderId(getCursor(), position);
}
@Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
if (convertView == null) {
holder = new HeaderViewHolder();
convertView = inflater.inflate(R.layout.row_header, parent, false);
holder.text = (TextView) convertView.findViewById(android.R.id.title);
convertView.setTag(holder);
} else {
holder = (HeaderViewHolder) convertView.getTag();
}
holder.text.setText(sorter == null ? "" : sorter.getHeaderText(getCursor(), position));
return convertView;
}
class ViewHolder {
@BindView(android.R.id.title) TextView title;
@BindView(android.R.id.text1) TextView text1;
@BindView(android.R.id.text2) TextView text2;
@BindView(android.R.id.message) TextView status;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
class HeaderViewHolder {
TextView text;
}
}
private interface GameQuery {
int _TOKEN = 0x22;
String[] PROJECTION = { Games.UPDATED_PLAYS };
int UPDATED_PLAYS = 0;
}
private interface SumQuery {
int _TOKEN = 0x23;
String[] PROJECTION = { Plays.SUM_QUANTITY };
int TOTAL_COUNT = 0;
}
private interface PlayerSumQuery {
int _TOKEN = 0x24;
String[] PROJECTION = { PlayPlayers.SUM_QUANTITY };
int SUM_QUANTITY = 0;
}
// TODO Add support for share option
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.plays_context, menu);
sendMenuItem = menu.findItem(R.id.menu_send);
editMenuItem = menu.findItem(R.id.menu_edit);
selectedPlaysPositions.clear();
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
if (!isAdded()) {
return;
}
if (checked) {
selectedPlaysPositions.add(position);
} else {
selectedPlaysPositions.remove(position);
}
int count = selectedPlaysPositions.size();
mode.setTitle(getResources().getQuantityString(R.plurals.msg_plays_selected, count, count));
boolean allPending = true;
for (int pos : selectedPlaysPositions) {
Cursor cursor = (Cursor) adapter.getItem(pos);
PlayModel play = PlayModel.fromCursor(cursor, getActivity());
boolean pending = play.getDirtyTimestamp() > 0;
allPending = allPending && pending;
}
sendMenuItem.setVisible(allPending);
editMenuItem.setVisible(count == 1);
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (!selectedPlaysPositions.iterator().hasNext()) {
return false;
}
switch (item.getItemId()) {
case R.id.menu_send:
mode.finish();
DialogUtils.createConfirmationDialog(getActivity(),
getResources().getQuantityString(R.plurals.are_you_sure_send_play, selectedPlaysPositions.size()),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
updateSelectedPlays(Plays.UPDATE_TIMESTAMP, System.currentTimeMillis());
}
}).show();
return true;
case R.id.menu_edit:
mode.finish();
Cursor cursor = (Cursor) adapter.getItem(selectedPlaysPositions.iterator().next());
long internalId = CursorUtils.getLong(cursor, Plays._ID, BggContract.INVALID_ID);
PlayModel play = PlayModel.fromCursor(cursor, getActivity());
ActivityUtils.editPlay(getActivity(), internalId, play.getGameId(), play.getName(), play.getThumbnailUrl(), play.getImageUrl());
return true;
case R.id.menu_delete:
mode.finish();
DialogUtils.createConfirmationDialog(
getActivity(),
getResources()
.getQuantityString(R.plurals.are_you_sure_delete_play, selectedPlaysPositions.size()),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
updateSelectedPlays(Plays.DELETE_TIMESTAMP, System.currentTimeMillis());
}
}).show();
return true;
}
return false;
}
private void updateSelectedPlays(String key, long value) {
ArrayList<ContentProviderOperation> batch = new ArrayList<>();
for (int position : selectedPlaysPositions) {
Cursor cursor = (Cursor) adapter.getItem(position);
long internalId = CursorUtils.getLong(cursor, Plays._ID, BggContract.INVALID_ID);
if (internalId != BggContract.INVALID_ID)
batch.add(ContentProviderOperation
.newUpdate(Plays.buildPlayUri(internalId))
.withValue(key, value)
.build());
}
ResolverUtils.applyBatch(getActivity(), batch);
SyncService.sync(getActivity(), SyncService.FLAG_SYNC_PLAYS_UPLOAD);
selectedPlaysPositions.clear();
}
}