package com.gk.simpleworkoutjournal; import android.app.AlertDialog; import android.content.DialogInterface; import android.database.Cursor; import android.util.Log; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AbsListView; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.Toast; import com.gk.datacontrol.DBClass; import java.util.HashSet; public class WJContext implements AbsListView.MultiChoiceModeListener, DialogInterface.OnClickListener { private static final String APP_NAME = "SWJournal"; private static final boolean DEBUG_FLAG = false; WorkoutJournal activity; WorkoutDataAdapter.Subject contextSubj; LinearLayout actionModeZone; Button ctxDeleteLogBtn, ctxCopyBtn; ImageButton ctxCancelBtn; ImageButton ctxAddBtn; EditText ctxEditRepsField; EditText ctxEditWeightField; AutoCompleteTextView ctxEditExField; ActionMode thisActionMode; String idOfSelected; WJContext(WorkoutJournal activity, WorkoutDataAdapter.Subject subj) { super(); this.activity = activity; this.contextSubj = subj; actionModeZone = (LinearLayout) activity.findViewById( R.id.actionModeZone); ctxCopyBtn = (Button)activity.findViewById(R.id.ctx_copySelectedBtn); ctxDeleteLogBtn = (Button)activity.findViewById(R.id.ctx_deleteLogEntriesBtn); ctxCancelBtn = (ImageButton)activity.findViewById(R.id.ctx_cancelBtn); ctxAddBtn = (ImageButton) activity.findViewById(R.id.ctx_addEditedBtn); ctxEditRepsField = (EditText)activity.findViewById(R.id.ctx_editReps); ctxEditWeightField = (EditText)activity.findViewById(R.id.ctx_editWeight); ctxEditExField = (AutoCompleteTextView) activity.findViewById(R.id.ctx_editExerciseACTV); } @Override public boolean onActionItemClicked(ActionMode actMode, MenuItem menuItem) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onActionItemClicked mode: " + actMode + " item: " + menuItem); WorkoutDataAdapter currAdapter; ListView currLv; switch ( contextSubj ) { case EXERCISES: currAdapter = activity.exerciseLogAdapter; currLv = activity.exercisesLv; break; case SETS: currAdapter = activity.setsLogAdapter; currLv = activity.setsLv; break; default: return false; } //get the only possible entry to work with if ( currAdapter.getcheckedAmount() != 1 ) { Log.e(APP_NAME, "WJContext :: onActionItemClicked: one checked expected, other amount is actually checked: "+currAdapter.getcheckedAmount()); return false; } Integer sequenceNumber = (Integer)currAdapter.getListIdsOfCtxChecked().toArray()[0]; Cursor entry = (Cursor)currLv.getItemAtPosition( sequenceNumber ); //launch appropriate action for this entry switch( menuItem.getItemId() ) { case R.id.context_action_rename_edit_single: if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onActionItemClicked case: edit/rename"); ctxCopyBtn.setVisibility(View.GONE); ctxDeleteLogBtn.setVisibility(View.GONE); ctxCancelBtn.setVisibility(View.VISIBLE); ctxAddBtn.setVisibility(View.VISIBLE); if ( contextSubj == WorkoutDataAdapter.Subject.EXERCISES ) { ctxEditExField.setVisibility(View.VISIBLE); ctxEditRepsField.setVisibility(View.GONE); ctxEditWeightField.setVisibility(View.GONE); ctxEditExField.setText( entry.getString( entry.getColumnIndex( DBClass.KEY_EX_NAME ) ) ); idOfSelected = entry.getString( entry.getColumnIndex( DBClass.KEY_EX_NAME )); } else { ctxEditExField.setVisibility(View.GONE); ctxEditRepsField.setVisibility(View.VISIBLE); ctxEditWeightField.setVisibility(View.VISIBLE); ctxEditRepsField.setText( entry.getString(entry.getColumnIndex(DBClass.KEY_REPS)) ); ctxEditWeightField.setText( entry.getString( entry.getColumnIndex( DBClass.KEY_WEIGHT ) ) ); idOfSelected = entry.getString( entry.getColumnIndex( DBClass.KEY_ID )); } break; case R.id.context_action_delete_ex: ctxCopyBtn.setVisibility(View.VISIBLE); ctxDeleteLogBtn.setVisibility(View.VISIBLE); ctxCancelBtn.setVisibility(View.GONE); ctxAddBtn.setVisibility(View.GONE); if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onActionItemClicked case: delete ex"); String exToDelete = entry.getString( entry.getColumnIndex("exercise_name") ); //some dialog over here AlertDialog.Builder alertBuilder = new AlertDialog.Builder( this.activity ); alertBuilder.setPositiveButton( R.string.delete, this ); alertBuilder.setNegativeButton( R.string.cancel, this ); alertBuilder.setTitle(exToDelete); alertBuilder.setMessage( activity.getResources().getString( R.string.delete_everything_related_to_ex )); AlertDialog alert = alertBuilder.create(); alert.show(); //rest of work will be done by alert handler break; default: Log.e(APP_NAME, "WJContext :: onActionItemClicked unexpected case"); break; } return true; } @Override public boolean onCreateActionMode(ActionMode actMode, Menu menu) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onCreateActionMode mode: "+actMode+" menu: "+menu); activity.currSubj = contextSubj; actionModeZone.setVisibility( View.VISIBLE ); thisActionMode = actMode; MenuInflater inflater = actMode.getMenuInflater(); inflater.inflate(R.menu.workout_context_menu, menu); return true; } @Override public void onDestroyActionMode(ActionMode actMode) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onDestroyActionMode mode: "+actMode); actionModeZone.setVisibility( View.GONE ); if ( !activity.setsLv.isEnabled() ) activity.setsLv.setEnabled( true ); if ( !activity.exercisesLv.isEnabled() ) activity.exercisesLv.setEnabled( true ); switch ( contextSubj ) { case EXERCISES: activity.exerciseLogAdapter.clearChecked(); break; case SETS: activity.setsLogAdapter.clearChecked(); break; } idOfSelected = ""; } @Override public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onPrepareActionMode mode: "+arg0+ " menu: "+arg1); // TODO Auto-generated method stub return true; } @Override public void onItemCheckedStateChanged(ActionMode actMode, int index, long arg2, boolean isChecked ) { //contextMode = startActionMode( this ); //required to set title later //TODO: check if need reduce scope of context mode. if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onItemCheckedStateChanged subject: " + contextSubj + " int: " + index + " long " + arg2 + " bool: " + isChecked); //reset buttons and editTexts onRestoreContextLookBtnPressed(); String actionBarText; WorkoutDataAdapter currAdapter; //if long click is the first click - we need to get currLv here. Potentially will need to define other current as well! switch ( this.contextSubj ) { case EXERCISES: //if changed from other listview if ( activity.setsLv.isEnabled() ) activity.setsLv.setEnabled( false ); actionBarText = activity.getString( R.string.exercises_chosen ); currAdapter = activity.exerciseLogAdapter; break; case SETS: //if changed from other listview if ( activity.exercisesLv.isEnabled() ) activity.exercisesLv.setEnabled( false ); actionBarText = activity.getString( R.string.sets_chosen ); currAdapter = activity.setsLogAdapter; break; default: return; } currAdapter.invertCtxChecked(index); currAdapter.notifyDataSetChanged(); //if all items deselected int checkedAmount = currAdapter.getcheckedAmount(); if ( checkedAmount == 0 ) { actMode.finish(); } else if ( checkedAmount == 1 ) { actMode.getMenu().getItem( 0 ).setVisible( true ); //edit btn ctxCopyBtn.setVisibility( View.VISIBLE ); if ( this.contextSubj == WorkoutDataAdapter.Subject.EXERCISES ) { actMode.getMenu().getItem(1).setVisible(true); // delete exercise btn } else { actMode.getMenu().getItem( 1 ).setVisible( false ); } } else { ctxCopyBtn.setVisibility( View.GONE ); actMode.getMenu().getItem( 0 ).setVisible( false ); actMode.getMenu().getItem( 1 ).setVisible( false ); } actionBarText += currAdapter.getcheckedAmount(); actMode.setTitle( actionBarText ); } public void copyButtonPressed(){ if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: copyButtonPressed : active context subject: "+contextSubj.toString() ); if ( contextSubj == WorkoutDataAdapter.Subject.EXERCISES ) { HashSet<Integer> ids = activity.exerciseLogAdapter.getListIdsOfCtxChecked(); if ( ids.size() != 1 ) { Log.e(APP_NAME, "WJContext :: copyButtonPressed : one selected expected for subject: "+contextSubj.toString() ); return; } Cursor entry = (Cursor) activity.exercisesLv.getItemAtPosition( (Integer)ids.toArray()[0] ); String ex = entry.getString(entry.getColumnIndex(DBClass.KEY_EX_NAME) ); activity.exerciseTextView.setText( ex ); activity.showEditsForSubject(WorkoutDataAdapter.Subject.EXERCISES); } else if ( contextSubj == WorkoutDataAdapter.Subject.SETS ) { HashSet<Integer> ids = activity.setsLogAdapter.getListIdsOfCtxChecked(); if ( ids.size() != 1 ) { Log.e(APP_NAME, "WJContext :: copyButtonPressed : one selected expected for subject: "+contextSubj.toString() ); return; } Cursor entry = (Cursor) activity.setsLv.getItemAtPosition( (Integer)ids.toArray()[0] ); String w = entry.getString(entry.getColumnIndex(DBClass.KEY_WEIGHT)); String r = entry.getString(entry.getColumnIndex(DBClass.KEY_REPS)); activity.weightEdit.setText( w ); activity.repsEdit.setText(r); } thisActionMode.finish(); } public void onDeleteLogEntriesPressed() { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onDeleteLogEntriesPressed : active context subject: "+contextSubj.toString() ); if ( contextSubj == WorkoutDataAdapter.Subject.EXERCISES ) { HashSet<Integer> ids = activity.exerciseLogAdapter.getListIdsOfCtxChecked(); int affectedSetEntries = 0; int affectedExEntries = 0; Cursor entry; for (Integer id : ids) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onDeleteLogEntriesPressed : following checked ex ID of item in list view to delete: " + id); entry = (Cursor) activity.exercisesLv.getItemAtPosition(id); long exId = entry.getLong( entry.getColumnIndex( DBClass.KEY_ID ) ); affectedSetEntries += activity.dbmediator.rmExLogEntry( exId, 1 ); affectedExEntries++; } int newMaxIdx = activity.setsLogAdapter.getCount() - affectedSetEntries - 1; if (activity.setsLogAdapter.getIdxOfCurrent() > newMaxIdx) activity.setsLogAdapter.setIdxOfCurrent(newMaxIdx); newMaxIdx = activity.exerciseLogAdapter.getCount() - affectedExEntries - 1; if (activity.exerciseLogAdapter.getIdxOfCurrent() > newMaxIdx) { activity.exerciseLogAdapter.setIdxOfCurrent(newMaxIdx); } if (affectedExEntries > 0) activity.initiateListUpdate(WorkoutDataAdapter.Subject.EXERCISES, WorkoutJournal.TriggerEvent.DELETE); } else if ( contextSubj == WorkoutDataAdapter.Subject.SETS ) { HashSet<Integer> setIds = activity.setsLogAdapter.getListIdsOfCtxChecked(); int affectedSetEntries = 0; HashSet<Integer> exIds = new HashSet<Integer>(); Cursor entry; for (Integer id : setIds) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onDeleteLogEntriesPressed : following checked set ID of item in list view to delete: " + id); entry = (Cursor) activity.setsLv.getItemAtPosition(id); exIds.add( entry.getInt(entry.getColumnIndex(DBClass.KEY_EX_LOG_ID)) ); affectedSetEntries += activity.dbmediator.rmSetLogEntry(entry); } //if ex log entry have no related sets - get rid of it as well int affectedExEntries = 0; for (Integer id : exIds) { if ( !activity.dbmediator.haveSetsWithExId( id ) ) { affectedExEntries += activity.dbmediator.rmExLogEntry( id , 0 ); } } //need to refresh ex list if some ex entry was removed //same code for ex and set if ( affectedExEntries != 0 ) { int newMaxIdx = activity.exerciseLogAdapter.getCount() - affectedExEntries - 1; if (activity.exerciseLogAdapter.getIdxOfCurrent() > newMaxIdx) activity.exerciseLogAdapter.setIdxOfCurrent(newMaxIdx); activity.initiateListUpdate(WorkoutDataAdapter.Subject.EXERCISES, WorkoutJournal.TriggerEvent.DELETE); } if (affectedSetEntries != 0) { int newMaxIdx = activity.setsLogAdapter.getCount() - affectedSetEntries - 1; if (activity.setsLogAdapter.getIdxOfCurrent() > newMaxIdx) activity.setsLogAdapter.setIdxOfCurrent(newMaxIdx); activity.initiateListUpdate(WorkoutDataAdapter.Subject.SETS, WorkoutJournal.TriggerEvent.DELETE); } } thisActionMode.finish(); } public void onRestoreContextLookBtnPressed() { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onRestoreContextLookBtnPressed"); ctxCancelBtn.setVisibility(View.GONE); ctxAddBtn.setVisibility(View.GONE); ctxEditRepsField.setVisibility(View.GONE); ctxEditWeightField.setVisibility(View.GONE); ctxEditExField.setVisibility(View.GONE); ctxDeleteLogBtn.setVisibility(View.VISIBLE); ctxCopyBtn.setVisibility(View.VISIBLE); ctxEditWeightField.setText(""); ctxEditRepsField.setText(""); ctxEditExField.setText(""); } public void onAddEditedBtnPressed() { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onAddEditedBtnPressed \""+ctxEditExField.getText().toString()+"\"" ); if ( idOfSelected.isEmpty() ) { Log.e(APP_NAME, "WJContext :: onAddEditedBtnPressed : ID of selected item is unknown"); return; } String newName = ctxEditExField.getText().toString().trim(); String newReps = ctxEditRepsField.getText().toString().trim(); String newWeight = ctxEditWeightField.getText().toString().trim(); boolean haveError = false; if ( (contextSubj == WorkoutDataAdapter.Subject.EXERCISES && newName.isEmpty() ) ) { haveError = true; } else if ( contextSubj == WorkoutDataAdapter.Subject.SETS && ( newReps.isEmpty() || newWeight.isEmpty() ) ) { haveError = true; } if ( haveError ) { Toast.makeText( activity, "Empty fields are not allowed", Toast.LENGTH_SHORT).show(); // TODO: make a string resources for this toast } if ( !haveError ) { switch ( contextSubj ) { case EXERCISES: if ( !activity.dbmediator.updateExercise( idOfSelected, newName ) ) { Log.w(APP_NAME, "Cannot rename: exercise with this name already exist (orig: "+idOfSelected+" new: " +newName+")"); haveError = true; Toast.makeText( activity, "Cannot rename: exercise with this name already exist", Toast.LENGTH_SHORT).show(); // TODO: make a string resources for this toast } break; case SETS: activity.dbmediator.updateSetLog( idOfSelected, newReps, newWeight.equals(".") ? "0" : newWeight); break; } if ( !haveError ) { activity.initiateListUpdate( contextSubj, WorkoutJournal.TriggerEvent.EDIT ); //TODO: need other, separate event? activity.exerciseLogAdapter.notifyDataSetChanged(); onRestoreContextLookBtnPressed(); } } if( !haveError ) { idOfSelected = ""; thisActionMode.finish(); } } private void deleteSelectedExercise() { Integer idOfChecked = (Integer)activity.exerciseLogAdapter.getListIdsOfCtxChecked().toArray()[0]; int deletedExLogs = activity.dbmediator.deleteEx( (Cursor)activity.exercisesLv.getItemAtPosition( idOfChecked ) ); if ( deletedExLogs != 0 ) { int newMaxIdx = activity.exerciseLogAdapter.getCount() - deletedExLogs - 1; //handle idx of current if (activity.exerciseLogAdapter.getIdxOfCurrent() > newMaxIdx) activity.exerciseLogAdapter.setIdxOfCurrent(newMaxIdx); ///handle idx of checked if ( idOfChecked > newMaxIdx ) { activity.exerciseLogAdapter.invertCtxChecked( newMaxIdx ); //select activity.exerciseLogAdapter.invertCtxChecked( idOfChecked ); //deselect } //show renewed data for exercises activity.initiateListUpdate(WorkoutDataAdapter.Subject.EXERCISES, WorkoutJournal.TriggerEvent.DELETE); //make sure exercise edit is active actionModeZone.setVisibility( View.GONE ); activity.showEditsForSubject(WorkoutDataAdapter.Subject.EXERCISES); //empty hint box for set since we have chosen other exercise activity.setNoteTv.setHint(activity.getString(R.string.workout_set_no_note_hint)); activity.setNoteTv.setText(""); //now take care of sets if ( newMaxIdx == -1 ) { activity.setsLv.setAdapter(null); return; } //update sets list view accordingly activity.initiateListUpdate( WorkoutDataAdapter.Subject.SETS, WorkoutJournal.TriggerEvent.DELETE ); } } @Override public void onClick(DialogInterface dialog, int which) { if ( DEBUG_FLAG ) Log.v(APP_NAME, "WJContext :: onClick of alert dialog pressed. dialog: "+dialog+ " which: "+which ); switch ( which ) { case -1: // Delete button deleteSelectedExercise(); break; case -2: // Cancel button break; } } }