package com.wangdaye.mysplash.common.utils.manager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.support.annotation.IntDef;
import android.support.design.widget.Snackbar;
import android.text.TextUtils;
import com.wangdaye.mysplash.Mysplash;
import com.wangdaye.mysplash.R;
import com.wangdaye.mysplash.common.data.entity.unsplash.AccessToken;
import com.wangdaye.mysplash.common.data.entity.unsplash.Me;
import com.wangdaye.mysplash.common.data.entity.unsplash.User;
import com.wangdaye.mysplash.common.data.service.UserService;
import com.wangdaye.mysplash.common.utils.helper.NotificationHelper;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Response;
/**
* Auth manager.
*
* A manager class to manage the authorization information.
*
* A process of authorize is as follow:
* 0. Get access token.
* 1. Request {@link Me} by a HTTP request.
* 2. Request {@link User} by a HTTP request.
*
* */
public class AuthManager
implements UserService.OnRequestMeProfileListener, UserService.OnRequestUserProfileListener {
private static AuthManager instance;
public static AuthManager getInstance() {
if (instance == null) {
synchronized (AuthManager.class) {
if (instance == null) {
instance = new AuthManager();
}
}
}
return instance;
}
private List<OnAuthDataChangedListener> listenerList;
private Me me;
private User user;
private UserService service;
private String access_token;
private String username;
private String first_name;
private String last_name;
private String email;
private String avatar_path;
private int numericId;
private boolean authorized;
private UserCollectionsManager collectionsManager; // cache of user's collections.
private UserNotificationManager notificationManager; // manage user's notification feeds.
private static final String PREFERENCE_MYSPLASH_AUTHORIZE_MANAGER = "mysplash_authorize_manager";
private static final String KEY_ACCESS_TOKEN = "access_token";
private static final String KEY_USERNAME = "username";
private static final String KEY_FIRST_NAME = "first_name";
private static final String KEY_LAST_NAME = "last_name";
private static final String KEY_EMAIL = "email";
private static final String KEY_AVATAR_PATH = "avatar_path";
private static final String KEY_NUMERIC_ID = "numeric_id";
@StateRule
private int state;
public static final int FREEDOM_STATE = 0;
public static final int LOADING_ME_STATE = 1;
public static final int LOADING_USER_STATE = 2;
@IntDef({FREEDOM_STATE, LOADING_ME_STATE, LOADING_USER_STATE})
private @interface StateRule {}
// if version code is increased, the user need to login again.
private static final String KEY_VERSION = "version";
private static final int VERSION_CODE = 8;
private AuthManager() {
SharedPreferences sharedPreferences = Mysplash.getInstance()
.getSharedPreferences(PREFERENCE_MYSPLASH_AUTHORIZE_MANAGER, Context.MODE_PRIVATE);
updateVersion(sharedPreferences);
this.listenerList = new ArrayList<>();
this.access_token = sharedPreferences.getString(KEY_ACCESS_TOKEN, null);
this.authorized = !TextUtils.isEmpty(access_token);
if (authorized) {
this.username = sharedPreferences.getString(KEY_USERNAME, null);
this.first_name = sharedPreferences.getString(KEY_FIRST_NAME, null);
this.last_name = sharedPreferences.getString(KEY_LAST_NAME, null);
this.email = sharedPreferences.getString(KEY_EMAIL, null);
this.avatar_path = sharedPreferences.getString(KEY_AVATAR_PATH, null);
this.numericId = sharedPreferences.getInt(KEY_NUMERIC_ID, -1);
}
this.collectionsManager = new UserCollectionsManager();
this.notificationManager = new UserNotificationManager();
this.me = null;
this.user = null;
this.service = UserService.getService();
this.state = FREEDOM_STATE;
}
private void updateVersion(SharedPreferences sharedPreferences) {
int versionNow = sharedPreferences.getInt(KEY_VERSION, 0);
String token = sharedPreferences.getString(KEY_ACCESS_TOKEN, null);
if ((versionNow < VERSION_CODE) && !TextUtils.isEmpty(token)) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(KEY_VERSION, VERSION_CODE);
editor.putString(KEY_ACCESS_TOKEN, null);
editor.putString(KEY_USERNAME, null);
editor.putString(KEY_FIRST_NAME, null);
editor.putString(KEY_LAST_NAME, null);
editor.putString(KEY_EMAIL, null);
editor.putString(KEY_AVATAR_PATH, null);
editor.apply();
NotificationHelper.showSnackbar(
Mysplash.getInstance().getString(R.string.feedback_please_login),
Snackbar.LENGTH_SHORT);
}
}
public void logout() {
service.cancel();
SharedPreferences.Editor editor = Mysplash.getInstance()
.getSharedPreferences(PREFERENCE_MYSPLASH_AUTHORIZE_MANAGER, Context.MODE_PRIVATE).edit();
editor.putString(KEY_ACCESS_TOKEN, null);
editor.putString(KEY_USERNAME, null);
editor.putString(KEY_FIRST_NAME, null);
editor.putString(KEY_LAST_NAME, null);
editor.putString(KEY_EMAIL, null);
editor.putString(KEY_AVATAR_PATH, null);
editor.apply();
this.access_token = null;
this.username = null;
this.first_name = null;
this.last_name = null;
this.email = null;
this.avatar_path = null;
this.authorized = false;
this.collectionsManager.clearCollections();
this.notificationManager.clearNotifications(true);
this.me = null;
this.user = null;
this.state = FREEDOM_STATE;
for (int i = 0; i < listenerList.size(); i ++) {
listenerList.get(i).onLogout();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
ShortcutsManager.refreshShortcuts(Mysplash.getInstance());
}
}
// HTTP request.
public void requestPersonalProfile() {
if (authorized) {
service.cancel();
state = LOADING_ME_STATE;
service.requestMeProfile(this);
}
}
public void requestPersonalNotifications() {
if (authorized && numericId >= 0) {
notificationManager.requestPersonalNotifications();
}
}
public void refreshPersonalNotifications() {
if (authorized && numericId >= 0) {
notificationManager.checkToRefreshNotification();
}
}
public void cancelRequest() {
service.cancel();
notificationManager.cancelRequest(true);
}
// getter.
public Me getMe() {
return me;
}
public User getUser() {
return user;
}
public String getAccessToken() {
return access_token;
}
public String getUsername() {
return username;
}
public String getFirstName() {
return first_name;
}
public String getLastName() {
return last_name;
}
public String getEmail() {
return email;
}
public String getAvatarPath() {
return avatar_path;
}
public int getNumericId() {
return numericId;
}
public boolean isAuthorized() {
return authorized;
}
public int getState() {
return state;
}
public UserCollectionsManager getCollectionsManager() {
return collectionsManager;
}
public UserNotificationManager getNotificationManager() {
return notificationManager;
}
// setter.
public void updateUser(User u) {
this.user = u;
}
public void writeAccessToken(AccessToken token) {
SharedPreferences.Editor editor = Mysplash.getInstance()
.getSharedPreferences(PREFERENCE_MYSPLASH_AUTHORIZE_MANAGER, Context.MODE_PRIVATE).edit();
editor.putString(KEY_ACCESS_TOKEN, token.access_token);
editor.apply();
access_token = token.access_token;
authorized = true;
for (int i = 0; i < listenerList.size(); i ++) {
listenerList.get(i).onWriteAccessToken();
}
}
public void writeUserInfo(Me me) {
SharedPreferences.Editor editor = Mysplash.getInstance()
.getSharedPreferences(PREFERENCE_MYSPLASH_AUTHORIZE_MANAGER, Context.MODE_PRIVATE).edit();
editor.putString(KEY_USERNAME, me.username);
editor.putString(KEY_FIRST_NAME, me.first_name);
editor.putString(KEY_LAST_NAME, me.last_name);
editor.putString(KEY_EMAIL, me.email);
editor.apply();
this.me = me;
username = me.username;
first_name = me.first_name;
last_name = me.last_name;
email = me.email;
for (int i = 0; i < listenerList.size(); i ++) {
listenerList.get(i).onWriteUserInfo();
}
}
public void writeUserInfo(User user) {
SharedPreferences.Editor editor = Mysplash.getInstance()
.getSharedPreferences(PREFERENCE_MYSPLASH_AUTHORIZE_MANAGER, Context.MODE_PRIVATE).edit();
editor.putString(KEY_USERNAME, user.username);
editor.putString(KEY_FIRST_NAME, user.first_name);
editor.putString(KEY_LAST_NAME, user.last_name);
editor.putString(KEY_AVATAR_PATH, user.profile_image.large);
editor.putInt(KEY_NUMERIC_ID, user.numeric_id);
editor.apply();
if (numericId < 0) {
numericId = user.numeric_id;
requestPersonalNotifications();
}
this.user = user;
avatar_path = user.profile_image.large;
numericId = user.numeric_id;
for (int i = 0; i < listenerList.size(); i ++) {
listenerList.get(i).onWriteAvatarPath();
}
}
// interface.
// on auth data changed swipeListener.
public interface OnAuthDataChangedListener {
void onWriteAccessToken();
void onWriteUserInfo();
void onWriteAvatarPath();
void onLogout();
}
public void addOnWriteDataListener(OnAuthDataChangedListener l) {
listenerList.add(l);
}
public void removeOnWriteDataListener(OnAuthDataChangedListener l) {
listenerList.remove(l);
}
// on request me profile swipeListener.
@Override
public void onRequestMeProfileSuccess(Call<Me> call, Response<Me> response) {
if (response.isSuccessful() && response.body() != null && isAuthorized()) {
state = LOADING_USER_STATE;
writeUserInfo(response.body());
service.requestUserProfile(response.body().username, this);
} else if (isAuthorized()) {
service.requestMeProfile(this);
}
}
@Override
public void onRequestMeProfileFailed(Call<Me> call, Throwable t) {
if (isAuthorized()) {
service.requestMeProfile(this);
}
}
// on request user profile swipeListener.
@Override
public void onRequestUserProfileSuccess(Call<User> call, Response<User> response) {
if (response.isSuccessful() && response.body() != null && isAuthorized()) {
state = FREEDOM_STATE;
writeUserInfo(response.body());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
ShortcutsManager.refreshShortcuts(Mysplash.getInstance());
}
} else if (isAuthorized()) {
service.requestUserProfile(me.username, this);
}
}
@Override
public void onRequestUserProfileFailed(Call<User> call, Throwable t) {
if (isAuthorized()) {
service.requestUserProfile(me.username, this);
}
}
}