/** * */ package com.gmail.charleszq.picorner.ui; import java.util.ArrayList; import java.util.List; import org.jinstagram.auth.model.Token; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.Toast; import com.github.yuyang226.j500px.J500px; import com.gmail.charleszq.picorner.PicornerApplication; import com.gmail.charleszq.picorner.R; import com.gmail.charleszq.picorner.SPUtil; import com.gmail.charleszq.picorner.model.Author; import com.gmail.charleszq.picorner.model.MediaSourceType; import com.gmail.charleszq.picorner.msg.IMessageConsumer; import com.gmail.charleszq.picorner.msg.Message; import com.gmail.charleszq.picorner.msg.MessageBus; import com.gmail.charleszq.picorner.task.IGeneralTaskDoneListener; import com.gmail.charleszq.picorner.task.ig.InstagramOAuthTask; import com.gmail.charleszq.picorner.task.px500.PxFetchUserProfileTask; import com.gmail.charleszq.picorner.ui.command.CommandType; import com.gmail.charleszq.picorner.ui.command.ICommand; import com.gmail.charleszq.picorner.ui.command.ICommandDoneListener; import com.gmail.charleszq.picorner.ui.command.MenuSectionHeaderCommand; import com.gmail.charleszq.picorner.ui.command.PhotoListCommand; import com.gmail.charleszq.picorner.ui.command.flickr.FlickrIntestringCommand; import com.gmail.charleszq.picorner.ui.command.flickr.FlickrLoginCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyFlickrContactPhotosCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyFlickrFavsCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyFlickrPhotosCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyFlickrPopularPhotosCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyGalleriesCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyGroupsCommand; import com.gmail.charleszq.picorner.ui.command.flickr.MyPhotosetsCommand; import com.gmail.charleszq.picorner.ui.command.ig.InstagramLikesCommand; import com.gmail.charleszq.picorner.ui.command.ig.InstagramLoginCommand; import com.gmail.charleszq.picorner.ui.command.ig.InstagramMyFeedsCommand; import com.gmail.charleszq.picorner.ui.command.ig.InstagramPopularsCommand; import com.gmail.charleszq.picorner.ui.command.ig.InstagramUserPhotosCommand; import com.gmail.charleszq.picorner.ui.command.px500.Px500MyPhotosCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxEditorsPhotosCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxFreshTodayPhotosCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxMyFavPhotosCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxMyFlowCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxPopularPhotosCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxSignInCommand; import com.gmail.charleszq.picorner.ui.command.px500.PxUpcomingPhotosCommand; import com.gmail.charleszq.picorner.ui.helper.CommandSectionListAdapter; import com.gmail.charleszq.picorner.ui.helper.IHiddenView; import com.gmail.charleszq.picorner.ui.helper.IHiddenView.IHiddenViewActionListener; import com.gmail.charleszq.picorner.utils.FlickrHelper; import com.gmail.charleszq.picorner.utils.IConstants; import com.googlecode.flickrjandroid.Flickr; import com.googlecode.flickrjandroid.oauth.OAuth; import com.googlecode.flickrjandroid.oauth.OAuthInterface; import com.googlecode.flickrjandroid.oauth.OAuthToken; import com.googlecode.flickrjandroid.people.User; /** * * @author Charles(charleszq@gmail.com) * */ @SuppressLint("DefaultLocale") public class MainMenuFragment extends AbstractFragmentWithImageFetcher implements IMessageConsumer { private CommandSectionListAdapter mSectionAdapter; private ProgressDialog mProgressDialog = null; private FrameLayout mBackViewContainer; private ListView mListView; /** * Records the latest command user clicks, then when the command finishes, * we know which one to load. */ private ICommand<?> mCurrentCommand; /** * The command done listener */ private ICommandDoneListener<Object> mCommandDoneListener = new ICommandDoneListener<Object>() { @Override public void onCommandDone(ICommand<Object> command, Object t) { if (mProgressDialog != null && mProgressDialog.isShowing()) { try { mProgressDialog.cancel(); } catch (Exception ex) { // do nothing. } } if (command != mCurrentCommand) return; MainSlideMenuActivity act = (MainSlideMenuActivity) MainMenuFragment.this .getActivity(); if (act == null) { // when configuration changed, the activity of this fragement // might be null, // then try to get it from the command. Context ctx = (Context) command.getAdapter(Context.class); if (ctx != null && ctx instanceof MainSlideMenuActivity) { act = (MainSlideMenuActivity) ctx; } } if (act != null) act.onCommandDone(command, t); } }; /** * The hidden view listener. */ private IHiddenViewActionListener mHideViewCancelListener = new IHiddenViewActionListener() { @SuppressWarnings("unchecked") @Override public void onAction(int action, ICommand<?> command, IHiddenView view, Object... data) { Context ctx = (Context) command.getAdapter(Context.class); switch (action) { case IHiddenView.ACTION_CANCEL: hideHiddenView(view.getView(ctx)); break; case IHiddenView.ACTION_DO: doCommand((ICommand<Object>) command, data); hideHiddenView(view.getView(ctx)); break; case IHiddenView.ACTION_JUST_CMD: doCommand((ICommand<Object>) command, data); break; } } }; private void doCommand(ICommand<Object> command, Object... params) { if (PhotoListCommand.class.isInstance(command)) { Message msg = new Message(Message.CANCEL_COMMAND, null, null, command); MessageBus.broadcastMessage(msg); mProgressDialog = ProgressDialog.show(getActivity(), "", getActivity() //$NON-NLS-1$ .getString(R.string.loading_photos)); mProgressDialog.setCanceledOnTouchOutside(true); } command.setCommndDoneListener(mCommandDoneListener); command.execute(params); // close the menu. MainSlideMenuActivity act = (MainSlideMenuActivity) getActivity(); act.closeMenu(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { this.setRetainInstance(true); View v = inflater.inflate(R.layout.main_menu, null); mBackViewContainer = (FrameLayout) v .findViewById(R.id.main_menu_container); // menu list mListView = (ListView) v.findViewById(R.id.listView1); mSectionAdapter = new CommandSectionListAdapter(getActivity()); prepareSections(); mListView.setAdapter(mSectionAdapter); mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int pos, long itemId) { ListAdapter adapter = ((ListView) parent).getAdapter(); @SuppressWarnings("unchecked") ICommand<Object> command = (ICommand<Object>) adapter .getItem(pos); // cancel the previous command and save the clicked one. if (mCurrentCommand != null) mCurrentCommand.cancel(); mCurrentCommand = command; Context ctx = (Context) command.getAdapter(Context.class); IHiddenView hiddenView = (IHiddenView) command .getAdapter(IHiddenView.class); if (hiddenView == null) { doPhotoListCommand(command); } else { hiddenView.init(command, mHideViewCancelListener); FrameLayout.LayoutParams param = new FrameLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER_VERTICAL); View hv = hiddenView.getView(ctx); hv.setLayoutParams(param); mBackViewContainer.addView(hv); showHiddenView(hv); return; } if (!(command instanceof FlickrLoginCommand) && !(command instanceof PxSignInCommand) && !CommandType.MENU_HEADER_CMD.equals(command .getCommandType())) { MainSlideMenuActivity act = (MainSlideMenuActivity) MainMenuFragment.this .getActivity(); act.closeMenu(); } } }); return v; } private void doPhotoListCommand(ICommand<Object> cmd) { cmd.setCommndDoneListener(mCommandDoneListener); cmd.execute(); if (PhotoListCommand.class.isInstance(cmd)) { Message msg = new Message(Message.CANCEL_COMMAND, null, null, cmd); MessageBus.broadcastMessage(msg); mProgressDialog = ProgressDialog.show(getActivity(), "", //$NON-NLS-1$ getActivity().getString(R.string.loading_photos)); mProgressDialog.setCancelable(true); } } private void hideHiddenView(final View view) { ObjectAnimator a1 = ObjectAnimator .ofFloat(mListView, "alpha", 0f, 1f).setDuration(1000); //$NON-NLS-1$ ObjectAnimator a2 = ObjectAnimator .ofFloat(view, "alpha", 1f, 0f).setDuration(1000); //$NON-NLS-1$ AnimatorSet set = new AnimatorSet(); set.playTogether(a1, a2); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mBackViewContainer.removeView(view); mListView.setVisibility(View.VISIBLE); } }); set.start(); } /** * Shows the hidden view. * * @param hv */ private void showHiddenView(View hv) { hv.setAlpha(0f); // hide the hidden view first ObjectAnimator a1 = ObjectAnimator .ofFloat(hv, "alpha", 0f, 1f).setDuration(1000); //$NON-NLS-1$ ObjectAnimator a2 = ObjectAnimator .ofFloat(mListView, "alpha", 1f, 0f).setDuration(1000); //$NON-NLS-1$ AnimatorSet set = new AnimatorSet(); set.playTogether(a2, a1); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mListView.setVisibility(View.INVISIBLE); } }); set.start(); } private void prepareSections() { mSectionAdapter.clearSections(); mSectionAdapter.addCommands(createPx500MenuItems()); mSectionAdapter.addCommands(createFlickrGeneralMenuItems()); mSectionAdapter.addCommands(createInstagramMenuItems()); mSectionAdapter.notifyDataSetChanged(); } private boolean isUserAuthedPx500() { return SPUtil.getPx500OauthToken(getActivity()) != null; } private boolean isUserAuthedInstagram() { PicornerApplication app = (PicornerApplication) this.getActivity() .getApplication(); return app.getInstagramAuthToken() != null; } private List<ICommand<?>> createInstagramMenuItems() { List<ICommand<?>> commands = new ArrayList<ICommand<?>>(); Context ctx = getActivity(); String headerName = ctx.getString(R.string.menu_header_ig); ICommand<?> command = new MenuSectionHeaderCommand(ctx, headerName); commands.add(command); command = new InstagramPopularsCommand(ctx); commands.add(command); if (isUserAuthedInstagram()) { command = new InstagramMyFeedsCommand(ctx); commands.add(command); command = new InstagramLikesCommand(ctx); commands.add(command); String myUserId = SPUtil.getInstagramUserId(getActivity()); Author a = new Author(); a.setUserId(myUserId); command = new InstagramUserPhotosCommand(ctx, a) { @Override public String getDescription() { // since we don't save my own user name return getString(R.string.cd_ig_my_photos); } @Override public Object getAdapter(Class<?> adapterClass) { if (adapterClass == ActionBar.class) { return Boolean.FALSE.toString(); } return super.getAdapter(adapterClass); } }; commands.add(command); } else { command = new InstagramLoginCommand(ctx); commands.add(command); } return commands; } private List<ICommand<?>> createPx500MenuItems() { List<ICommand<?>> commands = new ArrayList<ICommand<?>>(); String headerName = getActivity().getString(R.string.menu_header_px500); ICommand<?> command = new MenuSectionHeaderCommand(getActivity(), headerName); commands.add(command); command = new PxPopularPhotosCommand(getActivity()); commands.add(command); command = new PxEditorsPhotosCommand(getActivity()); commands.add(command); command = new PxUpcomingPhotosCommand(getActivity()); commands.add(command); command = new PxFreshTodayPhotosCommand(getActivity()); commands.add(command); if (isUserAuthedPx500()) { command = new Px500MyPhotosCommand(getActivity()); commands.add(command); command = new PxMyFavPhotosCommand(getActivity()); commands.add(command); command = new PxMyFlowCommand(getActivity()); commands.add(command); } else { command = new PxSignInCommand(getActivity()); commands.add(command); } return commands; } private List<ICommand<?>> createFlickrGeneralMenuItems() { List<ICommand<?>> commands = new ArrayList<ICommand<?>>(); Context ctx = getActivity(); // section header. String headerName = ctx.getString(R.string.menu_header_flickr); ICommand<?> command = new MenuSectionHeaderCommand(ctx, headerName); commands.add(command); // real commands command = new FlickrIntestringCommand(this.getActivity()); commands.add(command); if (!SPUtil.isFlickrAuthed(ctx)) { command = new FlickrLoginCommand(ctx); commands.add(command); } else { command = new MyFlickrPhotosCommand(ctx); commands.add(command); command = new MyFlickrFavsCommand(ctx); commands.add(command); command = new MyFlickrPopularPhotosCommand(ctx); commands.add(command); command = new MyFlickrContactPhotosCommand(ctx); commands.add(command); command = new MyPhotosetsCommand(ctx); commands.add(command); command = new MyGroupsCommand(ctx); commands.add(command); command = new MyGalleriesCommand(ctx); commands.add(command); } return commands; } @Override public void onResume() { super.onResume(); MessageBus.addConsumer(this); this.mProgressDialog = null; Intent intent = getActivity().getIntent(); String schema = intent.getScheme(); if (IConstants.ID_SCHEME.equals(schema)) { // if flickr already authed. if (SPUtil.isFlickrAuthed(getActivity())) { return; } Uri uri = intent.getData(); String query = uri.getQuery(); String[] data = query.split("&"); //$NON-NLS-1$ if (data != null && data.length == 2) { String oauthToken = data[0].substring(data[0].indexOf("=") + 1); //$NON-NLS-1$ String oauthVerifier = data[1] .substring(data[1].indexOf("=") + 1); //$NON-NLS-1$ String secret = getTokenSecret(MediaSourceType.FLICKR); if (secret != null) { GetOAuthTokenTask task = new GetOAuthTokenTask(this, MediaSourceType.FLICKR); task.execute(oauthToken, secret, oauthVerifier); } } } else if (IConstants.ID_IG_SCHEME.equals(schema)) { if (isUserAuthedInstagram()) { return; } Uri uri = intent.getData(); instagramAuth(uri); } else if (IConstants.PX500_OAUTH_CALLBACK_SCHEMA.equals(schema)) { if (isUserAuthedPx500()) { return; } Uri pxUri = intent.getData(); px500Auth(pxUri); } } private void px500Auth(Uri pxUri) { Log.d(TAG, pxUri.toString()); String query = pxUri.getQuery(); String[] data = query.split("&"); //$NON-NLS-1$ if (data != null && data.length == 2) { String oauthToken = data[0].substring(data[0].indexOf("=") + 1); //$NON-NLS-1$ String oauthVerifier = data[1].substring(data[1].indexOf("=") + 1); //$NON-NLS-1$ String secret = getTokenSecret(MediaSourceType.PX500); if (secret != null) { GetOAuthTokenTask task = new GetOAuthTokenTask(this, MediaSourceType.PX500); task.execute(oauthToken, secret, oauthVerifier); } } } /** * After recieves the auth token of instagram. * * @param uri */ private void instagramAuth(Uri uri) { String authority = uri.getAuthority(); if (IConstants.IG_AUTHORITY.equals(authority)) { // instagram String query = uri.getQuery(); int index = query.indexOf("="); //$NON-NLS-1$ if (index != -1) { String code = query.substring(index + 1); InstagramOAuthTask task = new InstagramOAuthTask(getActivity()); task.addTaskDoneListener(new IGeneralTaskDoneListener<Token>() { @Override public void onTaskDone(Token result) { MainMenuFragment.this.onOAuthDone(result, MediaSourceType.INSTAGRAM); } }); task.execute(code); } else { Log.e(getClass().getName(), "Instagram request token code not returned."); //$NON-NLS-1$ } } } /** * Represents the task to get the oauth token and user information. * <p> * This task should be called only after you got the request oauth request * token and the verifier. * * @author charles * */ private static class GetOAuthTokenTask extends AsyncTask<String, Integer, Object> { private MainMenuFragment mAuthDialog; private MediaSourceType mMediaSourceType; GetOAuthTokenTask(MainMenuFragment context, MediaSourceType type) { this.mAuthDialog = context; this.mMediaSourceType = type; } @Override protected Object doInBackground(String... params) { String oauthToken = params[0]; String oauthTokenSecret = params[1]; String verifier = params[2]; if (mMediaSourceType == MediaSourceType.FLICKR) { Flickr f = FlickrHelper.getInstance().getFlickr(); OAuthInterface oauthApi = f.getOAuthInterface(); try { return oauthApi.getAccessToken(oauthToken, oauthTokenSecret, verifier); } catch (Exception e) { return null; } } else if (mMediaSourceType == MediaSourceType.PX500) { try { J500px px = new J500px(IConstants.PX500_CONSUMER_KEY, IConstants.PX500_CONSUMER_SECRET); return px.getOAuthInterface().getAccessToken(oauthToken, oauthTokenSecret, verifier); } catch (Exception e) { } } return null; } @Override protected void onPostExecute(Object result) { if (mAuthDialog != null) { mAuthDialog.onOAuthDone(result, mMediaSourceType); } } } private String getTokenSecret(MediaSourceType type) { switch (type) { case FLICKR: return SPUtil.getFlickrAuthTokenSecret(getActivity()); case PX500: return SPUtil.getPx500TokenSecret(getActivity()); default: return null; // not support } } void onOAuthDone(Object result, MediaSourceType type) { if (result == null) { boolean signedin = false; String msg = getString(R.string.fail_to_oauth); switch (type) { case FLICKR: msg = String .format(msg, getString(R.string.menu_header_flickr)); signedin = SPUtil.isFlickrAuthed(getActivity()); break; case PX500: msg = String.format(msg, getString(R.string.menu_header_px500)); signedin = isUserAuthedPx500(); break; case INSTAGRAM: msg = String.format(msg, getString(R.string.menu_header_ig)); signedin = isUserAuthedInstagram(); break; } if (!signedin) { msg = msg.toLowerCase(); Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show(); } } else { PicornerApplication app = (PicornerApplication) getActivity() .getApplication(); if (type == MediaSourceType.FLICKR) { OAuth oauth = (OAuth) result; User user = oauth.getUser(); OAuthToken token = oauth.getToken(); if (user == null || user.getId() == null || token == null || token.getOauthToken() == null || token.getOauthTokenSecret() == null) { Toast.makeText(getActivity(), getActivity().getString(R.string.fail_to_oauth), Toast.LENGTH_LONG).show(); return; } app.saveFlickrAuthToken(oauth); } else if (type == MediaSourceType.PX500) { com.github.yuyang226.j500px.oauth.OAuth pxoauth = (com.github.yuyang226.j500px.oauth.OAuth) result; com.github.yuyang226.j500px.oauth.OAuthToken token = pxoauth .getToken(); app.savePxAuthToken(token); // fetch user profile PxFetchUserProfileTask userTask = new PxFetchUserProfileTask( getActivity()); userTask.execute(); } else { } prepareSections(); MessageBus.broadcastMessage(Message.PUBLIC_USER_LOGIN_MSG); } } @Override public boolean consumeMessage(Message msg) { if (msg.getMessageType() == Message.PX500_CHG_CAT) { @SuppressWarnings("unchecked") ICommand<Object> cmd = (ICommand<Object>) msg.getCoreData(); // cancel the previous command and save the clicked one. if (mCurrentCommand != null) mCurrentCommand.cancel(); mCurrentCommand = cmd; doPhotoListCommand(cmd); return true; } return false; } @Override public void onDetach() { super.onDetach(); MessageBus.removeConsumer(this); } }