package se.johan.wendler.fragment; import android.annotation.SuppressLint; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.mobeta.android.dslv.DragSortListView; import com.mobeta.android.dslv.SimpleFloatViewManager; import com.nispok.snackbar.Snackbar; import com.nispok.snackbar.SnackbarManager; import com.nispok.snackbar.listeners.ActionClickListener; import com.nispok.snackbar.listeners.EventListener; import java.util.ArrayList; import se.johan.wendler.R; import se.johan.wendler.fragment.base.WorkoutFragment; import se.johan.wendler.model.Action; import se.johan.wendler.model.AdditionalExercise; import se.johan.wendler.model.TapToUndoItem; import se.johan.wendler.model.Workout; import se.johan.wendler.sql.SqlHandler; import se.johan.wendler.ui.adapter.AdditionalExerciseAdapter; import se.johan.wendler.ui.dialog.AdditionalExerciseDialog; import se.johan.wendler.util.CardsOptionHandler; /** * WorkoutFragment for additional exercises. */ public class WorkoutAdditionalFragment extends WorkoutFragment implements DragSortListView.DropListener, DragSortListView.RemoveListener, AdditionalExerciseDialog.onConfirmClickedListener, Action.ActionListener { public static final String TAG = WorkoutAdditionalFragment.class.getName(); private static final String EXTRA_EXERCISE_ITEM = "exerciseItem"; private static final String EXTRA_WORKOUT_NAME = "workoutName"; private static ArrayList<AdditionalExercise> sAdditionalExercises = new ArrayList<AdditionalExercise>(); private AdditionalExerciseAdapter mAdapter; private DragSortListView mListView; private boolean mIsModified; public WorkoutAdditionalFragment() { } /** * Static creation to avoid problems on rotation. */ public static WorkoutAdditionalFragment newInstance( ArrayList<AdditionalExercise> additionalExercises, String workoutName) { Bundle arguments = new Bundle(); arguments.putParcelableArrayList(EXTRA_EXERCISE_ITEM, additionalExercises); arguments.putString(EXTRA_WORKOUT_NAME, workoutName); WorkoutAdditionalFragment fragment = new WorkoutAdditionalFragment(); fragment.setArguments(arguments); return fragment; } /** * Called when the view is created. */ @SuppressLint("WrongViewCast") @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.list_drag, container, false); sAdditionalExercises = getArguments().getParcelableArrayList(EXTRA_EXERCISE_ITEM); mListView = (DragSortListView) view.findViewById(R.id.list_drag); mAdapter = new AdditionalExerciseAdapter( getActivity(), sAdditionalExercises, mCardHandler, AdditionalExerciseAdapter.TYPE_WORKOUT); mListView.setAdapter(mAdapter); mListView.setDragEnabled(true); mListView.setDropListener(this); buildController(); return view; } /** * Called when additional exercises are reordered. */ @Override public void drop(int from, int to) { AdditionalExercise exercise = sAdditionalExercises.get(from); sAdditionalExercises.remove(exercise); sAdditionalExercises.add(to, exercise); mAdapter.notifyDataSetChanged(); mIsModified = true; } /** * Called when an additional exercise is removed. */ @Override public void remove(int which) { onRemove(which); } /** * Called when the confirmation dialog is confirmed. */ @Override public void onConfirmClicked(AdditionalExercise exercise) { int pos = getPosForAdditionalExercise(exercise.getExerciseId()); if (pos < 0) { sAdditionalExercises.add(exercise); } else { sAdditionalExercises.set(pos, exercise); } mIsModified = true; mAdapter.notifyDataSetChanged(); } /** * Called when the workout should be stored. */ @Override public boolean storeWorkout(boolean complete, Workout workout, SqlHandler handler, boolean delayedDeload) { boolean isStarted = mIsModified || isAnyExerciseStarted(); return handler.storeAdditionalExercise( workout.getWorkoutId(), sAdditionalExercises, isStarted); } /** * Called when an action in the floating action button is performed. */ @Override public void onActionTaken(Action action) { switch (action) { case ADD_EXERCISE: showAdditionalExerciseDialog(null, getNextExerciseId()); break; } } /** * Called to launch the additional exercise dialog. */ private void showAdditionalExerciseDialog(AdditionalExercise exercise, int id) { AdditionalExerciseDialog.newInstance( getString(R.string.add_exercise), exercise, id, this).show(getFragmentManager(), AdditionalExerciseDialog.TAG); } /** * Called to remove an additional exercise at a given position. */ private void onRemove(int which) { if (which >= sAdditionalExercises.size()) { return; } mIsModified = true; AdditionalExercise exercise = sAdditionalExercises.get(which); TapToUndoItem item = new TapToUndoItem(exercise, which); sAdditionalExercises.remove(which); createSnackBar(exercise, item); mAdapter.notifyDataSetChanged(); } /** * Create a snack bar where the user can undo the deletion. */ private void createSnackBar(AdditionalExercise exercise, TapToUndoItem item) { SnackbarManager.dismiss(); Snackbar bar = Snackbar.with(getActivity()) .text(getSnackBarText(exercise)) .actionLabel(getString(R.string.undo)) .actionListener(getActionListener(item)) .eventListener(getEventListener()); SnackbarManager.show(bar); } /** * Returns the event listener for the snack bar. */ private EventListener getEventListener() { if (getActivity() instanceof EventListener) { return (EventListener) getActivity(); } return null; } /** * Returns an ActionListener for undoing the deletion. */ private ActionClickListener getActionListener(final TapToUndoItem item) { return new ActionClickListener() { @Override public void onActionClicked(Snackbar snackbar) { sAdditionalExercises.add(item.getPosition(), (AdditionalExercise) item.getObject()); mAdapter.notifyDataSetChanged(); } }; } /** * Returns the text for the snack bar. */ private String getSnackBarText(AdditionalExercise exercise) { return String.format(getString(R.string.snack_bar_deleted), exercise.getName()); } /** * Build the controller for the ListView. */ private void buildController() { SimpleFloatViewManager simpleFloatViewManager = new SimpleFloatViewManager(mListView); simpleFloatViewManager.setBackgroundColor(Color.TRANSPARENT); mListView.setFloatViewManager(simpleFloatViewManager); mListView.setRemoveListener(this); } /** * Return the next available exercise id. */ private int getNextExerciseId() { int id = 1; for (AdditionalExercise exercise : sAdditionalExercises) { if (exercise.getExerciseId() > id) { id = exercise.getExerciseId(); } } return ++id; } /** * Return the position or -1 for a given exercise id. */ private int getPosForAdditionalExercise(int exerciseId) { for (int i = 0; i < sAdditionalExercises.size(); i++) { if (sAdditionalExercises.get(i).getExerciseId() == exerciseId) { return i; } } return -1; } /** * Returns true if any of the exercises are started. */ private boolean isAnyExerciseStarted() { for (AdditionalExercise exercise : sAdditionalExercises) { if (exercise.isStarted()) { return true; } } return false; } /** * Handler for the additional exercise cards. */ private final CardsOptionHandler mCardHandler = new CardsOptionHandler() { /** * Called when an additional exercise is deleted. */ @Override public void onDelete(int position) { onRemove(position); } /** * Called when an additional exercise should be edited. */ @Override public void onEdit(int position) { AdditionalExercise exercise = sAdditionalExercises.get(position); showAdditionalExerciseDialog(exercise, exercise.getExerciseId()); } }; }