/**
* Copyright 2010 Mark Wyszomierski
*/
package com.joelapenna.foursquared;
import com.joelapenna.foursquare.Foursquare;
import com.joelapenna.foursquare.error.FoursquareException;
import com.joelapenna.foursquare.types.Group;
import com.joelapenna.foursquare.types.Tip;
import com.joelapenna.foursquared.app.LoadableListActivityWithViewAndHeader;
import com.joelapenna.foursquared.location.LocationUtils;
import com.joelapenna.foursquared.util.NotificationsUtil;
import com.joelapenna.foursquared.widget.SegmentedButton;
import com.joelapenna.foursquared.widget.SegmentedButton.OnClickListenerSegmentedButton;
import com.joelapenna.foursquared.widget.TipsListAdapter;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import java.util.Observable;
import java.util.Observer;
/**
* Shows a tips of a user, but not the logged-in user. This is pretty much a copy-paste
* of TipsActivity, but there are enough small differences to put it in its own activity.
* The direction of this activity is unknown too, so separating i here.
*
* @date September 23, 2010
* @author Mark Wyszomierski (markww@gmail.com)
*/
public class UserDetailsTipsActivity extends LoadableListActivityWithViewAndHeader {
static final String TAG = "UserDetailsTipsActivity";
static final boolean DEBUG = FoursquaredSettings.DEBUG;
public static final String INTENT_EXTRA_USER_ID = Foursquared.PACKAGE_NAME
+ ".UserDetailsTipsActivity.INTENT_EXTRA_USER_ID";
public static final String INTENT_EXTRA_USER_NAME = Foursquared.PACKAGE_NAME
+ ".UserDetailsTipsActivity.INTENT_EXTRA_USER_NAME";
private static final int ACTIVITY_TIP = 500;
private StateHolder mStateHolder;
private TipsListAdapter mListAdapter;
private SearchLocationObserver mSearchLocationObserver = new SearchLocationObserver();
private View mLayoutEmpty;
private static final int MENU_REFRESH = 0;
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);
registerReceiver(mLoggedOutReceiver, new IntentFilter(Foursquared.INTENT_ACTION_LOGGED_OUT));
Object retained = getLastNonConfigurationInstance();
if (retained != null && retained instanceof StateHolder) {
mStateHolder = (StateHolder) retained;
mStateHolder.setActivity(this);
} else {
if (getIntent().hasExtra(INTENT_EXTRA_USER_ID) && getIntent().hasExtra(INTENT_EXTRA_USER_NAME)) {
mStateHolder = new StateHolder(
getIntent().getStringExtra(INTENT_EXTRA_USER_ID),
getIntent().getStringExtra(INTENT_EXTRA_USER_NAME));
mStateHolder.setRecentOnly(true);
} else {
Log.e(TAG, TAG + " requires user ID and name in intent extras.");
finish();
return;
}
}
ensureUi();
// Friend tips is shown first by default so auto-fetch it if necessary.
if (!mStateHolder.getRanOnceTipsRecent()) {
mStateHolder.startTaskTips(this, true);
}
}
@Override
public void onResume() {
super.onResume();
((Foursquared) getApplication()).requestLocationUpdates(mSearchLocationObserver);
}
@Override
public void onPause() {
super.onPause();
((Foursquared) getApplication()).removeLocationUpdates(mSearchLocationObserver);
if (isFinishing()) {
mStateHolder.cancelTasks();
mListAdapter.removeObserver();
unregisterReceiver(mLoggedOutReceiver);
}
}
@Override
public Object onRetainNonConfigurationInstance() {
mStateHolder.setActivity(null);
return mStateHolder;
}
private void ensureUi() {
LayoutInflater inflater = LayoutInflater.from(this);
mLayoutEmpty = inflater.inflate(R.layout.tips_activity_empty, null);
mLayoutEmpty.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
mListAdapter = new TipsListAdapter(this,
((Foursquared) getApplication()).getRemoteResourceManager(), R.layout.tip_venue_list_item);
if (mStateHolder.getRecentOnly()) {
mListAdapter.setGroup(mStateHolder.getTipsRecent());
if (mStateHolder.getTipsRecent().size() == 0) {
if (mStateHolder.getRanOnceTipsRecent()) {
setEmptyView(mLayoutEmpty);
} else {
setLoadingView();
}
}
} else {
mListAdapter.setGroup(mStateHolder.getTipsPopular());
if (mStateHolder.getTipsPopular().size() == 0) {
if (mStateHolder.getRanOnceTipsPopular()) {
setEmptyView(mLayoutEmpty);
} else {
setLoadingView();
}
}
}
SegmentedButton buttons = getHeaderButton();
buttons.clearButtons();
buttons.addButtons(
getString(R.string.user_details_tips_activity_btn_recent),
getString(R.string.user_details_tips_activity_btn_popular));
if (mStateHolder.mRecentOnly) {
buttons.setPushedButtonIndex(0);
} else {
buttons.setPushedButtonIndex(1);
}
buttons.setOnClickListener(new OnClickListenerSegmentedButton() {
@Override
public void onClick(int index) {
if (index == 0) {
mStateHolder.setRecentOnly(true);
mListAdapter.setGroup(mStateHolder.getTipsRecent());
if (mStateHolder.getTipsRecent().size() < 1) {
if (mStateHolder.getRanOnceTipsRecent()) {
setEmptyView(mLayoutEmpty);
} else {
setLoadingView();
mStateHolder.startTaskTips(UserDetailsTipsActivity.this, true);
}
}
} else {
mStateHolder.setRecentOnly(false);
mListAdapter.setGroup(mStateHolder.getTipsPopular());
if (mStateHolder.getTipsPopular().size() < 1) {
if (mStateHolder.getRanOnceTipsPopular()) {
setEmptyView(mLayoutEmpty);
} else {
setLoadingView();
mStateHolder.startTaskTips(UserDetailsTipsActivity.this, false);
}
}
}
mListAdapter.notifyDataSetChanged();
getListView().setSelection(0);
}
});
ListView listView = getListView();
listView.setAdapter(mListAdapter);
listView.setSmoothScrollbarEnabled(false);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Tip tip = (Tip) parent.getAdapter().getItem(position);
Intent intent = new Intent(UserDetailsTipsActivity.this, TipActivity.class);
intent.putExtra(TipActivity.EXTRA_TIP_PARCEL, tip);
startActivityForResult(intent, ACTIVITY_TIP);
}
});
if (mStateHolder.getIsRunningTaskTipsRecent() ||
mStateHolder.getIsRunningTaskTipsPopular()) {
setProgressBarIndeterminateVisibility(true);
} else {
setProgressBarIndeterminateVisibility(false);
}
setTitle(getString(R.string.user_details_tips_activity_title, mStateHolder.getUsername()));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, MENU_REFRESH, Menu.NONE, R.string.refresh)
.setIcon(R.drawable.ic_menu_refresh);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_REFRESH:
mStateHolder.startTaskTips(this, mStateHolder.getRecentOnly());
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// We don't care about the returned to-do (if any) since we're not bound
// to a venue in this activity for update. We just update the status member
// of the target tip.
if (requestCode == ACTIVITY_TIP && resultCode == Activity.RESULT_OK) {
if (data.hasExtra(TipActivity.EXTRA_TIP_RETURNED)) {
Log.i(TAG, "onActivityResult(), return tip intent extra found, processing.");
updateTip((Tip)data.getParcelableExtra(TipActivity.EXTRA_TIP_RETURNED));
} else {
Log.i(TAG, "onActivityResult(), no return tip intent extra found.");
}
}
}
private void updateTip(Tip tip) {
mStateHolder.updateTip(tip);
mListAdapter.notifyDataSetInvalidated();
}
private void onStartTaskTips() {
if (mListAdapter != null) {
if (mStateHolder.getRecentOnly()) {
mStateHolder.setIsRunningTaskTipsRecent(true);
mListAdapter.setGroup(mStateHolder.getTipsRecent());
} else {
mStateHolder.setIsRunningTaskTipsPopular(true);
mListAdapter.setGroup(mStateHolder.getTipsPopular());
}
mListAdapter.notifyDataSetChanged();
}
setProgressBarIndeterminateVisibility(true);
setLoadingView();
}
private void onTaskTipsComplete(Group<Tip> group, boolean recentOnly, Exception ex) {
SegmentedButton buttons = getHeaderButton();
boolean update = false;
if (group != null) {
if (recentOnly) {
mStateHolder.setTipsRecent(group);
if (buttons.getSelectedButtonIndex() == 0) {
mListAdapter.setGroup(mStateHolder.getTipsRecent());
update = true;
}
} else {
mStateHolder.setTipsPopular(group);
if (buttons.getSelectedButtonIndex() == 1) {
mListAdapter.setGroup(mStateHolder.getTipsPopular());
update = true;
}
}
}
else {
if (recentOnly) {
mStateHolder.setTipsRecent(new Group<Tip>());
if (buttons.getSelectedButtonIndex() == 0) {
mListAdapter.setGroup(mStateHolder.getTipsRecent());
update = true;
}
} else {
mStateHolder.setTipsPopular(new Group<Tip>());
if (buttons.getSelectedButtonIndex() == 1) {
mListAdapter.setGroup(mStateHolder.getTipsPopular());
update = true;
}
}
NotificationsUtil.ToastReasonForFailure(this, ex);
}
if (recentOnly) {
mStateHolder.setIsRunningTaskTipsRecent(false);
mStateHolder.setRanOnceTipsRecent(true);
if (mStateHolder.getTipsRecent().size() == 0 &&
buttons.getSelectedButtonIndex() == 0) {
setEmptyView(mLayoutEmpty);
}
} else {
mStateHolder.setIsRunningTaskTipsPopular(false);
mStateHolder.setRanOnceTipsPopular(true);
if (mStateHolder.getTipsPopular().size() == 0 &&
buttons.getSelectedButtonIndex() == 1) {
setEmptyView(mLayoutEmpty);
}
}
if (update) {
mListAdapter.notifyDataSetChanged();
getListView().setSelection(0);
}
if (!mStateHolder.getIsRunningTaskTipsRecent() &&
!mStateHolder.getIsRunningTaskTipsPopular()) {
setProgressBarIndeterminateVisibility(false);
}
}
private static class TaskTips extends AsyncTask<Void, Void, Group<Tip>> {
private String mUserId;
private UserDetailsTipsActivity mActivity;
private boolean mRecentOnly;
private Exception mReason;
public TaskTips(UserDetailsTipsActivity activity, String userId, boolean recentOnly) {
mActivity = activity;
mUserId = userId;
mRecentOnly = recentOnly;
}
@Override
protected void onPreExecute() {
mActivity.onStartTaskTips();
}
@Override
protected Group<Tip> doInBackground(Void... params) {
try {
Foursquared foursquared = (Foursquared) mActivity.getApplication();
Foursquare foursquare = foursquared.getFoursquare();
Location loc = foursquared.getLastKnownLocation();
if (loc == null) {
try { Thread.sleep(3000); } catch (InterruptedException ex) {}
loc = foursquared.getLastKnownLocation();
if (loc == null) {
throw new FoursquareException("Your location could not be determined!");
}
}
return foursquare.tips(
LocationUtils.createFoursquareLocation(loc),
mUserId,
"nearby",
mRecentOnly ? "recent" : "popular",
30);
} catch (Exception e) {
mReason = e;
}
return null;
}
@Override
protected void onPostExecute(Group<Tip> tips) {
if (mActivity != null) {
mActivity.onTaskTipsComplete(tips, mRecentOnly, mReason);
}
}
@Override
protected void onCancelled() {
if (mActivity != null) {
mActivity.onTaskTipsComplete(null, mRecentOnly, mReason);
}
}
public void setActivity(UserDetailsTipsActivity activity) {
mActivity = activity;
}
}
private static class StateHolder {
private String mUserId;
private String mUsername;
private Group<Tip> mTipsRecent;
private Group<Tip> mTipsPopular;
private TaskTips mTaskTipsRecent;
private TaskTips mTaskTipsPopular;
private boolean mIsRunningTaskTipsRecent;
private boolean mIsRunningTaskTipsPopular;
private boolean mRecentOnly;
private boolean mRanOnceTipsRecent;
private boolean mRanOnceTipsPopular;
public StateHolder(String userId, String username) {
mUserId = userId;
mUsername = username;
mIsRunningTaskTipsRecent = false;
mIsRunningTaskTipsPopular = false;
mRanOnceTipsRecent = false;
mRanOnceTipsPopular = false;
mTipsRecent = new Group<Tip>();
mTipsPopular = new Group<Tip>();
mRecentOnly = true;
}
public String getUsername() {
return mUsername;
}
public Group<Tip> getTipsRecent() {
return mTipsRecent;
}
public void setTipsRecent(Group<Tip> tipsRecent) {
mTipsRecent = tipsRecent;
}
public Group<Tip> getTipsPopular() {
return mTipsPopular;
}
public void setTipsPopular(Group<Tip> tipsPopular) {
mTipsPopular = tipsPopular;
}
public void startTaskTips(UserDetailsTipsActivity activity,
boolean recentOnly) {
if (recentOnly) {
if (mIsRunningTaskTipsRecent) {
return;
}
mIsRunningTaskTipsRecent = true;
mTaskTipsRecent = new TaskTips(activity, mUserId, recentOnly);
mTaskTipsRecent.execute();
} else {
if (mIsRunningTaskTipsPopular) {
return;
}
mIsRunningTaskTipsPopular = true;
mTaskTipsPopular = new TaskTips(activity, mUserId, recentOnly);
mTaskTipsPopular.execute();
}
}
public void setActivity(UserDetailsTipsActivity activity) {
if (mTaskTipsRecent != null) {
mTaskTipsRecent.setActivity(activity);
}
if (mTaskTipsPopular != null) {
mTaskTipsPopular.setActivity(activity);
}
}
public boolean getIsRunningTaskTipsRecent() {
return mIsRunningTaskTipsRecent;
}
public void setIsRunningTaskTipsRecent(boolean isRunning) {
mIsRunningTaskTipsRecent = isRunning;
}
public boolean getIsRunningTaskTipsPopular() {
return mIsRunningTaskTipsPopular;
}
public void setIsRunningTaskTipsPopular(boolean isRunning) {
mIsRunningTaskTipsPopular = isRunning;
}
public void cancelTasks() {
if (mTaskTipsRecent != null) {
mTaskTipsRecent.setActivity(null);
mTaskTipsRecent.cancel(true);
}
if (mTaskTipsPopular != null) {
mTaskTipsPopular.setActivity(null);
mTaskTipsPopular.cancel(true);
}
}
public boolean getRecentOnly() {
return mRecentOnly;
}
public void setRecentOnly(boolean recentOnly) {
mRecentOnly = recentOnly;
}
public boolean getRanOnceTipsRecent() {
return mRanOnceTipsRecent;
}
public void setRanOnceTipsRecent(boolean ranOnce) {
mRanOnceTipsRecent = ranOnce;
}
public boolean getRanOnceTipsPopular() {
return mRanOnceTipsPopular;
}
public void setRanOnceTipsPopular(boolean ranOnce) {
mRanOnceTipsPopular = ranOnce;
}
public void updateTip(Tip tip) {
updateTipFromArray(tip, mTipsRecent);
updateTipFromArray(tip, mTipsPopular);
}
private void updateTipFromArray(Tip tip, Group<Tip> target) {
for (Tip it : target) {
if (it.getId().equals(tip.getId())) {
it.setStatus(tip.getStatus());
break;
}
}
}
}
private class SearchLocationObserver implements Observer {
@Override
public void update(Observable observable, Object data) {
}
}
}