package org.adaptlab.chpir.android.survey; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import org.adaptlab.chpir.android.activerecordcloudsync.ActiveRecordCloudSync; import org.adaptlab.chpir.android.activerecordcloudsync.NetworkNotificationUtils; import org.adaptlab.chpir.android.survey.Models.Instrument; import org.adaptlab.chpir.android.survey.Models.Response; import org.adaptlab.chpir.android.survey.Models.Survey; import org.adaptlab.chpir.android.survey.Rules.InstrumentLaunchRule; import org.adaptlab.chpir.android.survey.Rules.RuleBuilder; import org.adaptlab.chpir.android.survey.Rules.RuleCallback; import org.adaptlab.chpir.android.survey.Tasks.DownloadImagesTask; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.text.InputType; import android.util.Log; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class InstrumentFragment extends ListFragment { public final static String TAG = "InstrumentFragment"; private List<Survey> mSurveys; private SurveyAdapter mSurveyAdapter; private ListView mSurveyListView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); setListAdapter(new InstrumentAdapter(Instrument.getAll())); AppUtil.appInit(getActivity()); } private void downloadInstrumentImages() { new DownloadImagesTask(getActivity()).execute(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.fragment_instrument, menu); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); if (getResources().getBoolean(R.bool.default_admin_settings)) { menu.findItem(R.id.menu_item_admin).setEnabled(false); menu.findItem(R.id.menu_item_admin).setVisible(false); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_item_admin: displayPasswordPrompt(); return true; case R.id.menu_item_refresh: new RefreshInstrumentsTask().execute(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onResume() { super.onResume(); setListAdapter(new InstrumentAdapter(Instrument.getAll())); createTabs(); } public void createTabs() { if (AppUtil.getAdminSettingsInstance().getShowSurveys()) { final ActionBar actionBar = getActivity().getActionBar(); ActionBar.TabListener tabListener = new ActionBar.TabListener() { @Override public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) { if (tab.getText().equals(getActivity().getResources().getString(R.string.surveys))) { if (Survey.getAll().isEmpty()) { setListAdapter(null); } else { mSurveys = Survey.getAllProjectSurveys(Long.parseLong(AppUtil.getAdminSettingsInstance().getProjectId())); mSurveyAdapter = new SurveyAdapter(mSurveys); setListAdapter(mSurveyAdapter); mSurveyListView = getListView(); mSurveyListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mSurveyListView.setMultiChoiceModeListener(mListener); } } else { setListAdapter(new InstrumentAdapter(Instrument.getAllProjectInstruments(Long.parseLong(AppUtil.getAdminSettingsInstance().getProjectId())))); } } // Required by interface public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) { } public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) { } }; actionBar.removeAllTabs(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.addTab(actionBar.newTab().setText(getActivity().getResources().getString(R.string.instruments)).setTabListener(tabListener)); actionBar.addTab(actionBar.newTab().setText(getActivity().getResources().getString(R.string.surveys)).setTabListener(tabListener)); } } private MultiChoiceModeListener mListener = new MultiChoiceModeListener() { List<Survey> selected = new ArrayList<Survey>(); @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { Survey survey = mSurveys.get(position); if (checked) { selected.add(survey); mSurveyAdapter.setNewSelection(position, true); } else { selected.remove(survey); mSurveyAdapter.setNewSelection(position, false); } } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_delete_item: showDeleteSurveysWarning(); mode.finish(); return true; default: return false; } } private void showDeleteSurveysWarning() { new AlertDialog.Builder(getActivity()) .setTitle(R.string.delete_surveys_title) .setMessage(R.string.delete_surveys_message) .setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { mSurveys.removeAll(selected); deleteSurveys(); mSurveyAdapter.notifyDataSetChanged(); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) {} }) .show(); } private void deleteSurveys() { for(Survey survey : selected) { for(Response response : survey.responses()) { response.delete(); } survey.delete(); } } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.list_view_item_delete, menu); return true; } @Override public void onDestroyActionMode(ActionMode mode) { mSurveyAdapter.clearSelection(); mSurveyAdapter.notifyDataSetChanged(); } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return true; } }; private class InstrumentAdapter extends ArrayAdapter<Instrument> { public InstrumentAdapter(List<Instrument> instruments) { super(getActivity(), 0, instruments); } @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater().inflate( R.layout.list_item_instrument, null); } if (position % 2 == 0) { convertView.setBackgroundResource(R.drawable.list_background_color); } else { convertView.setBackgroundResource(R.drawable.list_background_color_alternate); } Instrument instrument = getItem(position); TextView titleTextView = (TextView) convertView .findViewById(R.id.instrument_list_item_titleTextView); titleTextView.setText(instrument.getTitle()); titleTextView.setTypeface(instrument.getTypeFace(getActivity().getApplicationContext())); titleTextView.setTextColor(Color.BLACK); new SetInstrumentLabelTask().execute(new InstrumentListLabel(instrument, titleTextView)); TextView questionCountTextView = (TextView) convertView .findViewById(R.id.instrument_list_item_questionCountTextView); int numQuestions = instrument.questions().size(); questionCountTextView.setText(numQuestions + " " + FormatUtils.pluralize(numQuestions, getString(R.string.question), getString(R.string.questions))); TextView instrumentVersionTextView = (TextView) (TextView) convertView.findViewById(R.id.instrument_list_item_instrumentVersionTextView); instrumentVersionTextView.setText(getString(R.string.version) + ": " + instrument.getVersionNumber()); return convertView; } } private class SurveyAdapter extends ArrayAdapter<Survey> { private SparseBooleanArray mSelectionViews = new SparseBooleanArray(); public SurveyAdapter(List<Survey> surveys) { super(getActivity(), 0, surveys); } public void setNewSelection(int position, boolean value) { mSelectionViews.put(position, value); notifyDataSetChanged(); } public boolean isPositionChecked(int position) { Boolean result = mSelectionViews.get(position); return result == null ? false : result; } public void clearSelection() { mSelectionViews.clear(); notifyDataSetChanged(); } @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_survey, null); } if (position % 2 == 0) { convertView.setBackgroundResource(R.drawable.list_background_color); } else { convertView.setBackgroundResource(R.drawable.list_background_color_alternate); } if (mSelectionViews != null && mSurveyAdapter.isPositionChecked(position) != false) { convertView.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light)); } Survey survey = getItem(position); TextView titleTextView = (TextView) convertView .findViewById(R.id.survey_list_item_titleTextView); titleTextView.setText(survey.identifier(getActivity())); titleTextView.setTypeface(survey.getInstrument().getTypeFace(getActivity().getApplicationContext())); TextView progressTextView = (TextView) convertView.findViewById(R.id.survey_list_item_progressTextView); progressTextView.setText(survey.responses().size() + " " + getString(R.string.of) + " " + survey.getInstrument().questions().size()); if (survey.readyToSend()) { progressTextView.setTextColor(Color.GREEN); } else { progressTextView.setTextColor(Color.RED); } TextView instrumentTitleTextView = (TextView) convertView.findViewById(R.id.survey_list_item_instrumentTextView); instrumentTitleTextView.setText(survey.getInstrument().getTitle()); TextView lastUpdatedTextView = (TextView) convertView.findViewById(R.id.survey_list_item_lastUpdatedTextView); SimpleDateFormat df = new SimpleDateFormat("HH:mm yyyy-MM-dd"); lastUpdatedTextView.setText(df.format(survey.getLastUpdated())); return convertView; } } @Override public void onListItemClick(ListView l, View v, int position, long id) { if (l.getAdapter() instanceof InstrumentAdapter) { Instrument instrument = ((InstrumentAdapter) getListAdapter()).getItem(position); if (instrument == null) return; new LoadInstrumentTask().execute(instrument); } else if (l.getAdapter() instanceof SurveyAdapter) { Survey survey = ((SurveyAdapter) getListAdapter()).getItem(position); if (survey == null) return; new LoadSurveyTask().execute(survey); } } /* * Only display admin area if correct password. */ private void displayPasswordPrompt() { final EditText input = new EditText(getActivity()); input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); new AlertDialog.Builder(getActivity()) .setTitle(R.string.password_title) .setMessage(R.string.password_message) .setView(input) .setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int button) { if (AppUtil.checkAdminPassword(input.getText().toString())) { Intent i = new Intent(getActivity(), AdminActivity.class); startActivity(i); } else { Toast.makeText(getActivity(), R.string.incorrect_password, Toast.LENGTH_LONG).show(); } } }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int button) { } }).show(); } /* * Refresh the receive tables from the server */ private class RefreshInstrumentsTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { getActivity().setProgressBarIndeterminateVisibility(true); setListAdapter(null); } @Override protected Void doInBackground(Void... params) { if (isAdded() && NetworkNotificationUtils.checkForNetworkErrors(getActivity())) { ActiveRecordCloudSync.syncSendTables(getActivity()); ActiveRecordCloudSync.syncReceiveTables(getActivity()); } return null; } @Override protected void onPostExecute(Void param) { if (isAdded()) { downloadInstrumentImages(); if (AppUtil.getAdminSettingsInstance().getProjectId() != null) { setListAdapter(new InstrumentAdapter(Instrument.getAllProjectInstruments(Long.parseLong(AppUtil.getAdminSettingsInstance().getProjectId())))); } getActivity().setProgressBarIndeterminateVisibility(false); } } } /* * Check that the instrument has been fully loaded from the server before allowing * user to begin survey. */ private class LoadInstrumentTask extends AsyncTask<Instrument, Void, Long> { ProgressDialog mProgressDialog; @Override protected void onPreExecute() { mProgressDialog = ProgressDialog.show( getActivity(), getString(R.string.instrument_loading_progress_header), getString(R.string.instrument_loading_progress_message) ); } /* * If instrument is loaded, return the instrument id. * If not, return -1. */ @Override protected Long doInBackground(Instrument... params) { Instrument instrument = params[0]; if (instrument.loaded()) { return instrument.getRemoteId(); } else { return Long.valueOf(-1); } } @Override protected void onPostExecute(final Long instrumentId) { try { mProgressDialog.dismiss(); } catch (IllegalArgumentException iae) { Log.e(TAG, "Tried to close progress dialog that does not exist."); } if (isAdded()){ if (instrumentId == Long.valueOf(-1)) { Toast.makeText(getActivity(), R.string.instrument_not_loaded, Toast.LENGTH_LONG).show(); } else { new RuleBuilder(getActivity()) .addRule(new InstrumentLaunchRule(Instrument.findByRemoteId(instrumentId), getActivity().getString(R.string.rule_failure_instrument_launch))) .showToastOnFailure(true) .setCallbacks(new RuleCallback() { public void onRulesPass() { Intent i = new Intent(getActivity(), SurveyActivity.class); i.putExtra(SurveyFragment.EXTRA_INSTRUMENT_ID, instrumentId); startActivity(i); } public void onRulesFail() { } }) .checkRules(); } } } } private class LoadSurveyTask extends AsyncTask<Survey, Void, Survey> { ProgressDialog mProgressDialog; @Override protected void onPreExecute() { mProgressDialog = ProgressDialog.show( getActivity(), getString(R.string.instrument_loading_progress_header), getString(R.string.instrument_loading_progress_message) ); } /* * If instrument is loaded, return the survey. * If not, return null. */ @Override protected Survey doInBackground(Survey... params) { Survey survey = params[0]; Instrument instrument = survey.getInstrument(); if (instrument.loaded()) { return survey; } else { return null; } } @Override protected void onPostExecute(Survey survey) { try { mProgressDialog.dismiss(); } catch (IllegalArgumentException iae) { Log.e(TAG, "Tried to close progress dialog that does not exist."); } if (isAdded()) { if (survey == null) { Toast.makeText(getActivity(), R.string.instrument_not_loaded, Toast.LENGTH_LONG).show(); } else { Intent i = new Intent(getActivity(), SurveyActivity.class); i.putExtra(SurveyFragment.EXTRA_INSTRUMENT_ID, survey.getInstrument().getRemoteId()); i.putExtra(SurveyFragment.EXTRA_SURVEY_ID, survey.getId()); i.putExtra(SurveyFragment.EXTRA_QUESTION_ID, survey.getLastQuestion().getId()); startActivity(i); } } } } /* * Check that the instrument has been fully loaded from the server and sets * the color of instrument label red if it has not. * */ private class SetInstrumentLabelTask extends AsyncTask<InstrumentListLabel, Void, InstrumentListLabel> { @Override protected InstrumentListLabel doInBackground(InstrumentListLabel... params) { InstrumentListLabel instrumentListLabel = params[0]; Instrument instrument = instrumentListLabel.getInstrument(); instrumentListLabel.setLoaded(instrument.loaded()); return instrumentListLabel; } @Override protected void onPostExecute(InstrumentListLabel instrumentListLabel) { if (isAdded()){ if (instrumentListLabel.isLoaded()) { instrumentListLabel.getTextView().setTextColor(Color.BLACK); } else { instrumentListLabel.getTextView().setTextColor(Color.RED); } } } } private static class InstrumentListLabel { private Instrument mInstrument; private TextView mTextView; private Boolean mLoaded; public InstrumentListLabel(Instrument instrument, TextView textView) { this.mInstrument = instrument; this.mTextView = textView; } public Instrument getInstrument() { return mInstrument; } public TextView getTextView() { return mTextView; } public void setLoaded(boolean loaded) { mLoaded = loaded; } public Boolean isLoaded() { return mLoaded; } } }