Skip to content

Commit a33a8ee

Browse files
Merge pull request #1 from priteshshah1983/butterknife
Almost complete
2 parents f3682f4 + 5bf7daa commit a33a8ee

35 files changed

+1060
-77
lines changed

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ dependencies {
2323
compile 'com.android.support:appcompat-v7:21.0.0+'
2424
compile 'com.squareup.picasso:picasso:2.4.0'
2525
compile 'com.loopj.android:android-async-http:1.4.6'
26+
compile 'com.jakewharton:butterknife:6.1.0'
2627
}

app/src/main/AndroidManifest.xml

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
android:targetSdkVersion="21" />
1010

1111
<uses-permission android:name="android.permission.INTERNET" />
12+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
1213
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
13-
14-
<android:uses-permission android:name="android.permission.READ_PHONE_STATE" />
15-
<android:uses-permission
16-
android:name="android.permission.READ_EXTERNAL_STORAGE"
17-
android:maxSdkVersion="18" />
14+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
15+
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
1816

1917
<application
2018
android:name=".TwitterApplication"
@@ -24,13 +22,13 @@
2422
android:theme="@style/AppTheme" >
2523
<meta-data
2624
android:name="AA_DB_NAME"
27-
android:value="RestClient.db" />
25+
android:value="MySimpleTweets.db" />
2826
<meta-data
2927
android:name="AA_DB_VERSION"
3028
android:value="1" />
3129

3230
<activity
33-
android:name="com.codepath.apps.mysimpletweets.activities.LoginActivity"
31+
android:name=".activities.LoginActivity"
3432
android:label="@string/app_name"
3533
android:theme="@style/AppTheme" >
3634
<intent-filter>
@@ -50,8 +48,17 @@
5048
</intent-filter>
5149
</activity>
5250
<activity
53-
android:name="com.codepath.apps.mysimpletweets.activities.TimelineActivity"
54-
android:label="@string/title_activity_timeline" >
51+
android:name=".activities.TimelineActivity"
52+
android:label="@string/title_activity_timeline"
53+
android:launchMode="singleTop" >
54+
</activity>
55+
<activity
56+
android:name=".activities.TweetDetailsActivity"
57+
android:label="@string/title_activity_tweet_details"
58+
android:parentActivityName=".activities.TimelineActivity" >
59+
<meta-data
60+
android:name="android.support.PARENT_ACTIVITY"
61+
android:value="com.codepath.apps.mysimpletweets.activities.TimelineActivity" />
5562
</activity>
5663
</application>
5764

app/src/main/ic_launcher-web.png

20.2 KB
Loading

app/src/main/java/com/codepath/apps/mysimpletweets/TwitterClient.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.scribe.builder.api.TwitterApi;
66

77
import android.content.Context;
8+
import android.util.Log;
89

910
import com.codepath.oauth.OAuthBaseClient;
1011
import com.loopj.android.http.AsyncHttpResponseHandler;
@@ -23,6 +24,9 @@
2324
*
2425
*/
2526
public class TwitterClient extends OAuthBaseClient {
27+
28+
public static final String TWITTER_DATE_FORMAT = "EEE MMM dd HH:mm:ss ZZZZZ yyyy";
29+
2630
public static final Class<? extends Api> REST_API_CLASS = TwitterApi.class;
2731
public static final String REST_URL = "https://api.twitter.com/1.1"; // Change this, base API URL
2832
public static final String REST_CONSUMER_KEY = "GSgWyeJO5crdazkeDKNjBoybt";
@@ -33,24 +37,29 @@ public TwitterClient(Context context) {
3337
super(context, REST_API_CLASS, REST_URL, REST_CONSUMER_KEY, REST_CONSUMER_SECRET, REST_CALLBACK_URL);
3438
}
3539

36-
// CHANGE THIS
37-
// DEFINE METHODS for different API endpoints here
38-
public void getInterestingnessList(AsyncHttpResponseHandler handler) {
39-
String apiUrl = getApiUrl("?nojsoncallback=1&method=flickr.interestingness.getList");
40-
// Can specify query string params directly or through RequestParams.
41-
RequestParams params = new RequestParams();
42-
params.put("format", "json");
43-
client.get(apiUrl, params, handler);
44-
}
45-
46-
public void getHomeTimeline(AsyncHttpResponseHandler handler) {
40+
public void getHomeTimeline(long max_id, AsyncHttpResponseHandler handler) {
4741
String apiUrl = getApiUrl("statuses/home_timeline.json");
4842
RequestParams params = new RequestParams();
4943
params.put("count", 25);
5044
params.put("since_id", 1);
45+
if (max_id > 0) {
46+
params.put("max_id", max_id);
47+
}
5148
getClient().get(apiUrl, params, handler);
5249
}
5350

51+
public void getCurrentUser(AsyncHttpResponseHandler handler) {
52+
String apiUrl = getApiUrl("account/verify_credentials.json");
53+
getClient().get(apiUrl, null, handler);
54+
}
55+
56+
public void postTweet(String tweet, AsyncHttpResponseHandler handler){
57+
String apiUrl = getApiUrl("statuses/update.json");
58+
RequestParams params = new RequestParams();
59+
params.put("status", tweet);
60+
getClient().post(apiUrl, params, handler);
61+
}
62+
5463
/* 1. Define the endpoint URL with getApiUrl and pass a relative path to the endpoint
5564
* i.e getApiUrl("statuses/home_timeline.json");
5665
* 2. Define the parameters to pass to the request (query or body)

app/src/main/java/com/codepath/apps/mysimpletweets/activities/LoginActivity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class LoginActivity extends OAuthLoginActionBarActivity<TwitterClient> {
1818
protected void onCreate(Bundle savedInstanceState) {
1919
super.onCreate(savedInstanceState);
2020
setContentView(R.layout.activity_login);
21+
getSupportActionBar().hide();
2122
}
2223

2324

Lines changed: 134 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
package com.codepath.apps.mysimpletweets.activities;
22

3+
import android.content.Intent;
4+
import android.support.v4.app.FragmentManager;
35
import android.support.v4.widget.SwipeRefreshLayout;
6+
import android.support.v7.app.ActionBar;
47
import android.support.v7.app.ActionBarActivity;
58
import android.os.Bundle;
69
import android.util.Log;
710
import android.view.Menu;
811
import android.view.MenuItem;
912
import android.widget.ListView;
13+
import android.widget.ProgressBar;
14+
import android.widget.Toast;
1015

1116
import com.codepath.apps.mysimpletweets.R;
1217
import com.codepath.apps.mysimpletweets.TwitterApplication;
1318
import com.codepath.apps.mysimpletweets.TwitterClient;
19+
import com.codepath.apps.mysimpletweets.adapters.EndlessScrollListener;
1420
import com.codepath.apps.mysimpletweets.adapters.TweetsArrayAdapter;
21+
import com.codepath.apps.mysimpletweets.fragments.TweetFragment;
22+
import com.codepath.apps.mysimpletweets.models.CacheManager;
1523
import com.codepath.apps.mysimpletweets.models.Tweet;
24+
import com.codepath.apps.mysimpletweets.models.User;
25+
import com.codepath.apps.mysimpletweets.utils.ConnectivityHelper;
1626
import com.loopj.android.http.JsonHttpResponseHandler;
1727

1828
import org.apache.http.Header;
@@ -21,35 +31,58 @@
2131

2232
import java.util.ArrayList;
2333

24-
public class TimelineActivity extends ActionBarActivity {
34+
import butterknife.ButterKnife;
35+
import butterknife.InjectView;
36+
import butterknife.OnClick;
37+
import butterknife.OnItemClick;
38+
import butterknife.OnItemSelected;
39+
40+
public class TimelineActivity extends ActionBarActivity implements TweetFragment.TweetFragmentListener {
2541

2642
private static final String TAG = TimelineActivity.class.getName();
2743

2844
private TwitterClient client;
2945
private ArrayList<Tweet> tweets;
3046
private TweetsArrayAdapter aTweets;
31-
private ListView lvTweets;
32-
private SwipeRefreshLayout swipeContainer;
47+
@InjectView(R.id.lvTweets) ListView lvTweets;
48+
@InjectView(R.id.swipeContainer) SwipeRefreshLayout swipeContainer;
49+
@InjectView(R.id.pbLoading) ProgressBar progressBar;
50+
51+
private long max_id;
52+
private User currentUser;
3353

3454
@Override
3555
protected void onCreate(Bundle savedInstanceState) {
3656
super.onCreate(savedInstanceState);
3757
setContentView(R.layout.activity_timeline);
38-
lvTweets = (ListView) findViewById(R.id.lvTweets);
58+
ButterKnife.inject(this);
59+
lvTweets.setOnScrollListener(new EndlessScrollListener() {
60+
@Override
61+
public void onLoadMore(int page, int totalItemsCount) {
62+
// Triggered only when new data needs to be appended to the list
63+
// Add whatever code is needed to append new items to your AdapterView
64+
customLoadMoreDataFromApi(page);
65+
// or customLoadMoreDataFromApi(totalItemsCount);
66+
}
67+
});
3968
tweets = new ArrayList<>();
4069
aTweets = new TweetsArrayAdapter(this, tweets);
4170
lvTweets.setAdapter(aTweets);
4271
client = TwitterApplication.getRestClient();
72+
aTweets.addAll(CacheManager.latestTweets());
73+
populateCurrentUser();
74+
max_id = 0;
4375
populateTimeline();
4476

45-
swipeContainer = (SwipeRefreshLayout) findViewById(R.id.swipeContainer);
4677
// Setup refresh listener which triggers new data loading
4778
swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
4879
@Override
4980
public void onRefresh() {
5081
// Your code to refresh the list here.
5182
// Make sure you call swipeContainer.setRefreshing(false)
5283
// once the network request has completed successfully.
84+
max_id = 0;
85+
populateCurrentUser();
5386
populateTimeline();
5487
}
5588
});
@@ -60,13 +93,12 @@ public void onRefresh() {
6093
android.R.color.holo_red_light);
6194
}
6295

63-
private void populateTimeline() {
64-
client.getHomeTimeline(new JsonHttpResponseHandler() {
96+
private void populateCurrentUser() {
97+
client.getCurrentUser(new JsonHttpResponseHandler() {
6598
@Override
66-
public void onSuccess(int statusCode, Header[] headers, JSONArray json) {
67-
aTweets.clear();
68-
aTweets.addAll(Tweet.fromJSON(json));
69-
swipeContainer.setRefreshing(false);
99+
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
100+
currentUser = User.fromJSON(response);
101+
Log.d(TAG, "user populated: " + currentUser.getScreenName());
70102
}
71103

72104
@Override
@@ -76,6 +108,47 @@ public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSO
76108
});
77109
}
78110

111+
// Append more data into the adapter
112+
public void customLoadMoreDataFromApi(int offset) {
113+
// Log.d(TAG, "page = " + offset);
114+
populateTimeline();
115+
// This method probably sends out a network request and appends new data items to your adapter.
116+
// Use the offset value and add it as a parameter to your API request to retrieve paginated data.
117+
// Deserialize API response and then construct new objects to append to the adapter
118+
}
119+
120+
private void populateTimeline() {
121+
if (!ConnectivityHelper.isNetworkAvailable(this)) {
122+
ConnectivityHelper.notifyUserAboutNoInternetConnectivity(this);
123+
} else {
124+
progressBar.setVisibility(ProgressBar.VISIBLE);
125+
client.getHomeTimeline(max_id, new JsonHttpResponseHandler() {
126+
@Override
127+
public void onSuccess(int statusCode, Header[] headers, JSONArray json) {
128+
if (max_id == 0) {
129+
aTweets.clear();
130+
}
131+
ArrayList<Tweet> responseTweets = Tweet.fromJSON(json);
132+
// Fire and forget
133+
CacheManager.saveTweets(responseTweets);
134+
aTweets.addAll(responseTweets);
135+
Tweet lastTweet = aTweets.getItem(aTweets.getCount() - 1);
136+
max_id = lastTweet.getUid() - 1;
137+
// Log.d(TAG, "max_id = " + max_id);
138+
swipeContainer.setRefreshing(false);
139+
progressBar.setVisibility(ProgressBar.INVISIBLE);
140+
}
141+
142+
@Override
143+
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
144+
Log.e(TAG, "Failed to call API: " + throwable);
145+
progressBar.setVisibility(ProgressBar.INVISIBLE);
146+
ConnectivityHelper.notifyUserAboutAPIError(TimelineActivity.this);
147+
}
148+
});
149+
}
150+
}
151+
79152

80153
@Override
81154
public boolean onCreateOptionsMenu(Menu menu) {
@@ -86,16 +159,57 @@ public boolean onCreateOptionsMenu(Menu menu) {
86159

87160
@Override
88161
public boolean onOptionsItemSelected(MenuItem item) {
89-
// Handle action bar item clicks here. The action bar will
90-
// automatically handle clicks on the Home/Up button, so long
91-
// as you specify a parent activity in AndroidManifest.xml.
92-
int id = item.getItemId();
93-
94-
//noinspection SimplifiableIfStatement
95-
if (id == R.id.action_settings) {
96-
return true;
162+
// Handle presses on the action bar items
163+
switch (item.getItemId()) {
164+
case R.id.miTweet:
165+
showTweetDialog();
166+
return true;
167+
default:
168+
return super.onOptionsItemSelected(item);
169+
}
170+
}
171+
172+
private void showTweetDialog() {
173+
FragmentManager fragmentManager = getSupportFragmentManager();
174+
TweetFragment tweetFragment = TweetFragment.newInstance(currentUser);
175+
tweetFragment.show(fragmentManager, "fragment_tweet");
176+
}
177+
178+
@Override
179+
public void onTweet(String tweet) {
180+
tweet = tweet.trim();
181+
Log.d(TAG, "Posting tweet to Twitter: " + tweet);
182+
if (tweet.length() > 0){
183+
if (!ConnectivityHelper.isNetworkAvailable(this)) {
184+
ConnectivityHelper.notifyUserAboutNoInternetConnectivity(this);
185+
} else {
186+
progressBar.setVisibility(ProgressBar.VISIBLE);
187+
client.postTweet(tweet, new JsonHttpResponseHandler() {
188+
@Override
189+
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
190+
tweets.add(0, Tweet.fromJSON(response));
191+
aTweets.notifyDataSetChanged();
192+
progressBar.setVisibility(ProgressBar.INVISIBLE);
193+
Toast.makeText(TimelineActivity.this, R.string.tweet_posted_successfully, Toast.LENGTH_SHORT).show();
194+
}
195+
196+
@Override
197+
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
198+
Log.e(TAG, "Failed to call API: " + throwable);
199+
progressBar.setVisibility(ProgressBar.INVISIBLE);
200+
ConnectivityHelper.notifyUserAboutAPIError(TimelineActivity.this);
201+
}
202+
});
203+
}
97204
}
205+
}
98206

99-
return super.onOptionsItemSelected(item);
207+
@SuppressWarnings("unused") // it's actually used, just injected by Butter Knife
208+
@OnItemClick(R.id.lvTweets)
209+
void onItemSelected(int position) {
210+
Intent i = new Intent(TimelineActivity.this, TweetDetailsActivity.class);
211+
Tweet tweet = tweets.get(position);
212+
i.putExtra(TweetDetailsActivity.EXTRA_TWEET, tweet);
213+
startActivity(i);
100214
}
101215
}

0 commit comments

Comments
 (0)