Java tutorial
/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package me.jreilly.JamesTweet.TweetView; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.SpannableString; import android.text.format.DateUtils; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TabHost; import android.widget.TextView; import android.widget.Toast; import com.squareup.picasso.Picasso; import com.squareup.picasso.Transformation; import com.twitter.sdk.android.Twitter; import com.twitter.sdk.android.core.Callback; import com.twitter.sdk.android.core.Result; import com.twitter.sdk.android.core.TwitterCore; import com.twitter.sdk.android.core.TwitterException; import com.twitter.sdk.android.core.models.Tweet; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; import io.realm.Realm; import io.realm.RealmResults; import me.jreilly.JamesTweet.Adapters.RealmAdapter; import me.jreilly.JamesTweet.Etc.ComposeActivity; import me.jreilly.JamesTweet.Models.RealmHelper; import me.jreilly.JamesTweet.Models.TweetRealm; import me.jreilly.JamesTweet.Profile.ProfileActivity; import me.jreilly.JamesTweet.R; import me.jreilly.JamesTweet.TweetParsers.ProfileLink; import me.jreilly.JamesTweet.TweetParsers.ProfileSwitch; /** * Created by jreilly on 1/19/15. * The Fragment of the detail of the Tweet given * It is passed the tweet ID and the name of the Realm database the tweet is stored in the intent */ public class TweetFragment extends android.support.v4.app.Fragment implements ProfileSwitch { /** Variable to hold the visual objects that need to be filled */ private long mTweetId; private TextView mTweet; private TextView mUser; private TextView mDate; private ImageButton mImage; private ImageButton mProfileImage; private ImageButton mReplyButton; private ImageButton mRetweetButton; private ImageButton mFavoriteButton; /** Variables to hold the data for the RecyclerView */ private ProfileSwitch mActivity; private RecyclerView mRecyclerView; private RecyclerView.LayoutManager mLayoutManager; /**Vairables for the Realm */ private RealmAdapter mAdapter; private RealmResults<TweetRealm> mDataset; private RealmHelper mRealmHelper; private String mRealmLoc; private TabHost mTabHost; private int currentTab; private View mRoot; private final String LOG_TAG = "TweetFragment"; public TweetFragment() { } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getActivity().getIntent(); if (intent != null && intent.hasExtra(TweetActivity.TWEET_KEY)) { //Get the ID of the tweet to be displayed mTweetId = intent.getLongExtra(TweetActivity.TWEET_KEY, 0); //Get the database in which this tweet is stored mRealmLoc = intent.getStringExtra(TweetActivity.REALM_KEY); Log.v(LOG_TAG, "Got Tweet id: " + mTweetId); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_tweet, container, false); mRoot = rootView; //Get Visuals to set mUser = (TextView) rootView.findViewById(R.id.my_user); mTweet = (TextView) rootView.findViewById(R.id.my_text); mImage = (ImageButton) rootView.findViewById(R.id.my_picture); mDate = (TextView) rootView.findViewById(R.id.my_time); mProfileImage = (ImageButton) rootView.findViewById(R.id.user_image); mReplyButton = (ImageButton) rootView.findViewById(R.id.tweet_reply_button); mRetweetButton = (ImageButton) rootView.findViewById(R.id.tweet_retweet_button); mFavoriteButton = (ImageButton) rootView.findViewById(R.id.tweet_favorite_button); //private variable to use to switch to other profiles mActivity = (ProfileSwitch) getActivity(); //Get the database that is storing the tweet to be accessed Realm realm; if (mRealmLoc.equals("null")) { realm = Realm.getInstance(this.getActivity()); } else { realm = Realm.getInstance(this.getActivity(), mRealmLoc); } //Query the database for the selected tweet RealmResults<TweetRealm> result = realm.where(TweetRealm.class).equalTo("id", mTweetId).findAll(); //Sets the layout of the fragment setTweet(result); //Setup the favorite/retweet/layout button (Haven't changed function name) setUpTweetLayout(); //Initialize the RecyclerView to hold the replies mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_replies); mLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mLayoutManager); //Clear the database, etc. setUpRealm(); //get at max 15 replies from tweet and populate data getReplies(mTweetId, 15, true); //Initialize variables for the adapter ProfileSwitch pFragment = this; int shortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); //initialize the RealmAdapter for the tweet mAdapter = new RealmAdapter(mDataset, rootView, shortAnimationDuration, pFragment, null, true); //Set the adapter to the recyclerview mRecyclerView.setAdapter(mAdapter); return rootView; } @Override public void onResume() { super.onResume(); setUpRealm(); getReplies(mTweetId, 15, true); } /** * Sets the realm up for the use of the fragment * It clears the database and assigns the database the data for the adapter */ public void setUpRealm() { //Initialize the helper mRealmHelper = new RealmHelper(this.getActivity(), "tweet.realm"); //Get the tweet reply realm Realm realm = mRealmHelper.getRealm(); //Clear the Database from previous tweets realm.beginTransaction(); realm.clear(TweetRealm.class); realm.commitTransaction(); //Get sorted tweets mDataset = mRealmHelper.getTweets(15); } /** * Sets all the visual elements of the detail view of the tweet using the private variable * mTweetId */ public void setUpTweetLayout() { Twitter.getApiClient().getStatusesService().show(mTweetId, null, true, true, new Callback<Tweet>() { @Override public void success(Result<Tweet> tweetResult) { final Tweet t = tweetResult.data; //Setting the replaybutton mReplyButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getActivity(), ComposeActivity.class) .putExtra(ComposeActivity.REPLY_ID, mTweetId) .putExtra(ComposeActivity.REPLY_USER, "@" + t.user.screenName); startActivity(intent); } }); //Set initial favorite highlight if (t.favorited) { mFavoriteButton .setImageDrawable(getResources().getDrawable(R.drawable.ic_toggle_star_selected)); } else { mFavoriteButton .setImageDrawable(getResources().getDrawable(R.drawable.ic_star_outline_grey600_24dp)); } //setactionlistener setFavoriteButton(); //Set initial retweet highlight if (t.retweeted) { mRetweetButton .setImageDrawable(getResources().getDrawable(R.drawable.ic_action_cached_selected)); } else { mRetweetButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_cached_grey600_24dp)); } //setactionlistener setRetweetButton(); Log.v(LOG_TAG, "Set all attributes!"); } @Override public void failure(TwitterException e) { Log.e(LOG_TAG, "Could not get Tweets : " + e); } }); } public void setTweet(RealmResults<TweetRealm> mDataset) { int i = 0; String user_img = mDataset.get(i).getProfileImageUrl(); final String user_screen = mDataset.get(i).getScreename(); String media_url = "null"; Date created = mDataset.get(i).getDate(); boolean retweeted = mDataset.get(i).isRetweetedStatus(); String original = mDataset.get(i).getRetweetedBy(); String username = mDataset.get(i).getName(); String text = mDataset.get(i).getText(); final long tId = mDataset.get(i).getId(); //Load Profile Image Picasso.with(mProfileImage.getContext()).load(user_img).transform(new CircleTransform()) .into(mProfileImage); //Set profile image to go to the users profile mProfileImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mActivity.swapToProfile(user_screen, mProfileImage); } }); final String imageUrl = media_url; ViewGroup.LayoutParams params = mImage.getLayoutParams(); //Set Cropped Media image and zoomImage animation if (!imageUrl.equals("null")) { mImage.getLayoutParams().height = 400; Picasso.with(mImage.getContext()).load(imageUrl).fit().centerCrop().into(mImage); } else { //Media is not need so it is hidden. mImage.setImageDrawable(null); mImage.getLayoutParams().height = 0; } //Set Username Text Field Calendar cal = Calendar.getInstance(); mDate.setText(DateUtils.getRelativeTimeSpanString(created.getTime())); mUser.setText(username); String tweetText = text; //Highlight Profile names/hashtags and their clickable spans ArrayList<int[]> hashtagSpans = getSpans(tweetText, '#'); ArrayList<int[]> profileSpans = getSpans(tweetText, '@'); SpannableString tweetContent = new SpannableString(tweetText); for (int j = 0; j < profileSpans.size(); j++) { int[] span = profileSpans.get(j); int profileStart = span[0]; int profileEnd = span[1]; tweetContent.setSpan(new ProfileLink(mTweet.getContext(), mActivity), profileStart, profileEnd, 0); } mTweet.setMovementMethod(LinkMovementMethod.getInstance()); mTweet.setText(tweetContent); } /** * @param body The text to span * @param prefix The symbol at the beggining of the span * @return The clickable spans * Sets the clickable spans for any prefix * (This program uses it for @ strings and # strings */ public ArrayList<int[]> getSpans(String body, char prefix) { ArrayList<int[]> spans = new ArrayList<int[]>(); Pattern pattern = Pattern.compile(prefix + "\\w+"); Matcher matcher = pattern.matcher(body); // Check all occurrences while (matcher.find()) { int[] currentSpan = new int[2]; currentSpan[0] = matcher.start(); currentSpan[1] = matcher.end(); spans.add(currentSpan); } return spans; } /** * @param id The id of the tweet to get replies to * @param num_left number of depths left to search * @param first if the first tweet in the reply search * Gets the replies to a tweet recursively */ public void getReplies(long id, final int num_left, final boolean first) { Twitter.getApiClient().getStatusesService().show(id, null, true, true, new Callback<Tweet>() { @Override public void success(Result<Tweet> tweetResult) { if (!first) { mRealmHelper.insertToRealm(tweetResult.data); mRecyclerView.getAdapter().notifyDataSetChanged(); } if (tweetResult.data.inReplyToStatusIdStr != null && num_left > 0) { getReplies(tweetResult.data.inReplyToStatusId, num_left - 1, false); } } @Override public void failure(TwitterException e) { Log.e(LOG_TAG, "Excpetion: " + e); } }); } /** * sets the clickListener for the favorite button */ public void setFavoriteButton() { mFavoriteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Twitter.getApiClient().getStatusesService().show(mTweetId, null, true, true, new Callback<Tweet>() { @Override public void success(Result<Tweet> tweetResult) { Tweet t = tweetResult.data; if (t.favorited) { TwitterCore.getInstance().getApiClient().getFavoriteService().destroy(mTweetId, null, new Callback<Tweet>() { @Override public void success(Result result) { Toast.makeText(mFavoriteButton.getContext(), "FAVORITE!", Toast.LENGTH_SHORT).show(); mFavoriteButton.setImageDrawable(getResources() .getDrawable(R.drawable.ic_star_outline_grey600_24dp)); } @Override public void failure(TwitterException e) { } }); } else { TwitterCore.getInstance().getApiClient().getFavoriteService().create(mTweetId, null, new Callback<Tweet>() { @Override public void success(Result result) { Toast.makeText(mFavoriteButton.getContext(), "FAVORITE!", Toast.LENGTH_SHORT).show(); mFavoriteButton.setImageDrawable( getResources().getDrawable(R.drawable.ic_toggle_star_selected)); } @Override public void failure(TwitterException e) { Toast.makeText(mFavoriteButton.getContext(), "Exception " + e, Toast.LENGTH_SHORT).show(); } }); } } @Override public void failure(TwitterException e) { Log.e("TweetFragment", "Exception: " + e); } }); } }); } /** * sets the clickListener for the retweet button */ public void setRetweetButton() { mRetweetButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Twitter.getApiClient().getStatusesService().show(mTweetId, null, true, true, new Callback<Tweet>() { @Override public void success(Result<Tweet> tweetResult) { Tweet t = tweetResult.data; if (t.retweeted) { Log.v(LOG_TAG, t.currentUserRetweet.toString()); String retweetId = t.currentUserRetweet.toString(); int id = retweetId.indexOf("id_str=") + 7; String id2 = retweetId.substring(id, retweetId.length() - 1); Log.v(LOG_TAG, id2); long rtId = Long.valueOf(id2); TwitterCore.getInstance().getApiClient().getStatusesService().destroy(rtId, null, new Callback<Tweet>() { @Override public void success(Result<Tweet> tweetResult) { Toast.makeText(mRetweetButton.getContext(), "UN-RETWEETED!", Toast.LENGTH_SHORT).show(); mRetweetButton.setImageDrawable( getResources().getDrawable(R.drawable.ic_cached_grey600_24dp)); } @Override public void failure(TwitterException e) { Log.e("TweetFragment", "Exception: " + e); } }); } else { TwitterCore.getInstance().getApiClient().getStatusesService().retweet(mTweetId, null, new Callback<Tweet>() { @Override public void success(Result result) { Toast.makeText(mRetweetButton.getContext(), "RETWEET!", Toast.LENGTH_SHORT).show(); mRetweetButton.setImageDrawable(getResources() .getDrawable(R.drawable.ic_action_cached_selected)); } @Override public void failure(TwitterException e) { } }); } } @Override public void failure(TwitterException e) { } }); } }); } /** * @param uId The ID of the profile to switch to * Starts the ProfileActivity with the uID passed as the intent */ public void swapToProfile(String uId, View view) { Intent intent = new Intent(getActivity(), ProfileActivity.class).putExtra(ProfileActivity.PROFILE_KEY, uId); startActivity(intent); getActivity().finish(); } /** * @param tweetId The ID of the tweet to show * Starts the TweetActivity with the tweetID passed as the intent */ public void swapToTweet(long tweetId, View view) { Intent intent = new Intent(getActivity(), TweetActivity.class).putExtra(TweetActivity.TWEET_KEY, tweetId) .putExtra(TweetActivity.REALM_KEY, "tweet.realm"); String transitionName = getString(R.transition.transition); Log.v(LOG_TAG, transitionName); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this.getActivity(), view, // The view which starts the transition transitionName // The transitionName of the view were transitioning to ); ActivityCompat.startActivity(this.getActivity(), intent, options.toBundle()); } @Override public void onDestroy() { super.onDestroy(); Realm realm = mRealmHelper.getRealm(); realm.beginTransaction(); realm.clear(TweetRealm.class); realm.commitTransaction(); realm.close(); } /** * Transform a square image into a circular one. */ public class CircleTransform implements Transformation { @Override public Bitmap transform(Bitmap source) { int size = Math.min(source.getWidth(), source.getHeight()); int x = (source.getWidth() - size) / 2; int y = (source.getHeight() - size) / 2; Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); if (squaredBitmap != source) { source.recycle(); } Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig()); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); paint.setShader(shader); paint.setAntiAlias(true); float r = size / 2f; canvas.drawCircle(r, r, r, paint); squaredBitmap.recycle(); return bitmap; } @Override public String key() { return "circle"; } } }