Use OkHttp3 Authenticator instead of OkHttp Interceptor to handle the case when the request fails with code 401. Refresh the access token in a synchronized block to avoid getting more than one access tokens and getting duplicate posts when performing multiple unauthorized requests. Minor bugs fixed.

This commit is contained in:
Alex Ning 2018-10-14 11:24:38 +08:00
parent 8b52810d7c
commit 4d0a0725c9
15 changed files with 220 additions and 335 deletions

View File

@ -0,0 +1,43 @@
package ml.docilealligator.infinityforreddit;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.io.IOException;
import okhttp3.Authenticator;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
class AccessTokenAuthenticator implements Authenticator {
private SharedPreferences mAuthInfoSharedPreferences;
AccessTokenAuthenticator(SharedPreferences authInfoSharedPreferences) {
mAuthInfoSharedPreferences = authInfoSharedPreferences;
}
@Nullable
@Override
public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException {
if (response.code() == 401) {
String accessToken = response.request().header(RedditUtils.AUTHORIZATION_KEY).substring(RedditUtils.AUTHORIZATION_BASE.length());
synchronized (this) {
String accessTokenFromSharedPreferences = mAuthInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
if (accessToken.equals(accessTokenFromSharedPreferences)) {
String newAccessToken = RefreshAccessToken.refreshAccessToken(mAuthInfoSharedPreferences);
if (!newAccessToken.equals("")) {
return response.request().newBuilder().headers(Headers.of(RedditUtils.getOAuthHeader(newAccessToken))).build();
} else {
return null;
}
} else {
return response.request().newBuilder().headers(Headers.of(RedditUtils.getOAuthHeader(accessTokenFromSharedPreferences))).build();
}
}
}
return null;
}
}

View File

@ -1,6 +1,7 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
@ -29,19 +30,22 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
private Context mContext; private Context mContext;
private Retrofit mRetrofit; private Retrofit mRetrofit;
private Retrofit mOauthRetrofit; private Retrofit mOauthRetrofit;
private SharedPreferences mSharedPreferences;
private ArrayList<CommentData> mCommentData; private ArrayList<CommentData> mCommentData;
private MultiLevelRecyclerView mMultiLevelRecyclerView; private MultiLevelRecyclerView mMultiLevelRecyclerView;
private String subredditNamePrefixed; private String subredditNamePrefixed;
private String article; private String article;
private Locale locale; private Locale locale;
CommentMultiLevelRecyclerViewAdapter(Context context, Retrofit retrofit, Retrofit oauthRetrofit, ArrayList<CommentData> commentData, CommentMultiLevelRecyclerViewAdapter(Context context, Retrofit retrofit, Retrofit oauthRetrofit,
SharedPreferences sharedPreferences, ArrayList<CommentData> commentData,
MultiLevelRecyclerView multiLevelRecyclerView, MultiLevelRecyclerView multiLevelRecyclerView,
String subredditNamePrefixed, String article, Locale locale) { String subredditNamePrefixed, String article, Locale locale) {
super(commentData); super(commentData);
mContext = context; mContext = context;
mRetrofit = retrofit; mRetrofit = retrofit;
mOauthRetrofit = oauthRetrofit; mOauthRetrofit = oauthRetrofit;
mSharedPreferences = sharedPreferences;
mCommentData = commentData; mCommentData = commentData;
mMultiLevelRecyclerView = multiLevelRecyclerView; mMultiLevelRecyclerView = multiLevelRecyclerView;
this.subredditNamePrefixed = subredditNamePrefixed; this.subredditNamePrefixed = subredditNamePrefixed;
@ -136,7 +140,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1));
} }
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit,mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
commentItem.setVoteType(1); commentItem.setVoteType(1);
@ -154,13 +158,13 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
((CommentViewHolder) holder).downvoteButton.setColorFilter(minusButtonColorFilter); ((CommentViewHolder) holder).downvoteButton.setColorFilter(minusButtonColorFilter);
} }
}, commentItem.getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); }, commentItem.getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) holder).getAdapterPosition());
} else { } else {
//Upvoted before //Upvoted before
((CommentViewHolder) holder).upvoteButton.clearColorFilter(); ((CommentViewHolder) holder).upvoteButton.clearColorFilter();
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1)); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1));
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
commentItem.setVoteType(0); commentItem.setVoteType(0);
@ -174,7 +178,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); ((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
commentItem.setScore(commentItem.getScore() + 1); commentItem.setScore(commentItem.getScore() + 1);
} }
}, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) holder).getAdapterPosition());
} }
} }
}); });
@ -195,7 +199,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1)); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1));
} }
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
commentItem.setVoteType(-1); commentItem.setVoteType(-1);
@ -213,13 +217,13 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
((CommentViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter); ((CommentViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter);
} }
}, commentItem.getFullName(), RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition(), 1); }, commentItem.getFullName(), RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition());
} else { } else {
//Down voted before //Down voted before
((CommentViewHolder) holder).downvoteButton.clearColorFilter(); ((CommentViewHolder) holder).downvoteButton.clearColorFilter();
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1));
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
commentItem.setVoteType(0); commentItem.setVoteType(0);
@ -233,7 +237,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
commentItem.setScore(commentItem.getScore()); commentItem.setScore(commentItem.getScore());
} }
}, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, holder.getAdapterPosition(), 1); }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, holder.getAdapterPosition());
} }
} }
}); });

View File

@ -1,6 +1,6 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.SharedPreferences;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
@ -19,20 +19,15 @@ class FetchSubscribedThing {
void onFetchSubscribedThingFail(); void onFetchSubscribedThingFail();
} }
static void fetchSubscribedThing(final Context context, final Retrofit retrofit, final String lastItem, static void fetchSubscribedThing(final Retrofit retrofit, final SharedPreferences sharedPreferences,
final String lastItem,
final ArrayList<SubscribedSubredditData> subscribedSubredditData, final ArrayList<SubscribedSubredditData> subscribedSubredditData,
final ArrayList<SubscribedUserData> subscribedUserData, final ArrayList<SubscribedUserData> subscribedUserData,
final ArrayList<SubredditData> subredditData, final ArrayList<SubredditData> subredditData,
final FetchSubscribedThingListener fetchSubscribedThingListener, final int refreshTime) { final FetchSubscribedThingListener fetchSubscribedThingListener) {
if(refreshTime < 0) {
fetchSubscribedThingListener.onFetchSubscribedThingFail();
return;
}
RedditAPI api = retrofit.create(RedditAPI.class); RedditAPI api = retrofit.create(RedditAPI.class);
String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) String accessToken = sharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
Call<String> subredditDataCall = api.getSubscribedThing(lastItem, RedditUtils.getOAuthHeader(accessToken)); Call<String> subredditDataCall = api.getSubscribedThing(lastItem, RedditUtils.getOAuthHeader(accessToken));
subredditDataCall.enqueue(new Callback<String>() { subredditDataCall.enqueue(new Callback<String>() {
@ -52,9 +47,9 @@ class FetchSubscribedThing {
fetchSubscribedThingListener.onFetchSubscribedThingSuccess( fetchSubscribedThingListener.onFetchSubscribedThingSuccess(
subscribedSubredditData, subscribedUserData, subredditData); subscribedSubredditData, subscribedUserData, subredditData);
} else { } else {
fetchSubscribedThing(context, retrofit, lastItem, subscribedSubredditData, fetchSubscribedThing(retrofit, sharedPreferences, lastItem, subscribedSubredditData,
subscribedUserData, subredditData, subscribedUserData, subredditData,
fetchSubscribedThingListener, refreshTime); fetchSubscribedThingListener);
} }
} }
@ -63,17 +58,6 @@ class FetchSubscribedThing {
fetchSubscribedThingListener.onFetchSubscribedThingFail(); fetchSubscribedThingListener.onFetchSubscribedThingFail();
} }
}); });
} else if(response.code() == 401) {
RefreshAccessToken.refreshAccessToken(context, new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
fetchSubscribedThing(context, retrofit, lastItem, subscribedSubredditData,
subscribedUserData, subredditData, fetchSubscribedThingListener, refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {}
});
} else { } else {
Log.i("call failed", response.message()); Log.i("call failed", response.message());
fetchSubscribedThingListener.onFetchSubscribedThingFail(); fetchSubscribedThingListener.onFetchSubscribedThingFail();

View File

@ -1,6 +1,6 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.SharedPreferences;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
@ -15,32 +15,17 @@ class FetchUserInfo {
void onFetchUserInfoFail(); void onFetchUserInfoFail();
} }
static void fetchUserInfo(final Retrofit retrofit, final Context context, final FetchUserInfoListener fetchUserInfoListener, final int refreshTime) { static void fetchUserInfo(final Retrofit retrofit, SharedPreferences authInfoSharedPreferences,
if(refreshTime < 0) { final FetchUserInfoListener fetchUserInfoListener) {
fetchUserInfoListener.onFetchUserInfoFail();
return;
}
RedditAPI api = retrofit.create(RedditAPI.class); RedditAPI api = retrofit.create(RedditAPI.class);
String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
Call<String> userInfo = api.getUserInfo(RedditUtils.getOAuthHeader(accessToken)); Call<String> userInfo = api.getUserInfo(RedditUtils.getOAuthHeader(accessToken));
userInfo.enqueue(new Callback<String>() { userInfo.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
if(response.isSuccessful()) { if(response.isSuccessful()) {
fetchUserInfoListener.onFetchUserInfoSuccess(response.body()); fetchUserInfoListener.onFetchUserInfoSuccess(response.body());
} else if(response.code() == 401){
RefreshAccessToken.refreshAccessToken(context, new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
fetchUserInfo(retrofit, context, fetchUserInfoListener, refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {}
});
} else { } else {
Log.i("call failed", response.message()); Log.i("call failed", response.message());
fetchUserInfoListener.onFetchUserInfoFail(); fetchUserInfoListener.onFetchUserInfoFail();

View File

@ -9,7 +9,9 @@ public class Infinity extends Application {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
mNetworkComponent = DaggerNetworkComponent.create(); mNetworkComponent = DaggerNetworkComponent.builder()
.networkModule(new NetworkModule(this))
.build();
} }
public NetworkComponent getmNetworkComponent() { public NetworkComponent getmNetworkComponent() {

View File

@ -26,7 +26,6 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager; import com.bumptech.glide.RequestManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -65,8 +64,13 @@ public class MainActivity extends AppCompatActivity {
private SubscribedSubredditViewModel mSubscribedSubredditViewModel; private SubscribedSubredditViewModel mSubscribedSubredditViewModel;
private SubscribedUserViewModel mSubscribedUserViewModel; private SubscribedUserViewModel mSubscribedUserViewModel;
@Inject @Inject @Named("user_info")
@Named("oauth") SharedPreferences mUserInfoSharedPreferences;
@Inject @Named("auth_info")
SharedPreferences mAuthInfoSharedPreferences;
@Inject @Named("oauth")
Retrofit mOauthRetrofit; Retrofit mOauthRetrofit;
@Override @Override
@ -101,28 +105,7 @@ public class MainActivity extends AppCompatActivity {
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit(); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit();
} }
Calendar now = Calendar.getInstance();
Calendar queryAccessTokenTime = Calendar.getInstance();
queryAccessTokenTime.setTimeInMillis(getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE)
.getLong(SharedPreferencesUtils.QUERY_ACCESS_TOKEN_TIME_KEY, 0));
int interval = getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE)
.getInt(SharedPreferencesUtils.ACCESS_TOKEN_EXPIRE_INTERVAL_KEY, 0);
queryAccessTokenTime.add(Calendar.SECOND, interval - 300);
if(now.after(queryAccessTokenTime)) {
RefreshAccessToken.refreshAccessToken(this,
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
loadUserData(savedInstanceState); loadUserData(savedInstanceState);
}
@Override
public void onRefreshAccessTokenFail() {}
});
} else {
loadUserData(savedInstanceState);
}
View header = findViewById(R.id.nav_header_main_activity); View header = findViewById(R.id.nav_header_main_activity);
mNameTextView = header.findViewById(R.id.name_text_view_nav_header_main); mNameTextView = header.findViewById(R.id.name_text_view_nav_header_main);
@ -191,7 +174,7 @@ public class MainActivity extends AppCompatActivity {
private void loadUserData(Bundle savedInstanceState) { private void loadUserData(Bundle savedInstanceState) {
if (savedInstanceState == null) { if (savedInstanceState == null) {
if (!mFetchUserInfoSuccess) { if (!mFetchUserInfoSuccess) {
FetchUserInfo.fetchUserInfo(mOauthRetrofit, this, new FetchUserInfo.FetchUserInfoListener() { FetchUserInfo.fetchUserInfo(mOauthRetrofit, mAuthInfoSharedPreferences, new FetchUserInfo.FetchUserInfoListener() {
@Override @Override
public void onFetchUserInfoSuccess(String response) { public void onFetchUserInfoSuccess(String response) {
ParseUserInfo.parseUserInfo(response, new ParseUserInfo.ParseUserInfoListener() { ParseUserInfo.parseUserInfo(response, new ParseUserInfo.ParseUserInfoListener() {
@ -212,7 +195,7 @@ public class MainActivity extends AppCompatActivity {
mKarmaTextView.setText(mKarma); mKarmaTextView.setText(mKarma);
SharedPreferences.Editor editor = getSharedPreferences(SharedPreferencesUtils.USER_INFO_FILE_KEY, Context.MODE_PRIVATE).edit(); SharedPreferences.Editor editor = mUserInfoSharedPreferences.edit();
editor.putString(SharedPreferencesUtils.USER_KEY, name); editor.putString(SharedPreferencesUtils.USER_KEY, name);
editor.putString(SharedPreferencesUtils.PROFILE_IMAGE_URL_KEY, profileImageUrl); editor.putString(SharedPreferencesUtils.PROFILE_IMAGE_URL_KEY, profileImageUrl);
editor.putString(SharedPreferencesUtils.BANNER_IMAGE_URL_KEY, bannerImageUrl); editor.putString(SharedPreferencesUtils.BANNER_IMAGE_URL_KEY, bannerImageUrl);
@ -232,11 +215,11 @@ public class MainActivity extends AppCompatActivity {
public void onFetchUserInfoFail() { public void onFetchUserInfoFail() {
mFetchUserInfoSuccess = false; mFetchUserInfoSuccess = false;
} }
}, 1); });
} }
if (!mInsertSuccess) { if (!mInsertSuccess) {
FetchSubscribedThing.fetchSubscribedThing(this, mOauthRetrofit, null, FetchSubscribedThing.fetchSubscribedThing(mOauthRetrofit, mAuthInfoSharedPreferences, null,
new ArrayList<SubscribedSubredditData>(), new ArrayList<SubscribedUserData>(), new ArrayList<SubscribedSubredditData>(), new ArrayList<SubscribedUserData>(),
new ArrayList<SubredditData>(), new ArrayList<SubredditData>(),
new FetchSubscribedThing.FetchSubscribedThingListener() { new FetchSubscribedThing.FetchSubscribedThingListener() {
@ -263,7 +246,7 @@ public class MainActivity extends AppCompatActivity {
public void onFetchSubscribedThingFail() { public void onFetchSubscribedThingFail() {
mInsertSuccess = false; mInsertSuccess = false;
} }
}, 1); });
} }
} }
} }

View File

@ -1,5 +1,9 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -11,11 +15,18 @@ import retrofit2.converter.scalars.ScalarsConverterFactory;
@Module @Module
class NetworkModule { class NetworkModule {
Application mApplication;
public NetworkModule(Application application) {
mApplication = application;
}
@Provides @Named("oauth") @Provides @Named("oauth")
@Singleton @Singleton
Retrofit provideOauthRetrofit() { Retrofit provideOauthRetrofit(OkHttpClient okHttpClient) {
return new Retrofit.Builder() return new Retrofit.Builder()
.baseUrl(RedditUtils.OAUTH_API_BASE_URI) .baseUrl(RedditUtils.OAUTH_API_BASE_URI)
.client(okHttpClient)
.addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create())
.build(); .build();
} }
@ -31,9 +42,20 @@ class NetworkModule {
@Provides @Provides
@Singleton @Singleton
OkHttpClient provideOkHttpClient() { OkHttpClient provideOkHttpClient(@Named("auth_info") SharedPreferences sharedPreferences) {
OkHttpClient okHttpClient = new OkHttpClient(); OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClient.interceptors().add(new OkHttpInterceptor()); okHttpClientBuilder.authenticator(new AccessTokenAuthenticator(sharedPreferences));
return okHttpClient; return okHttpClientBuilder.build();
}
@Provides @Named("auth_info")
@Singleton
SharedPreferences provideAuthInfoSharedPreferences() {
return mApplication.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE);
}
@Provides @Named("user_info")
SharedPreferences provideUserInfoSharedPreferences() {
return mApplication.getSharedPreferences(SharedPreferencesUtils.USER_INFO_FILE_KEY, Context.MODE_PRIVATE);
} }
} }

View File

@ -1,48 +0,0 @@
package ml.docilealligator.infinityforreddit;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Response;
class OkHttpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
/*Request request = chain.request();
//Build new request
Request.Builder builder = request.newBuilder();
builder.header("Accept", "application/json"); //if necessary, say to consume JSON
String token = settings.getAccessToken(); //save token of this request for future
setAuthHeader(builder, token); //write current token to request
request = builder.build(); //overwrite old request
Response response = chain.proceed(request); //perform request, here original request will be executed
if (response.code() == 401) { //if unauthorized
synchronized (this) { //perform all 401 in sync blocks, to avoid multiply token updates
String currentToken = settings.getAccessToken(); //get currently stored token
if(currentToken != null && currentToken.equals(token)) { //compare current token with token that was stored before, if it was not updated - do update
int code = refreshToken() / 100; //refresh token
if(code != 2) { //if refresh token failed for some reason
if(code == 4) //only if response is 400, 500 might mean that token was not updated
logout(); //go to login screen
return response; //if token refresh failed - show error to user
}
}
if(settings.getAccessToken() != null) { //retry requires new auth token,
setAuthHeader(builder, settings.getAccessToken()); //set auth token to updated
request = builder.build();
return chain.proceed(request); //repeat request with new token
}
}
}
return response;*/
return null;
}
}

View File

@ -4,6 +4,7 @@ package ml.docilealligator.infinityforreddit;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.CoordinatorLayout;
@ -58,15 +59,15 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
private boolean mIsBestPost; private boolean mIsBestPost;
private String mSubredditName; private String mSubredditName;
@Inject @Inject @Named("no_oauth")
@Named("no_oauth")
Retrofit mRetrofit; Retrofit mRetrofit;
@Inject @Inject @Named("oauth")
@Named("oauth")
Retrofit mOauthRetrofit; Retrofit mOauthRetrofit;
@Inject @Inject @Named("auth_info")
SharedPreferences mSharedPreferences;
public PostFragment() { public PostFragment() {
// Required empty public constructor // Required empty public constructor
} }
@ -122,7 +123,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if(mIsBestPost) { if(mIsBestPost) {
fetchBestPost(1); fetchBestPost();
} else { } else {
fetchPost(); fetchPost();
} }
@ -142,7 +143,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
mPaginationSynchronizer.setLoadSuccess(savedInstanceState.getBoolean(LOAD_SUCCESS_STATE)); mPaginationSynchronizer.setLoadSuccess(savedInstanceState.getBoolean(LOAD_SUCCESS_STATE));
mPaginationSynchronizer.setLoadingState(savedInstanceState.getBoolean(LOADING_STATE_STATE)); mPaginationSynchronizer.setLoadingState(savedInstanceState.getBoolean(LOADING_STATE_STATE));
PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit,
mPostData, mPaginationSynchronizer, mIsBestPost); mSharedPreferences, mPostData, mPaginationSynchronizer, mIsBestPost);
mPostRecyclerView.setAdapter(adapter); mPostRecyclerView.setAdapter(adapter);
if(mIsBestPost) { if(mIsBestPost) {
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
@ -167,7 +168,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
} }
}); });
if(mIsBestPost) { if(mIsBestPost) {
fetchBestPost(1); fetchBestPost();
} else { } else {
fetchPost(); fetchPost();
} }
@ -176,12 +177,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
return rootView; return rootView;
} }
private void fetchBestPost(final int refreshTime) { private void fetchBestPost() {
if(refreshTime < 0) {
showErrorView();
return;
}
Log.i("fetch best post", "start" + refreshTime);
mFetchPostErrorLinearLayout.setVisibility(View.GONE); mFetchPostErrorLinearLayout.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
@ -212,7 +208,9 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
if(isAdded() && getActivity() != null) { if(isAdded() && getActivity() != null) {
mPostData = postData; mPostData = postData;
mLastItem = lastItem; mLastItem = lastItem;
PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, postData, mPaginationSynchronizer, mIsBestPost); PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(
getActivity(), mOauthRetrofit, mSharedPreferences,
postData, mPaginationSynchronizer, mIsBestPost);
mPostRecyclerView.setAdapter(adapter); mPostRecyclerView.setAdapter(adapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
@ -230,19 +228,6 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
showErrorView(); showErrorView();
} }
}); });
} else if(response.code() == 401) {
// Error indicating that there was an Authentication Failure while performing the request
// Access token expired
RefreshAccessToken.refreshAccessToken(getActivity(),
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
fetchBestPost(refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {}
});
} else { } else {
Log.i("Post fetch error", response.message()); Log.i("Post fetch error", response.message());
showErrorView(); showErrorView();
@ -284,7 +269,9 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
if(isAdded() && getActivity() != null) { if(isAdded() && getActivity() != null) {
mPostData = postData; mPostData = postData;
mLastItem = lastItem; mLastItem = lastItem;
PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mRetrofit, postData, mPaginationSynchronizer, mIsBestPost); PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(
getActivity(), mRetrofit, mSharedPreferences,
postData, mPaginationSynchronizer, mIsBestPost);
mPostRecyclerView.setAdapter(adapter); mPostRecyclerView.setAdapter(adapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
@ -329,7 +316,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (mIsBestPost) { if (mIsBestPost) {
fetchBestPost(1); fetchBestPost();
} else { } else {
fetchPost(); fetchPost();
} }
@ -358,7 +345,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
(mPostRecyclerView.getAdapter()).notifyDataSetChanged(); (mPostRecyclerView.getAdapter()).notifyDataSetChanged();
} }
if(mIsBestPost) { if(mIsBestPost) {
fetchBestPost(1); fetchBestPost();
} else { } else {
fetchPost(); fetchPost();
} }

View File

@ -57,7 +57,7 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
@Override @Override
public void retry() { public void retry() {
if (isBestPost) { if (isBestPost) {
fetchBestPost(1); fetchBestPost();
} else { } else {
fetchPost(subredditName, 1); fetchPost(subredditName, 1);
} }
@ -78,7 +78,7 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
if((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { if((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) {
if(isBestPost) { if(isBestPost) {
fetchBestPost(1); fetchBestPost();
} else { } else {
fetchPost(mSubredditName, 1); fetchPost(mSubredditName, 1);
} }
@ -87,12 +87,7 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
} }
private void fetchBestPost(final int refreshTime) { private void fetchBestPost() {
if(refreshTime < 0) {
loadFailed();
return;
}
Log.i("fetch best post pag", "start");
isLoading = true; isLoading = true;
loadSuccess = false; loadSuccess = false;
mPaginationSynchronizer.setLoadingState(true); mPaginationSynchronizer.setLoadingState(true);
@ -136,19 +131,6 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
loadFailed(); loadFailed();
} }
}); });
} else if(response.code() == 401) {
//Access token expired
RefreshAccessToken.refreshAccessToken(mContext,
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
fetchBestPost(refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {
}
});
} else { } else {
Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show();
Log.i("best post", response.message()); Log.i("best post", response.message());

View File

@ -2,6 +2,7 @@ package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
@ -46,6 +47,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
private ArrayList<PostData> mPostData; private ArrayList<PostData> mPostData;
private Context mContext; private Context mContext;
private Retrofit mOauthRetrofit; private Retrofit mOauthRetrofit;
private SharedPreferences mSharedPreferences;
private PaginationSynchronizer mPaginationSynchronizer; private PaginationSynchronizer mPaginationSynchronizer;
private RequestManager glide; private RequestManager glide;
private SubredditDao subredditDao; private SubredditDao subredditDao;
@ -57,10 +59,11 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
private static final int VIEW_TYPE_LOADING = 1; private static final int VIEW_TYPE_LOADING = 1;
PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, ArrayList<PostData> postData, PaginationSynchronizer paginationSynchronizer, boolean hasMultipleSubreddits) { PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences, ArrayList<PostData> postData, PaginationSynchronizer paginationSynchronizer, boolean hasMultipleSubreddits) {
if(context != null) { if(context != null) {
mContext = context; mContext = context;
mOauthRetrofit = oauthRetrofit; mOauthRetrofit = oauthRetrofit;
mSharedPreferences = sharedPreferences;
mPostData = postData; mPostData = postData;
mPaginationSynchronizer = paginationSynchronizer; mPaginationSynchronizer = paginationSynchronizer;
this.hasMultipleSubreddits = hasMultipleSubreddits; this.hasMultipleSubreddits = hasMultipleSubreddits;
@ -91,17 +94,16 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
if(mPostData.get(holder.getAdapterPosition()) == null) { if(mPostData.get(holder.getAdapterPosition()) == null) {
Log.i("is null", Integer.toString(holder.getAdapterPosition())); Log.i("is null", Integer.toString(holder.getAdapterPosition()));
} else { } else {
final int adapterPosition = holder.getAdapterPosition(); final String id = mPostData.get(holder.getAdapterPosition()).getFullName();
final String id = mPostData.get(adapterPosition).getFullName(); final String subredditName = mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed();
final String subredditName = mPostData.get(adapterPosition).getSubredditNamePrefixed(); final String postTime = mPostData.get(holder.getAdapterPosition()).getPostTime();
final String postTime = mPostData.get(adapterPosition).getPostTime(); final String title = mPostData.get(holder.getAdapterPosition()).getTitle();
final String title = mPostData.get(adapterPosition).getTitle(); final String permalink = mPostData.get(holder.getAdapterPosition()).getPermalink();
final String permalink = mPostData.get(adapterPosition).getPermalink(); int voteType = mPostData.get(holder.getAdapterPosition()).getVoteType();
int voteType = mPostData.get(adapterPosition).getVoteType(); int gilded = mPostData.get(holder.getAdapterPosition()).getGilded();
int gilded = mPostData.get(adapterPosition).getGilded(); boolean nsfw = mPostData.get(holder.getAdapterPosition()).isNSFW();
boolean nsfw = mPostData.get(adapterPosition).isNSFW();
if(mPostData.get(adapterPosition).getSubredditIconUrl() == null) { if(mPostData.get(holder.getAdapterPosition()).getSubredditIconUrl() == null) {
new LoadSubredditIconAsyncTask(subredditDao, subredditName, new LoadSubredditIconAsyncTask(subredditDao, subredditName,
new LoadSubredditIconAsyncTask.LoadSubredditIconAsyncTaskListener() { new LoadSubredditIconAsyncTask.LoadSubredditIconAsyncTaskListener() {
@Override @Override
@ -115,7 +117,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
.into(((DataViewHolder) holder).subredditIconCircleImageView); .into(((DataViewHolder) holder).subredditIconCircleImageView);
} }
mPostData.get(adapterPosition).setSubredditIconUrl(iconImageUrl); mPostData.get(holder.getAdapterPosition()).setSubredditIconUrl(iconImageUrl);
} }
} }
}).execute(); }).execute();
@ -132,7 +134,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
canStartActivity = false; canStartActivity = false;
Intent intent = new Intent(mContext, ViewPostDetailActivity.class); Intent intent = new Intent(mContext, ViewPostDetailActivity.class);
intent.putExtra(ViewPostDetailActivity.EXTRA_TITLE, title); intent.putExtra(ViewPostDetailActivity.EXTRA_TITLE, title);
intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, mPostData.get(adapterPosition)); intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, mPostData.get(holder.getAdapterPosition()));
mContext.startActivity(intent); mContext.startActivity(intent);
} }
} }
@ -145,9 +147,9 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
canStartActivity = false; canStartActivity = false;
Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY,
mPostData.get(adapterPosition).getSubredditNamePrefixed().substring(2)); mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed().substring(2));
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY, intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY,
mPostData.get(adapterPosition).getSubredditNamePrefixed()); mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed());
intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, false); intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, false);
mContext.startActivity(intent); mContext.startActivity(intent);
} }
@ -163,9 +165,9 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
canStartActivity = false; canStartActivity = false;
Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY,
mPostData.get(adapterPosition).getSubredditNamePrefixed().substring(2)); mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed().substring(2));
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY, intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY,
mPostData.get(adapterPosition).getSubredditNamePrefixed()); mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed());
intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, false); intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, false);
mContext.startActivity(intent); mContext.startActivity(intent);
} }
@ -256,10 +258,10 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
Intent intent = new Intent(mContext, ViewVideoActivity.class); Intent intent = new Intent(mContext, ViewVideoActivity.class);
intent.setData(gifVideoUri); intent.setData(gifVideoUri);
intent.putExtra(ViewVideoActivity.TITLE_KEY, title); intent.putExtra(ViewVideoActivity.TITLE_KEY, title);
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPostData.get(adapterPosition).isDashVideo()); intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPostData.get(holder.getAdapterPosition()).isDashVideo());
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPostData.get(adapterPosition).isDownloadableGifOrVideo()); intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo());
if(mPostData.get(adapterPosition).isDownloadableGifOrVideo()) { if(mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPostData.get(adapterPosition).getGifOrVideoDownloadUrl()); intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPostData.get(holder.getAdapterPosition()).getGifOrVideoDownloadUrl());
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName); intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName);
intent.putExtra(ViewVideoActivity.ID_KEY, id); intent.putExtra(ViewVideoActivity.ID_KEY, id);
} }
@ -277,10 +279,10 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
Intent intent = new Intent(mContext, ViewVideoActivity.class); Intent intent = new Intent(mContext, ViewVideoActivity.class);
intent.setData(videoUri); intent.setData(videoUri);
intent.putExtra(ViewVideoActivity.TITLE_KEY, title); intent.putExtra(ViewVideoActivity.TITLE_KEY, title);
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPostData.get(adapterPosition).isDashVideo()); intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPostData.get(holder.getAdapterPosition()).isDashVideo());
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPostData.get(adapterPosition).isDownloadableGifOrVideo()); intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo());
if(mPostData.get(adapterPosition).isDownloadableGifOrVideo()) { if(mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPostData.get(adapterPosition).getGifOrVideoDownloadUrl()); intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPostData.get(holder.getAdapterPosition()).getGifOrVideoDownloadUrl());
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName); intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName);
intent.putExtra(ViewVideoActivity.ID_KEY, id); intent.putExtra(ViewVideoActivity.ID_KEY, id);
} }
@ -319,12 +321,12 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
if (((DataViewHolder) holder).upvoteButton.getColorFilter() == null) { if (((DataViewHolder) holder).upvoteButton.getColorFilter() == null) {
((DataViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); ((DataViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
if(isDownvotedBefore) { if(isDownvotedBefore) {
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(adapterPosition).getScore() + 2)); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() + 2));
} else { } else {
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(adapterPosition).getScore() + 1)); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() + 1));
} }
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
mPostData.get(position).setVoteType(1); mPostData.get(position).setVoteType(1);
@ -342,13 +344,13 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore()));
((DataViewHolder) holder).downvoteButton.setColorFilter(downvoteButtonColorFilter); ((DataViewHolder) holder).downvoteButton.setColorFilter(downvoteButtonColorFilter);
} }
}, id, RedditUtils.DIR_UPVOTE, holder.getAdapterPosition(), 1); }, id, RedditUtils.DIR_UPVOTE, holder.getAdapterPosition());
} else { } else {
//Upvoted before //Upvoted before
((DataViewHolder) holder).upvoteButton.clearColorFilter(); ((DataViewHolder) holder).upvoteButton.clearColorFilter();
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(adapterPosition).getScore() - 1)); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() - 1));
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
mPostData.get(position).setVoteType(0); mPostData.get(position).setVoteType(0);
@ -362,7 +364,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
((DataViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); ((DataViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
mPostData.get(position).setScore(mPostData.get(position).getScore() + 1); mPostData.get(position).setScore(mPostData.get(position).getScore() + 1);
} }
}, id, RedditUtils.DIR_UNVOTE, holder.getAdapterPosition(), 1); }, id, RedditUtils.DIR_UNVOTE, holder.getAdapterPosition());
} }
} }
}); });
@ -377,12 +379,12 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
if (((DataViewHolder) holder).downvoteButton.getColorFilter() == null) { if (((DataViewHolder) holder).downvoteButton.getColorFilter() == null) {
((DataViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); ((DataViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN);
if (isUpvotedBefore) { if (isUpvotedBefore) {
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(adapterPosition).getScore() - 2)); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() - 2));
} else { } else {
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(adapterPosition).getScore() - 1)); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() - 1));
} }
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
mPostData.get(position).setVoteType(-1); mPostData.get(position).setVoteType(-1);
@ -400,13 +402,13 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore()));
((DataViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter); ((DataViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter);
} }
}, id, RedditUtils.DIR_DOWNVOTE, adapterPosition, 1); }, id, RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition());
} else { } else {
//Down voted before //Down voted before
((DataViewHolder) holder).downvoteButton.clearColorFilter(); ((DataViewHolder) holder).downvoteButton.clearColorFilter();
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(adapterPosition).getScore() + 1)); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() + 1));
VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
mPostData.get(position).setVoteType(0); mPostData.get(position).setVoteType(0);
@ -420,7 +422,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore()));
mPostData.get(position).setScore(mPostData.get(position).getScore()); mPostData.get(position).setScore(mPostData.get(position).getScore());
} }
}, id, RedditUtils.DIR_UNVOTE, adapterPosition, 1); }, id, RedditUtils.DIR_UNVOTE, holder.getAdapterPosition());
} }
} }
}); });

View File

@ -27,7 +27,6 @@ class RedditUtils {
static final String SCOPE_KEY = "scope"; static final String SCOPE_KEY = "scope";
static final String SCOPE = "identity edit flair history modconfig modflair modlog modposts modwiki mysubreddits privatemessages read report save submit subscribe vote wikiedit wikiread"; static final String SCOPE = "identity edit flair history modconfig modflair modlog modposts modwiki mysubreddits privatemessages read report save submit subscribe vote wikiedit wikiread";
static final String ACCESS_TOKEN_KEY = "access_token"; static final String ACCESS_TOKEN_KEY = "access_token";
static final String EXPIRES_IN_KEY = "expires_in";
static final String AUTHORIZATION_KEY = "Authorization"; static final String AUTHORIZATION_KEY = "Authorization";
static final String AUTHORIZATION_BASE = "bearer "; static final String AUTHORIZATION_BASE = "bearer ";

View File

@ -1,19 +1,17 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Calendar; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Response;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory;
@ -22,17 +20,10 @@ import retrofit2.converter.scalars.ScalarsConverterFactory;
*/ */
class RefreshAccessToken { class RefreshAccessToken {
static String refreshAccessToken(/*Retrofit oauthRetrofit, */SharedPreferences sharedPreferences) {
String refreshToken = sharedPreferences.getString(SharedPreferencesUtils.REFRESH_TOKEN_KEY, "");
interface RefreshAccessTokenListener { Retrofit retrofit = new Retrofit.Builder()
void onRefreshAccessTokenSuccess();
void onRefreshAccessTokenFail();
}
static void refreshAccessToken(final Context context, final RefreshAccessTokenListener refreshAccessTokenListener) {
if(context != null) {
String refreshToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE).getString(SharedPreferencesUtils.REFRESH_TOKEN_KEY, "");
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RedditUtils.API_BASE_URI) .baseUrl(RedditUtils.API_BASE_URI)
.addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create())
.build(); .build();
@ -44,38 +35,20 @@ class RefreshAccessToken {
params.put(RedditUtils.REFRESH_TOKEN_KEY, refreshToken); params.put(RedditUtils.REFRESH_TOKEN_KEY, refreshToken);
Call<String> accessTokenCall = api.getAccessToken(RedditUtils.getHttpBasicAuthHeader(), params); Call<String> accessTokenCall = api.getAccessToken(RedditUtils.getHttpBasicAuthHeader(), params);
accessTokenCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
try { try {
JSONObject jsonObject = new JSONObject(response.body()); Response response = accessTokenCall.execute();
JSONObject jsonObject = new JSONObject((String) response.body());
String newAccessToken = jsonObject.getString(RedditUtils.ACCESS_TOKEN_KEY); String newAccessToken = jsonObject.getString(RedditUtils.ACCESS_TOKEN_KEY);
int expireIn = jsonObject.getInt(RedditUtils.EXPIRES_IN_KEY);
long queryAccessTokenTime = Calendar.getInstance().getTimeInMillis(); sharedPreferences.edit().putString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, newAccessToken).apply();
SharedPreferences.Editor editor = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE).edit();
editor.putString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, newAccessToken);
editor.putInt(SharedPreferencesUtils.ACCESS_TOKEN_EXPIRE_INTERVAL_KEY, expireIn);
editor.putLong(SharedPreferencesUtils.QUERY_ACCESS_TOKEN_TIME_KEY, queryAccessTokenTime);
editor.apply();
Log.i("access token", newAccessToken); Log.i("access token", newAccessToken);
refreshAccessTokenListener.onRefreshAccessTokenSuccess(); return newAccessToken;
} catch (JSONException e) { } catch (IOException | JSONException e) {
e.printStackTrace(); e.printStackTrace();
refreshAccessTokenListener.onRefreshAccessTokenFail();
Log.i("main activity", "Error parsing JSON object when getting the access token");
}
refreshAccessTokenListener.onRefreshAccessTokenSuccess();
} }
@Override return "";
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Log.i("call failed", t.getMessage());
refreshAccessTokenListener.onRefreshAccessTokenFail();
}
});
}
} }
} }

View File

@ -1,6 +1,7 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
@ -69,14 +70,15 @@ public class ViewPostDetailActivity extends AppCompatActivity {
private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask; private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask;
@Inject @Inject @Named("no_oauth")
@Named("no_oauth")
Retrofit mRetrofit; Retrofit mRetrofit;
@Inject @Inject @Named("oauth")
@Named("oauth")
Retrofit mOauthRetrofit; Retrofit mOauthRetrofit;
@Inject @Named("auth_info")
SharedPreferences mSharedPreferences;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -380,7 +382,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); scoreTextView.setText(Integer.toString(mPostData.getScore() + 1));
} }
VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override @Override
public void onVoteThingSuccess() { public void onVoteThingSuccess() {
mPostData.setVoteType(1); mPostData.setVoteType(1);
@ -398,13 +400,13 @@ public class ViewPostDetailActivity extends AppCompatActivity {
scoreTextView.setText(Integer.toString(mPostData.getScore())); scoreTextView.setText(Integer.toString(mPostData.getScore()));
downvoteButton.setColorFilter(downVoteButtonColorFilter); downvoteButton.setColorFilter(downVoteButtonColorFilter);
} }
}, mPostData.getFullName(), RedditUtils.DIR_UPVOTE, 1); }, mPostData.getFullName(), RedditUtils.DIR_UPVOTE);
} else { } else {
//Upvoted before //Upvoted before
upvoteButton.clearColorFilter(); upvoteButton.clearColorFilter();
scoreTextView.setText(Integer.toString(mPostData.getScore() - 1)); scoreTextView.setText(Integer.toString(mPostData.getScore() - 1));
VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override @Override
public void onVoteThingSuccess() { public void onVoteThingSuccess() {
mPostData.setVoteType(0); mPostData.setVoteType(0);
@ -418,7 +420,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
upvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); upvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
mPostData.setScore(mPostData.getScore() + 1); mPostData.setScore(mPostData.getScore() + 1);
} }
}, mPostData.getFullName(), RedditUtils.DIR_UNVOTE, 1); }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE);
} }
} }
}); });
@ -440,7 +442,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
scoreTextView.setText(Integer.toString(mPostData.getScore() - 1)); scoreTextView.setText(Integer.toString(mPostData.getScore() - 1));
} }
VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override @Override
public void onVoteThingSuccess() { public void onVoteThingSuccess() {
mPostData.setVoteType(-1); mPostData.setVoteType(-1);
@ -458,13 +460,13 @@ public class ViewPostDetailActivity extends AppCompatActivity {
scoreTextView.setText(Integer.toString(mPostData.getScore())); scoreTextView.setText(Integer.toString(mPostData.getScore()));
upvoteButton.setColorFilter(upvoteButtonColorFilter); upvoteButton.setColorFilter(upvoteButtonColorFilter);
} }
}, mPostData.getFullName(), RedditUtils.DIR_DOWNVOTE, 1); }, mPostData.getFullName(), RedditUtils.DIR_DOWNVOTE);
} else { } else {
//Down voted before //Down voted before
downvoteButton.clearColorFilter(); downvoteButton.clearColorFilter();
scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); scoreTextView.setText(Integer.toString(mPostData.getScore() + 1));
VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override @Override
public void onVoteThingSuccess() { public void onVoteThingSuccess() {
mPostData.setVoteType(0); mPostData.setVoteType(0);
@ -478,7 +480,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
scoreTextView.setText(Integer.toString(mPostData.getScore())); scoreTextView.setText(Integer.toString(mPostData.getScore()));
mPostData.setScore(mPostData.getScore()); mPostData.setScore(mPostData.getScore());
} }
}, mPostData.getFullName(), RedditUtils.DIR_UNVOTE, 1); }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE);
} }
} }
}); });
@ -501,7 +503,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
if (commentData.size() > 0) { if (commentData.size() > 0) {
CommentMultiLevelRecyclerViewAdapter adapter = new CommentMultiLevelRecyclerViewAdapter( CommentMultiLevelRecyclerViewAdapter adapter = new CommentMultiLevelRecyclerViewAdapter(
ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit, ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit,
(ArrayList<CommentData>) commentData, mSharedPreferences, (ArrayList<CommentData>) commentData,
mRecyclerView, mPostData.getSubredditNamePrefixed(), mRecyclerView, mPostData.getSubredditNamePrefixed(),
mPostData.getId(), getResources().getConfiguration().locale); mPostData.getId(), getResources().getConfiguration().locale);
mRecyclerView.removeItemClickListeners(); mRecyclerView.removeItemClickListeners();

View File

@ -1,6 +1,6 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.SharedPreferences;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
@ -27,19 +27,12 @@ class VoteThing {
void onVoteThingFail(); void onVoteThingFail();
} }
static void voteThing(final Context context, final Retrofit retrofit, static void voteThing(final Retrofit retrofit, SharedPreferences authInfoSharedPreferences,
final VoteThingListener voteThingListener, final String fullName, final VoteThingListener voteThingListener, final String fullName,
final String point, final int position, final int refreshTime) { final String point, final int position) {
if(context != null) {
if(refreshTime < 0) {
voteThingListener.onVoteThingFail(position);
return;
}
RedditAPI api = retrofit.create(RedditAPI.class); RedditAPI api = retrofit.create(RedditAPI.class);
String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put(RedditUtils.DIR_KEY, point); params.put(RedditUtils.DIR_KEY, point);
params.put(RedditUtils.ID_KEY, fullName); params.put(RedditUtils.ID_KEY, fullName);
@ -55,35 +48,17 @@ class VoteThing {
@Override @Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Log.i("call failed", t.getMessage()); Log.i("call failed", t.getMessage());
RefreshAccessToken.refreshAccessToken(context, voteThingListener.onVoteThingFail(position);
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
voteThing(context, retrofit, voteThingListener, fullName, point, position, refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {
} }
}); });
} }
});
}
}
static void voteThing(final Context context, final Retrofit retrofit, static void voteThing(final Retrofit retrofit, SharedPreferences authInfoSharedPreferences,
final VoteThingWithoutPositionListener voteThingWithoutPositionListener, final VoteThingWithoutPositionListener voteThingWithoutPositionListener,
final String fullName, final String point, final int refreshTime) { final String fullName, final String point) {
if(context != null) {
if(refreshTime < 0) {
voteThingWithoutPositionListener.onVoteThingFail();
return;
}
RedditAPI api = retrofit.create(RedditAPI.class); RedditAPI api = retrofit.create(RedditAPI.class);
String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put(RedditUtils.DIR_KEY, point); params.put(RedditUtils.DIR_KEY, point);
params.put(RedditUtils.ID_KEY, fullName); params.put(RedditUtils.ID_KEY, fullName);
@ -99,18 +74,8 @@ class VoteThing {
@Override @Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Log.i("call failed", t.getMessage()); Log.i("call failed", t.getMessage());
RefreshAccessToken.refreshAccessToken(context, voteThingWithoutPositionListener.onVoteThingFail();
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
voteThing(context, retrofit, voteThingWithoutPositionListener, fullName, point, refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {}
});
} }
}); });
} }
} }
}