package be.digitalia.fosdem.adapters; import android.content.Context; import android.database.Cursor; import android.graphics.Typeface; import android.os.AsyncTask; import android.os.Parcelable; import android.support.annotation.ColorInt; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ActionMode; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.view.Menu; import android.view.MenuItem; import android.view.View; import java.util.Date; import be.digitalia.fosdem.R; import be.digitalia.fosdem.db.DatabaseManager; import be.digitalia.fosdem.model.Event; import be.digitalia.fosdem.model.Track; import be.digitalia.fosdem.widgets.MultiChoiceHelper; public class BookmarksAdapter extends EventsAdapter { @ColorInt private final int errorColor; final MultiChoiceHelper multiChoiceHelper; public BookmarksAdapter(AppCompatActivity activity) { super(activity); errorColor = ContextCompat.getColor(activity, R.color.error_material); multiChoiceHelper = new MultiChoiceHelper(activity, this); multiChoiceHelper.setMultiChoiceModeListener(new MultiChoiceHelper.MultiChoiceModeListener() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.action_mode_bookmarks, menu); return true; } private void updateSelectedCountDisplay(ActionMode mode) { int count = multiChoiceHelper.getCheckedItemCount(); mode.setTitle(multiChoiceHelper.getContext().getResources().getQuantityString(R.plurals.selected, count, count)); } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { updateSelectedCountDisplay(mode); return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.delete: // Remove multiple bookmarks at once new RemoveBookmarksAsyncTask().execute(multiChoiceHelper.getCheckedItemIds()); mode.finish(); return true; } return false; } @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { updateSelectedCountDisplay(mode); } @Override public void onDestroyActionMode(ActionMode mode) { } }); } public Parcelable onSaveInstanceState() { return multiChoiceHelper.onSaveInstanceState(); } public void onRestoreInstanceState(Parcelable state) { multiChoiceHelper.onRestoreInstanceState(state); } public void onDestroyView() { multiChoiceHelper.clearChoices(); } @Override public void onBindViewHolder(ViewHolder holder, Cursor cursor) { final int position = cursor.getPosition(); Context context = holder.itemView.getContext(); Event event = DatabaseManager.toEvent(cursor, holder.event); holder.event = event; holder.title.setText(event.getTitle()); String personsSummary = event.getPersonsSummary(); holder.persons.setText(personsSummary); holder.persons.setVisibility(TextUtils.isEmpty(personsSummary) ? View.GONE : View.VISIBLE); Track track = event.getTrack(); holder.trackName.setText(track.getName()); holder.trackName.setTextColor(ContextCompat.getColor(holder.trackName.getContext(), track.getType().getColorResId())); holder.trackName.setContentDescription(context.getString(R.string.track_content_description, track.getName())); Date startTime = event.getStartTime(); Date endTime = event.getEndTime(); String startTimeString = (startTime != null) ? timeDateFormat.format(startTime) : "?"; String endTimeString = (endTime != null) ? timeDateFormat.format(endTime) : "?"; String details = String.format("%1$s, %2$s ― %3$s | %4$s", event.getDay().getShortName(), startTimeString, endTimeString, event.getRoomName()); String detailsContentDescription = details; // Highlight the date and time with error color in case of conflicting schedules if (isOverlapping(cursor, startTime, endTime)) { SpannableString detailsSpannable = new SpannableString(details); int endPosition = details.indexOf(" | "); detailsSpannable.setSpan(new ForegroundColorSpan(errorColor), 0, endPosition, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); detailsSpannable.setSpan(new StyleSpan(Typeface.BOLD), 0, endPosition, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); holder.details.setText(detailsSpannable); detailsContentDescription = context.getString(R.string.bookmark_conflict_content_description, detailsContentDescription); } else { holder.details.setText(details); } holder.details.setContentDescription(context.getString(R.string.details_content_description, detailsContentDescription)); // Enable MultiChoice selection and update checked state holder.bind(multiChoiceHelper, position); } /** * Checks if the current event is overlapping with the previous or next one. * Warning: this methods will update the cursor's position. */ private static boolean isOverlapping(Cursor cursor, Date startTime, Date endTime) { final int position = cursor.getPosition(); if ((startTime != null) && (position > 0) && cursor.moveToPosition(position - 1)) { long previousEndTime = DatabaseManager.toEventEndTimeMillis(cursor); if ((previousEndTime != -1L) && (previousEndTime > startTime.getTime())) { // The event overlaps with the previous one return true; } } if ((endTime != null) && (position < (cursor.getCount() - 1)) && cursor.moveToPosition(position + 1)) { long nextStartTime = DatabaseManager.toEventStartTimeMillis(cursor); if ((nextStartTime != -1L) && (nextStartTime < endTime.getTime())) { // The event overlaps with the next one return true; } } return false; } static class RemoveBookmarksAsyncTask extends AsyncTask<long[], Void, Void> { @Override protected Void doInBackground(long[]... params) { DatabaseManager.getInstance().removeBookmarks(params[0]); return null; } } }