package org.ohmage.activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.google.android.imageloader.ImageLoader;
import org.ohmage.AccountHelper;
import org.ohmage.R;
import org.ohmage.UserPreferencesHelper;
import org.ohmage.async.CampaignXmlDownloadTask;
import org.ohmage.controls.ActionBarControl;
import org.ohmage.controls.ActionBarControl.ActionListener;
import org.ohmage.db.DbContract.Campaigns;
import org.ohmage.db.Models.Campaign;
import org.ohmage.logprobe.Analytics;
import org.ohmage.triggers.base.TriggerDB;
import org.ohmage.ui.BaseInfoActivity;
import org.ohmage.ui.OhmageFilterable.CampaignFilter;
public class CampaignInfoActivity extends BaseInfoActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private static final int TRIGGER_UPDATE_FINISHED = 0;
// helpers
private FragmentActivity mContext;
private AccountHelper mAccount;
private ImageLoader mImageLoader;
// action bar commands
private static final int ACTION_TAKE_SURVEY = 1;
private static final int ACTION_VIEW_RESPHISTORY = 2;
private static final int ACTION_SETUP_TRIGGERS = 3;
// handles to views we'll be manipulating
private TextView mErrorBox;
private TextView mDescView;
private TextView mPrivacyValue;
private TextView mStatusValue;
private TextView mResponsesValue;
private TextView mTriggersValue;
// state vars
private int mCampaignStatus; // status code for campaign as of last refresh
private int mLocalResponses;
private String mCampaignUrn;
private int mTriggerCount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// save the context so the action bar can use it to fire off intents
mContext = this;
mAccount = new AccountHelper(this);
mImageLoader = ImageLoader.get(this);
setContentView(R.layout.campaign_info_details);
// and inflate all the possible commands into the button tray
getLayoutInflater().inflate(R.layout.campaign_info_buttons, mButtonTray, true);
// clear some things to their default values
mNotetext.setVisibility(View.GONE);
// nab references to things we'll be populating
mErrorBox = (TextView)findViewById(R.id.campaign_info_errorbox);
mDescView = (TextView)findViewById(R.id.campaign_info_desc);
mPrivacyValue = (TextView)findViewById(R.id.campaign_info_privacy_value);
mStatusValue = (TextView)findViewById(R.id.campaign_info_status_value);
mResponsesValue = (TextView)findViewById(R.id.campaign_info_responses_value);
mTriggersValue = (TextView)findViewById(R.id.campaign_info_triggers_value);
// and attach some handlers + populate some html data
// privacy
TextView privacyDetails = (TextView)findViewById(R.id.campaign_info_privacy_details);
privacyDetails.setText(Html.fromHtml(getString(R.string.campaign_info_privacy_details)));
setDetailsExpansionHandler(
findViewById(R.id.campaign_info_privacy_row),
privacyDetails);
// status
TextView statusDetails = (TextView)findViewById(R.id.campaign_info_status_details);
statusDetails.setText(Html.fromHtml(getString(R.string.campaign_info_status_details)));
setDetailsExpansionHandler(
findViewById(R.id.campaign_info_status_row),
statusDetails);
// responses
TextView responsesDetails = (TextView)findViewById(R.id.campaign_info_responses_details);
responsesDetails.setText(Html.fromHtml(getString(R.string.campaign_info_responses_details)));
setDetailsExpansionHandler(
findViewById(R.id.campaign_info_responses_row),
responsesDetails);
// triggers
TextView triggersDetails = (TextView)findViewById(R.id.campaign_info_triggers_details);
triggersDetails.setText(Html.fromHtml(getString(R.string.campaign_info_triggers_details)));
setDetailsExpansionHandler(
findViewById(R.id.campaign_info_triggers_row),
triggersDetails);
// hide our content behind the overlay before we load
setLoadingVisibility(true);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getSupportLoaderManager().initLoader(0, null, this);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case TRIGGER_UPDATE_FINISHED:
//Triggers might have changed so we update it here
setTriggerCount();
break;
}
}
protected void populateCommands(final String campaignUrn, final int campaignStatus) {
// first remove all the commands from the action bar...
ActionBarControl actionBar = getActionBarControl();
actionBar.clearActionBarCommands();
// ...and gather up the commands in the command tray so we can hide/show them
Button surveysButton = (Button)findViewById(R.id.campaign_info_button_surveys);
Button participateButton = (Button)findViewById(R.id.campaign_info_button_particpate);
Button removeButton = (Button)findViewById(R.id.campaign_info_button_remove);
// now, depending on the context, we can regenerate our commands
// this applies both to the action bar and to the command tray
if (campaignStatus != Campaign.STATUS_REMOTE) {
// only show data-related actions if it's ready
if (campaignStatus == Campaign.STATUS_READY) {
if(new UserPreferencesHelper(this).showFeedback())
actionBar.addActionBarCommand(ACTION_VIEW_RESPHISTORY, getString(R.string.response_history_action_button_description), R.drawable.btn_title_resphist);
actionBar.addActionBarCommand(ACTION_SETUP_TRIGGERS, getString(R.string.reminder_action_button_description), R.drawable.btn_title_trigger);
// route the actions to the appropriate places
actionBar.setOnActionListener(new ActionListener() {
@Override
public void onActionClicked(int commandID) {
Intent intent;
switch (commandID) {
case ACTION_TAKE_SURVEY:
intent = new Intent(mContext, SurveyListActivity.class);
intent.putExtra(CampaignFilter.EXTRA_CAMPAIGN_URN, campaignUrn);
startActivity(intent);
break;
case ACTION_VIEW_RESPHISTORY:
intent = new Intent(mContext, ResponseHistoryActivity.class);
intent.putExtra(CampaignFilter.EXTRA_CAMPAIGN_URN, campaignUrn);
startActivity(intent);
break;
case ACTION_SETUP_TRIGGERS:
Intent triggerIntent = Campaign.launchTriggerIntent(mContext, campaignUrn);
startActivityForResult(triggerIntent, TRIGGER_UPDATE_FINISHED);
return;
}
}
});
// also show the take surveys button
surveysButton.setVisibility(View.VISIBLE);
// and attach a handler for it
surveysButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Analytics.widget(v);
Intent intent = new Intent(mContext, SurveyListActivity.class);
intent.putExtra(CampaignFilter.EXTRA_CAMPAIGN_URN, campaignUrn);
startActivity(intent);
}
});
}
// and set the command tray buttons accordingly
participateButton.setVisibility(View.GONE);
removeButton.setVisibility(View.VISIBLE);
// attach a remove handler
removeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Analytics.widget(v);
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
SpannableStringBuilder message = new SpannableStringBuilder(getString(R.string.campaign_info_remove_text));
if(mTriggerCount != 0) {
message.append(" ");
message.append(getString(R.string.campaign_info_remove_campaign_reminders));
}
if(mLocalResponses != 0) {
if(mTriggerCount != 0) {
message.append(" ");
message.append(Html.fromHtml(getResources().getQuantityString(R.plurals.campaign_info_remove_campaign_responses_w_reminders, mLocalResponses, mLocalResponses)));
} else {
message.append(" ");
message.append(Html.fromHtml(getResources().getQuantityString(R.plurals.campaign_info_remove_campaign_responses, mLocalResponses, mLocalResponses)));
}
builder.setNeutralButton(R.string.upload, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
Intent uploadQueue = new Intent(CampaignInfoActivity.this, UploadQueueActivity.class);
uploadQueue.putExtra(CampaignFilter.EXTRA_CAMPAIGN_URN, campaignUrn);
startActivity(uploadQueue);
}
});
}
if(mTriggerCount != 0 || mLocalResponses != 0)
message.append(".");
builder.setMessage(message);
builder.setPositiveButton(R.string.remove, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// set this campaign as "remote" and exit out of here
Campaign.setRemote(CampaignInfoActivity.this, campaignUrn);
mContext.finish();
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
});
}
else {
// show commands for a remote campaign (e.g. "participate")
surveysButton.setVisibility(View.GONE);
participateButton.setVisibility(View.VISIBLE);
removeButton.setVisibility(View.GONE);
// attach a participation handler
participateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Analytics.widget(v);
// when clicked, it fires off a download task,
// waits for it to finish, then goes back to the list when it's done
new CampaignXmlDownloadTask(CampaignInfoActivity.this, campaignUrn, mAccount.getUsername(), mAccount.getAuthToken()).startLoading();
}
});
}
}
// ========================================================
// === view databinding below,
// === describes how this info view shows its data
// ========================================================
private interface QueryParams {
String[] PROJECTION = {
Campaigns.CAMPAIGN_URN,
Campaigns.CAMPAIGN_NAME,
Campaigns.CAMPAIGN_DESCRIPTION,
Campaigns.CAMPAIGN_STATUS,
Campaigns.CAMPAIGN_PRIVACY,
Campaigns.CAMPAIGN_ICON
};
final int URN = 0;
final int NAME = 1;
final int DESCRIPTION = 2;
final int STATUS = 3;
final int PRIVACY = 4;
final int ICON = 5;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
return new CursorLoader(this, getIntent().getData(), QueryParams.PROJECTION, null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// ensure that we're on the first record in the cursor
if (!data.moveToFirst())
return;
mCampaignUrn = data.getString(QueryParams.URN);
// set the header fields first
mHeadertext.setText(data.getString(QueryParams.NAME));
mSubtext.setText(mCampaignUrn);
final String iconUrl = data.getString(QueryParams.ICON);
if(iconUrl == null || mImageLoader.bind(mIconView, iconUrl, null) != ImageLoader.BindResult.OK) {
mIconView.setImageResource(R.drawable.apple_logo);
}
// fill in the description
mDescView.setText(data.getString(QueryParams.DESCRIPTION));
// set the appropriate text and icon for the privacy state
String privacy = data.getString(QueryParams.PRIVACY);
mPrivacyValue.setText(privacy);
if ("private".equalsIgnoreCase(privacy))
mPrivacyValue.setCompoundDrawablesWithIntrinsicBounds(R.drawable.website_private, 0, 0, 0);
else if ("shared".equalsIgnoreCase(privacy))
mPrivacyValue.setCompoundDrawablesWithIntrinsicBounds(R.drawable.website_shared, 0, 0, 0);
else
mPrivacyValue.setCompoundDrawablesWithIntrinsicBounds(R.drawable.website_private, 0, 0, 0);
// hide our error box; it'll become visible below (and filled w/text) if the status is appropriate
mErrorBox.setVisibility(View.GONE);
// set many things on the view according to the campaign status, too
mStatusValue.setCompoundDrawablesWithIntrinsicBounds(R.drawable.website_stopped, 0, 0, 0); // start out a default gray sphere
mCampaignStatus = data.getInt(QueryParams.STATUS);
switch (mCampaignStatus) {
case Campaign.STATUS_READY:
mStatusValue.setText(R.string.campaign_status_ready);
mStatusValue.setCompoundDrawablesWithIntrinsicBounds(R.drawable.website_running, 0, 0, 0);
break;
case Campaign.STATUS_VAGUE:
mStatusValue.setText(R.string.campaign_status_vague);
break;
case Campaign.STATUS_REMOTE:
mStatusValue.setText(R.string.campaign_status_remote);
break;
case Campaign.STATUS_OUT_OF_DATE:
mStatusValue.setText(R.string.campaign_status_out_of_date);
mErrorBox.setVisibility(View.VISIBLE);
mErrorBox.setText(Html.fromHtml(getString(R.string.campaign_info_errorbox_outofdate)));
break;
case Campaign.STATUS_NO_EXIST:
mStatusValue.setText(R.string.campaign_status_no_exist);
mErrorBox.setVisibility(View.VISIBLE);
mErrorBox.setText(Html.fromHtml(getString(R.string.campaign_info_errorbox_no_exist)));
break;
case Campaign.STATUS_STOPPED:
mStatusValue.setText(R.string.campaign_status_stopped);
mStatusValue.setCompoundDrawablesWithIntrinsicBounds(R.drawable.website_stopped, 0, 0, 0);
mErrorBox.setVisibility(View.VISIBLE);
mErrorBox.setText(Html.fromHtml(getString(R.string.campaign_info_errorbox_stopped)));
break;
case Campaign.STATUS_INVALID_USER_ROLE:
mStatusValue.setText(R.string.campaign_status_invalid_user_role);
mErrorBox.setVisibility(View.VISIBLE);
mErrorBox.setText(Html.fromHtml(getString(R.string.campaign_info_errorbox_invalid_role)));
break;
case Campaign.STATUS_DOWNLOADING:
mStatusValue.setText(R.string.campaign_status_downloading);
break;
default:
mStatusValue.setText(R.string.campaign_status_unknown);
break;
}
// set the responses by querying the response table
// and getting the number of responses submitted for this campaign
Cursor responses = getContentResolver().query(Campaigns.buildResponsesUri(mCampaignUrn), null, null, null, null);
mResponsesValue.setText(getResources().getQuantityString(R.plurals.campaign_info_response_count, responses.getCount(), responses.getCount()));
responses.close();
mLocalResponses = Campaign.localResponseCount(this, mCampaignUrn);
// get the number of triggers for this survey
setTriggerCount();
// and finally populate the action bar + command tray
populateCommands(mCampaignUrn, mCampaignStatus);
// and make the entity header visible (although i assume it already was)
mEntityHeader.setVisibility(View.VISIBLE);
// finally, show our content
setLoadingVisibility(false);
}
private void setTriggerCount() {
// get the number of triggers for this campaign
TriggerDB trigDB = new TriggerDB(mContext);
if (trigDB.open()) {
Cursor triggers = trigDB.getAllTriggers(mCampaignUrn);
mTriggerCount = triggers.getCount();
mTriggersValue.setText(getResources().getQuantityString(R.plurals.campaign_info_trigger_count, mTriggerCount, mTriggerCount));
triggers.close();
trigDB.close();
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// FIXME should we hide the entity header like cameron does?
}
}