package im.zico.wingtwitter.ui; import android.animation.Animator; import android.app.Activity; import android.app.ActivityOptions; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.media.Image; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.text.Html; import android.text.Spannable; import android.text.TextPaint; import android.text.method.LinkMovementMethod; import android.text.style.URLSpan; import android.transition.Fade; import android.transition.Slide; import android.transition.Transition; import android.util.Log; import android.util.Pair; import android.util.TypedValue; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.Button; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.github.ksoichiro.android.observablescrollview.ObservableScrollView; import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks; import com.github.ksoichiro.android.observablescrollview.ScrollState; import com.nineoldandroids.view.ViewHelper; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import java.util.ArrayList; import de.hdodenhof.circleimageview.CircleImageView; import im.zico.wingtwitter.R; import im.zico.wingtwitter.WingApp; import im.zico.wingtwitter.adapter.UserTweetsAdapter; import im.zico.wingtwitter.dao.WingDataHelper; import im.zico.wingtwitter.dao.WingStore; import im.zico.wingtwitter.type.WingTweet; import im.zico.wingtwitter.type.WingUser; import im.zico.wingtwitter.ui.activity.UserTimelineActivity; import im.zico.wingtwitter.ui.view.HtmlTextView; import im.zico.wingtwitter.ui.view.NestedListView; import im.zico.wingtwitter.utils.HackyMovementMethod; import im.zico.wingtwitter.utils.SpannableStringUtils; import twitter4j.AsyncTwitter; import twitter4j.Paging; import twitter4j.Relationship; import twitter4j.ResponseList; import twitter4j.Status; import twitter4j.TwitterAdapter; import twitter4j.TwitterException; import twitter4j.TwitterListener; import twitter4j.TwitterMethod; import twitter4j.User; public class ProfileActivity extends BaseActivity implements ObservableScrollViewCallbacks { ImageView bannerImage; private int mParallaxImageHeight; private BasicProfileCard basicInfo; private AsyncTwitter asyncTwitter; private String mScreenName; private NestedListView tweetList; private WingDataHelper DBHelper; private WingUser mUser; private ObservableScrollView scrollView; public static void startActivity(Activity activity, String screen_name) { Intent intent = new Intent(activity, ProfileActivity.class); intent.putExtra(WingStore.TweetColumns.USER_SCREEN_NAME, screen_name); ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity); activity.startActivity(intent, options.toBundle()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_profile); getActionBar().setDisplayHomeAsUpEnabled(true); bannerImage = (ImageView) findViewById(R.id.profile_bannder_image); getActionBar().setTitle(""); getActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(android.R.color.transparent))); mParallaxImageHeight = getResources().getDimensionPixelSize(R.dimen.parallax_image_height); scrollView = (ObservableScrollView) findViewById(R.id.scroll); scrollView.setScrollViewCallbacks(this); DBHelper = new WingDataHelper(this); basicInfo = new BasicProfileCard(this); tweetList = (NestedListView) findViewById(R.id.user_profile_tweets_list); asyncTwitter = WingApp.newTwitterInstance(); asyncTwitter.addListener(listener); initProfileFromIntent(); // show User detail Log.d("DEBUG", "Get User Detail ... "); asyncTwitter.showUser(mScreenName); new Handler().postDelayed(new Runnable() { @Override public void run() { asyncTwitter.getUserTimeline(mScreenName, new Paging().count(5)); } }, 800); } private void initProfileFromIntent() { Intent intent = getIntent(); if (intent.hasExtra(WingStore.TweetColumns.USER_SCREEN_NAME)) { revealBanner(); mScreenName = intent.getStringExtra(WingStore.TweetColumns.USER_SCREEN_NAME); } else if(intent.getData()!=null) { mScreenName = intent.getData().getHost(); } else { revealBanner(); mScreenName = WingApp.getCurrentScreenName(); // finishAfterTransition(); // return; } mUser = DBHelper.getUser(mScreenName); if (mUser == null) { if (intent.hasExtra(WingStore.TweetColumns.USER_NAME)) { // Activity from tweet user, show info from intent mUser = new WingUser(); mUser.user_id = intent.getLongExtra(WingStore.TweetColumns.USER_ID, -1); mUser.name = intent.getStringExtra(WingStore.TweetColumns.USER_NAME); mUser.screenName = intent.getStringExtra(WingStore.TweetColumns.USER_SCREEN_NAME); mUser.avatar = intent.getStringExtra(WingStore.TweetColumns.USER_AVATAR_URL); basicInfo.setUserInfo(mUser); } } else { // Cached user exists, if no banner then disappear the anchor view above profile card if (mUser.banner == null || mUser.banner.isEmpty()) { findViewById(R.id.anchor).setVisibility(View.GONE); } basicInfo.setUserInfo(mUser); } } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); } private void revealBanner() { bannerImage.postOnAnimationDelayed(new Runnable() { @Override public void run() { if (!bannerImage.isAttachedToWindow()) return; int cx = (bannerImage.getRight() + bannerImage.getLeft()) / 4; int cy = (bannerImage.getTop() + bannerImage.getBottom()) * 2 / 3; // get the final radius for the clipping circle int finalRadius = Math.max(bannerImage.getWidth(), bannerImage.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(bannerImage, cx, cy, 0, finalRadius); // make the view visible and start the animation bannerImage.setVisibility(View.VISIBLE); anim.setDuration(400); anim.start(); } }, 100); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); } @Override protected void onResume() { super.onResume(); } private TwitterListener listener = new TwitterAdapter() { @Override public void gotUserDetail(User user) { Log.d("DEBUG", "Got User Detail: " + user.getName() + ", tweets=" + user.getStatusesCount()); WingUser tmpUser = new WingUser(user); if(mUser != null){ tmpUser.isFollowing = mUser.isFollowing; tmpUser.isFollowMe = mUser.isFollowMe; } mUser = tmpUser; mHandler.sendEmptyMessage(GOT_USER_DETAIL); Log.d("DEBUG", "Get User Relation ... "); asyncTwitter.showFriendship(WingApp.getCurrentScreenName(), mUser.screenName); super.gotUserDetail(user); } @Override public void gotUserTimeline(ResponseList<Status> statuses) { super.gotUserTimeline(statuses); Log.d("DEBUG", "Got User Statuses: " + statuses.size()); ArrayList<WingTweet> utweets = new ArrayList<>(); Message msg = new Message(); for (Status ss : statuses) { WingTweet tweet = new WingTweet(ss); utweets.add(tweet); } msg.obj = utweets; msg.what = GOT_USER_TWEETS; mHandler.sendMessage(msg); } @Override public void gotFavorites(ResponseList<Status> statuses) { super.gotFavorites(statuses); Log.d("DEBUG", "Got User Favs: " + statuses.size()); } @Override public void gotShowFriendship(Relationship relationship) { super.gotShowFriendship(relationship); Log.d("DEBUG", "Got Relationship " + relationship.isSourceFollowingTarget()); mUser.isFollowing = relationship.isSourceFollowingTarget(); mUser.isFollowMe = relationship.isTargetFollowingSource(); DBHelper.save(mUser); mHandler.sendEmptyMessage(GOT_RELATIONSHIP); } @Override public void createdFriendship(User user) { super.createdFriendship(user); Log.d("DEBUG", "FOLLOWED"); mUser.isFollowing = true; DBHelper.save(mUser); mHandler.sendEmptyMessage(CREATED_RELATIONSHIP); } @Override public void destroyedFriendship(User user) { super.destroyedFriendship(user); mUser.isFollowing = false; DBHelper.save(mUser); mHandler.sendEmptyMessage(DESTROYED_RELATIONSHIP); } @Override public void onException(TwitterException te, TwitterMethod method) { Toast.makeText(ProfileActivity.this, method.toString() + ": " + te.getMessage(), Toast.LENGTH_SHORT).show(); if (method == TwitterMethod.USER_TIMELINE) { findViewById(R.id.progressBarView).setVisibility(View.INVISIBLE); } super.onException(te, method); } }; private static final int GOT_USER_DETAIL = 0; private static final int GOT_USER_TWEETS = 1; private static final int GOT_RELATIONSHIP = 2; private static final int CREATED_RELATIONSHIP = 3; private static final int DESTROYED_RELATIONSHIP = 4; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case GOT_USER_DETAIL: basicInfo.setUserInfo(mUser); break; case GOT_USER_TWEETS: findViewById(R.id.progressBarView).setVisibility(View.INVISIBLE); UserTweetsAdapter tweetsAdapter = new UserTweetsAdapter(ProfileActivity.this, (ArrayList<WingTweet>) msg.obj); tweetList.setAdapter(tweetsAdapter); break; case GOT_RELATIONSHIP: basicInfo.toFollow.setText(mUser.isFollowing ? "Following" : "Follow"); basicInfo.isFollowadge.setVisibility(mUser.isFollowing ? View.VISIBLE : View.INVISIBLE); break; case DESTROYED_RELATIONSHIP: case CREATED_RELATIONSHIP: basicInfo.toFollowProgress.setVisibility(View.GONE); basicInfo.toFollow.setText(mUser.isFollowing ? "Following" : "Follow"); basicInfo.isFollowadge.setVisibility(mUser.isFollowing ? View.VISIBLE : View.INVISIBLE); break; } super.handleMessage(msg); } }; @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_profile, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. switch (item.getItemId()) { case android.R.id.home: finishAfterTransition(); break; } return super.onOptionsItemSelected(item); } @Override public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) { ViewHelper.setTranslationY(bannerImage, scrollY / 2); if (scrollY > mParallaxImageHeight * 0.15) { getActionBar().hide(); } else { getActionBar().show(); } // if (scrollY < mParallaxImageHeight * 0.15) { //// getActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(android.R.color.transparent))); //// getActionBar().setTitle(""); // getActionBar().show(); // } // if (scrollY < 0) { // getActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.primary))); // if(mUser.name!=null) getActionBar().setTitle(mUser.name); // getActionBar().show(); // } // if (scrollY > mParallaxImageHeight * 1.2) { // getActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.primary))); // if(mUser.name!=null) getActionBar().setTitle(mUser.name); // getActionBar().show(); // // } else if (scrollY > mParallaxImageHeight * 0.2) { // getActionBar().hide(); // } else { // getActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(android.R.color.transparent))); // getActionBar().setTitle(""); // getActionBar().show(); // } } @Override public void onDownMotionEvent() { } @Override public void onUpOrCancelMotionEvent(ScrollState scrollState) { } private void setBackgroundAlpha(View view, float alpha, int baseColor) { int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24; int rgb = 0x00ffffff & baseColor; view.setBackgroundColor(a + rgb); if (alpha == 1) { getActionBar().setTitle("tinyao"); } else { getActionBar().setTitle(""); } } @Override protected void onDestroy() { asyncTwitter.shutdown(); super.onDestroy(); } /** * View Group for Basic UserInfo */ private class BasicProfileCard implements View.OnClickListener{ CircleImageView avatar; TextView name, screenName, address, website; HtmlTextView desc; TextView tweets, followers, followings; TextView toTweet, toFollow; View toFollowV, toFollowProgress; View isFollowadge; public BasicProfileCard(Activity context) { avatar = (CircleImageView) context.findViewById(R.id.user_avatar); name = (TextView) context.findViewById(R.id.user_name); screenName = (TextView) context.findViewById(R.id.user_screen_name); desc = (HtmlTextView) context.findViewById(R.id.user_desc); address = (TextView) context.findViewById(R.id.user_addr); website = (TextView) context.findViewById(R.id.user_web); tweets = (TextView) context.findViewById(R.id.user_tweet_count); followers = (TextView) context.findViewById(R.id.user_follower_count); followings = (TextView) context.findViewById(R.id.user_following_count); toTweet = (TextView) context.findViewById(R.id.user_to_tweet); toFollow = (TextView) context.findViewById(R.id.user_to_follow); toFollowV = context.findViewById(R.id.user_to_follow_v); toFollowProgress = context.findViewById(R.id.user_to_follow_progressbar); isFollowadge = context.findViewById(R.id.user_follow_badge); toTweet.setOnClickListener(this); tweets.setOnClickListener(this); followers.setOnClickListener(this); followings.setOnClickListener(this); toFollowV.setOnClickListener(this); } public void setUserInfo(WingUser user) { name.setText(user.name); screenName.setText(user.screenName); tweets.setText("" + user.tweetCount); followers.setText("" + user.followerCount); followings.setText("" + user.followingCount); toFollow.setText(user.isFollowing ? "Following" : "Follow"); isFollowadge.setVisibility(user.isFollowing ? View.VISIBLE : View.INVISIBLE); if (user.desc != null && !user.desc.isEmpty()) { desc.setHtmlText(user.desc); desc.setVisibility(View.VISIBLE); } if (user.location != null && !user.location.isEmpty()){ address.setText(user.location); address.setVisibility(View.VISIBLE); } if (user.website != null && !user.website.isEmpty()) { website.setText(user.website); website.setMovementMethod(HackyMovementMethod.getInstance()); SpannableStringUtils.removeUnderlines((Spannable) website.getText()); website.setVisibility(View.VISIBLE); } Picasso.with(ProfileActivity.this) .load(user.avatar) // .fit() .into(avatar); if (user.banner != null) { Picasso.with(ProfileActivity.this) .load(user.banner) .error(R.color.primary) .into(bannerImage); } else { Log.d("DEBUG", "currentY: " + scrollView.getCurrentScrollY() + " -- Y: " + scrollView.getScrollY()); if (scrollView.getCurrentScrollY() == 0 && user.bannerColor != null && !user.bannerColor.isEmpty()) { Log.d("DEBUG", "banner color: " + user.bannerColor); bannerImage.setBackgroundColor(Color.parseColor("#FF" + user.bannerColor)); } } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.user_to_follow_v: if (mUser.isFollowing) { // show dialog to confirm unfollow AlertDialog.Builder builder = new AlertDialog.Builder(ProfileActivity.this) .setMessage("Stop following " + mUser.name + " ?") .setTitle("Unfollow") .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { toFollowProgress.setVisibility(View.VISIBLE); Log.d("DEBUG", "UNFOLLOW ... " + mUser.screenName + " - " + mUser.user_id); asyncTwitter.destroyFriendship(mUser.user_id); } }) .setNegativeButton(R.string.no, null); builder.create().show(); } else { // follow toFollowProgress.setVisibility(View.VISIBLE); Log.d("DEBUG", "FOLLOW ... " + mUser.screenName + " - " + mUser.user_id); asyncTwitter.createFriendship(mUser.user_id); } break; case R.id.user_tweet_count: // view user timeline Intent toUserTimeline = new Intent(ProfileActivity.this, UserTimelineActivity.class); toUserTimeline.putExtra(WingStore.UserColumns.SCREEN_NAME, mUser.screenName); toUserTimeline.putExtra(WingStore.UserColumns.NAME, mUser.name); startActivity(toUserTimeline); break; case R.id.user_follower_count: // view all followers break; case R.id.user_following_count: // view all followings break; case R.id.user_to_tweet: // go to compose activity break; } } // private void stripUnderlines(TextView textView) { // Spannable s = (Spannable)textView.getText(); // URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class); // for (URLSpan span: spans) { // int start = s.getSpanStart(span); // int end = s.getSpanEnd(span); // s.removeSpan(span); // span = new URLSpanNoUnderline(span.getURL()); // s.setSpan(span, start, end, 0); // } // textView.setText(s); // } // // class URLSpanNoUnderline extends URLSpan { // public URLSpanNoUnderline(String url) { // super(url); // } // @Override public void updateDrawState(TextPaint ds) { // super.updateDrawState(ds); // ds.setUnderlineText(false); // } // } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // ToDo: When the avatar View not in screen, cancel the element-shared-transition on it if (keyCode == KeyEvent.KEYCODE_BACK) { asyncTwitter.shutdown(); if (scrollView.getCurrentScrollY() > (getResources().getDimensionPixelSize(R.dimen.parallax_image_height) * 1.2) ) { getWindow().setReturnTransition(new Fade()); getWindow().setSharedElementReturnTransition(new Fade()); } } return super.onKeyDown(keyCode, event); } }