/**
* Copyright 2010 Mark Wyszomierski
*/
package com.joelapenna.foursquared;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.joelapenna.foursquare.Foursquare;
import com.joelapenna.foursquare.types.FoursquareType;
import com.joelapenna.foursquare.types.Tip;
import com.joelapenna.foursquare.types.Todo;
import com.joelapenna.foursquare.types.User;
import com.joelapenna.foursquare.types.Venue;
import com.joelapenna.foursquared.util.StringFormatters;
import com.joelapenna.foursquared.util.TipUtils;
/**
* Shows actions a user can perform on a tip, which includes marking a tip
* as a to-do, marking a tip as done, un-marking a tip. Marking a tip as
* a to-do will generate a to-do, which has the tip as a child object.
*
* The intent will return a Tip object and a Todo object (if the final state
* of the tip was marked as a Todo). In the case where a Todo is returned,
* the Tip will be the representation as found within the Todo object.
*
* If the user does not modify the tip, no intent data is returned. If the
* final state of the tip was not marked as a to-do, the Todo object is
* not returned.
*
* @date September 2, 2010
* @author Mark Wyszomierski (markww@gmail.com)
*
*/
public class TipActivity extends Activity {
private static final String TAG = "TipActivity";
private static final boolean DEBUG = FoursquaredSettings.DEBUG;
public static final String EXTRA_TIP_PARCEL = Foursquared.PACKAGE_NAME
+ ".TipActivity.EXTRA_TIP_PARCEL";
public static final String EXTRA_VENUE_CLICKABLE = Foursquared.PACKAGE_NAME
+ ".TipActivity.EXTRA_VENUE_CLICKABLE";
/**
* Always returned if the user modifies the tip in any way. Captures the
* new <status> attribute of the tip. It may not have been changed by the
* user.
*/
public static final String EXTRA_TIP_RETURNED = Foursquared.PACKAGE_NAME
+ ".TipActivity.EXTRA_TIP_RETURNED";
/**
* If the user marks the tip as to-do as the final state, then a to-do object
* will also be returned here. The to-do object has the same tip object as
* returned in EXTRA_TIP_PARCEL_RETURNED as a child member.
*/
public static final String EXTRA_TODO_RETURNED = Foursquared.PACKAGE_NAME
+ ".TipActivity.EXTRA_TODO_RETURNED";
private StateHolder mStateHolder;
private ProgressDialog mDlgProgress;
private BroadcastReceiver mLoggedOutReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "onReceive: " + intent);
finish();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tip_activity);
registerReceiver(mLoggedOutReceiver, new IntentFilter(Foursquared.INTENT_ACTION_LOGGED_OUT));
Object retained = getLastNonConfigurationInstance();
if (retained != null && retained instanceof StateHolder) {
mStateHolder = (StateHolder) retained;
mStateHolder.setActivityForTipTask(this);
setPreparedResultIntent();
} else {
mStateHolder = new StateHolder();
if (getIntent().getExtras() != null) {
if (getIntent().hasExtra(EXTRA_TIP_PARCEL)) {
Tip tip = getIntent().getExtras().getParcelable(EXTRA_TIP_PARCEL);
mStateHolder.setTip(tip);
} else {
Log.e(TAG, "TipActivity requires a tip pareclable in its intent extras.");
finish();
return;
}
if (getIntent().hasExtra(EXTRA_VENUE_CLICKABLE)) {
mStateHolder.setVenueClickable(
getIntent().getBooleanExtra(EXTRA_VENUE_CLICKABLE, true));
}
} else {
Log.e(TAG, "TipActivity requires a tip pareclable in its intent extras.");
finish();
return;
}
}
ensureUi();
}
@Override
public void onResume() {
super.onResume();
if (mStateHolder.getIsRunningTipTask()) {
startProgressBar();
}
}
@Override
public void onPause() {
super.onPause();
if (isFinishing()) {
stopProgressBar();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mLoggedOutReceiver);
}
@Override
public Object onRetainNonConfigurationInstance() {
mStateHolder.setActivityForTipTask(null);
return mStateHolder;
}
private void ensureUi() {
Tip tip = mStateHolder.getTip();
Venue venue = tip.getVenue();
LinearLayout llHeader = (LinearLayout)findViewById(R.id.tipActivityHeaderView);
if (mStateHolder.getVenueClickable()) {
llHeader.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showVenueDetailsActivity(mStateHolder.getTip().getVenue());
}
});
}
ImageView ivVenueChevron = (ImageView)findViewById(R.id.tipActivityVenueChevron);
if (mStateHolder.getVenueClickable()) {
ivVenueChevron.setVisibility(View.VISIBLE);
} else {
ivVenueChevron.setVisibility(View.INVISIBLE);
}
TextView tvTitle = (TextView)findViewById(R.id.tipActivityName);
TextView tvAddress = (TextView)findViewById(R.id.tipActivityAddress);
if (venue != null) {
tvTitle.setText(venue.getName());
tvAddress.setText(
venue.getAddress() +
(TextUtils.isEmpty(venue.getCrossstreet()) ?
"" : " (" + venue.getCrossstreet() + ")"));
} else {
tvTitle.setText("");
tvAddress.setText("");
}
TextView tvBody = (TextView)findViewById(R.id.tipActivityBody);
tvBody.setText(tip.getText());
String created = getResources().getString(
R.string.tip_activity_created,
StringFormatters.getTipAge(getResources(), tip.getCreated()));
TextView tvDate = (TextView)findViewById(R.id.tipActivityDate);
tvDate.setText(created);
TextView tvAuthor = (TextView)findViewById(R.id.tipActivityAuthor);
if (tip.getUser() != null) {
tvAuthor.setText(tip.getUser().getFirstname());
tvAuthor.setClickable(true);
tvAuthor.setFocusable(true);
tvAuthor.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showUserDetailsActivity(mStateHolder.getTip().getUser());
}
});
tvDate.setText(tvDate.getText() + getResources().getString(
R.string.tip_activity_created_by));
} else {
tvAuthor.setText("");
}
Button btn1 = (Button)findViewById(R.id.tipActivityyAddTodoList);
Button btn2 = (Button)findViewById(R.id.tipActivityIveDoneThis);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onBtnTodo();
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onBtnDone();
}
});
updateButtonStates();
}
private void onBtnTodo() {
Tip tip = mStateHolder.getTip();
if (TipUtils.isTodo(tip)) {
mStateHolder.startTipTask(TipActivity.this, mStateHolder.getTip().getId(),
TipTask.ACTION_UNMARK_TODO);
} else {
mStateHolder.startTipTask(TipActivity.this, mStateHolder.getTip().getId(),
TipTask.ACTION_TODO);
}
}
private void onBtnDone() {
Tip tip = mStateHolder.getTip();
if (TipUtils.isDone(tip)) {
mStateHolder.startTipTask(TipActivity.this, mStateHolder.getTip().getId(),
TipTask.ACTION_UNMARK_DONE);
} else {
mStateHolder.startTipTask(TipActivity.this, mStateHolder.getTip().getId(),
TipTask.ACTION_DONE);
}
}
private void updateButtonStates() {
Button btn1 = (Button)findViewById(R.id.tipActivityyAddTodoList);
Button btn2 = (Button)findViewById(R.id.tipActivityIveDoneThis);
TextView tv = (TextView)findViewById(R.id.tipActivityCongrats);
Tip tip = mStateHolder.getTip();
if (TipUtils.isTodo(tip)) {
btn1.setText(getResources().getString(R.string.tip_activity_btn_tip_1)); // "REMOVE FROM MY TO-DO LIST"
btn2.setText(getResources().getString(R.string.tip_activity_btn_tip_2)); // "I'VE DONE THIS"
btn1.setVisibility(View.VISIBLE);
tv.setVisibility(View.GONE);
} else if (TipUtils.isDone(tip)) {
tv.setText(getResources().getString(R.string.tip_activity_btn_tip_4)); // "CONGRATS! YOU'VE DONE THIS"
btn2.setText(getResources().getString(R.string.tip_activity_btn_tip_3)); // "UNDO THIS"
btn1.setVisibility(View.GONE);
tv.setVisibility(View.VISIBLE);
} else {
btn1.setText(getResources().getString(R.string.tip_activity_btn_tip_0)); // "ADD TO MY TO-DO LIST"
btn2.setText(getResources().getString(R.string.tip_activity_btn_tip_2)); // "I'VE DONE THIS"
btn1.setVisibility(View.VISIBLE);
tv.setVisibility(View.GONE);
}
}
private void showUserDetailsActivity(User user) {
Intent intent = new Intent(this, UserDetailsActivity.class);
intent.putExtra(UserDetailsActivity.EXTRA_USER_ID, user.getId());
startActivity(intent);
}
private void showVenueDetailsActivity(Venue venue) {
Intent intent = new Intent(this, VenueActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(VenueActivity.INTENT_EXTRA_VENUE_PARTIAL, venue);
startActivity(intent);
}
private void startProgressBar() {
if (mDlgProgress == null) {
mDlgProgress = ProgressDialog.show(this, "",
getResources().getString(R.string.tip_activity_progress_message));
}
mDlgProgress.show();
}
private void stopProgressBar() {
if (mDlgProgress != null) {
mDlgProgress.dismiss();
mDlgProgress = null;
}
}
private void prepareResultIntent(Tip tip, Todo todo) {
Intent intent = new Intent();
intent.putExtra(EXTRA_TIP_RETURNED, tip);
if (todo != null) {
intent.putExtra(EXTRA_TODO_RETURNED, todo); // tip is also a part of the to-do.
}
mStateHolder.setPreparedResult(intent);
setPreparedResultIntent();
}
private void setPreparedResultIntent() {
if (mStateHolder.getPreparedResult() != null) {
setResult(Activity.RESULT_OK, mStateHolder.getPreparedResult());
}
}
private void onTipTaskComplete(FoursquareType tipOrTodo, int type, Exception ex) {
stopProgressBar();
mStateHolder.setIsRunningTipTask(false);
if (tipOrTodo != null) {
// When the tip and todo are serialized into the intent result, the
// link between them will be lost, they'll appear as two separate
// tip object instances (ids etc will all be the same though).
if (tipOrTodo instanceof Tip) {
Tip tip = (Tip)tipOrTodo;
mStateHolder.setTip(tip);
prepareResultIntent(tip, null);
} else {
Todo todo = (Todo)tipOrTodo;
Tip tip = todo.getTip();
mStateHolder.setTip(tip);
prepareResultIntent(tip, todo);
}
} else if (ex != null) {
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Error updating tip!", Toast.LENGTH_LONG).show();
}
ensureUi();
}
private static class TipTask extends AsyncTask<String, Void, FoursquareType> {
private TipActivity mActivity;
private String mTipId;
private int mTask;
private Exception mReason;
public static final int ACTION_TODO = 0;
public static final int ACTION_DONE = 1;
public static final int ACTION_UNMARK_TODO = 2;
public static final int ACTION_UNMARK_DONE = 3;
public TipTask(TipActivity activity, String tipid, int task) {
mActivity = activity;
mTipId = tipid;
mTask = task;
}
public void setActivity(TipActivity activity) {
mActivity = activity;
}
@Override
protected void onPreExecute() {
mActivity.startProgressBar();
}
@Override
protected FoursquareType doInBackground(String... params) {
try {
Foursquared foursquared = (Foursquared) mActivity.getApplication();
Foursquare foursquare = foursquared.getFoursquare();
switch (mTask) {
case ACTION_TODO:
return foursquare.markTodo(mTipId); // returns a todo.
case ACTION_DONE:
return foursquare.markDone(mTipId); // returns a tip.
case ACTION_UNMARK_TODO:
return foursquare.unmarkTodo(mTipId); // returns a tip
case ACTION_UNMARK_DONE:
return foursquare.unmarkDone(mTipId); // returns a tip
default:
return null;
}
} catch (Exception e) {
if (DEBUG) Log.d(TAG, "TipTask: Exception performing tip task.", e);
mReason = e;
}
return null;
}
@Override
protected void onPostExecute(FoursquareType tipOrTodo) {
if (DEBUG) Log.d(TAG, "TipTask: onPostExecute()");
if (mActivity != null) {
mActivity.onTipTaskComplete(tipOrTodo, mTask, mReason);
}
}
@Override
protected void onCancelled() {
if (mActivity != null) {
mActivity.onTipTaskComplete(null, mTask, new Exception("Tip task cancelled."));
}
}
}
private static class StateHolder {
private Tip mTip;
private TipTask mTipTask;
private boolean mIsRunningTipTask;
private boolean mVenueClickable;
private Intent mPreparedResult;
public StateHolder() {
mTip = null;
mPreparedResult = null;
mIsRunningTipTask = false;
mVenueClickable = true;
}
public Tip getTip() {
return mTip;
}
public void setTip(Tip tip) {
mTip = tip;
}
public void startTipTask(TipActivity activity, String tipId, int task) {
mIsRunningTipTask = true;
mTipTask = new TipTask(activity, tipId, task);
mTipTask.execute();
}
public void setActivityForTipTask(TipActivity activity) {
if (mTipTask != null) {
mTipTask.setActivity(activity);
}
}
public void setIsRunningTipTask(boolean isRunningTipTask) {
mIsRunningTipTask = isRunningTipTask;
}
public boolean getIsRunningTipTask() {
return mIsRunningTipTask;
}
public boolean getVenueClickable() {
return mVenueClickable;
}
public void setVenueClickable(boolean venueClickable) {
mVenueClickable = venueClickable;
}
public Intent getPreparedResult() {
return mPreparedResult;
}
public void setPreparedResult(Intent intent) {
mPreparedResult = intent;
}
}
}