aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Ning <chineseperson5@gmail.com>2019-08-07 02:54:47 +0000
committerAlex Ning <chineseperson5@gmail.com>2019-08-07 02:54:47 +0000
commit7f2bc01180c284154fb69976122016c4638e9973 (patch)
treeb009b9cfab924cce98c25ae5b6355af4f18c311c
parent77d83654aa8063b0c4d9f95ba91bd3d77be84ad9 (diff)
downloadinfinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.tar
infinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.tar.gz
infinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.tar.bz2
infinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.tar.lz
infinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.tar.xz
infinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.tar.zst
infinity-for-reddit-7f2bc01180c284154fb69976122016c4638e9973.zip
Preparing to support multi user. Use the database to store accounts' info. LoginActivity is successfully refactored. Any other features are unavailable for now.
-rw-r--r--.idea/inspectionProfiles/Project_Default.xml15
-rw-r--r--app/src/main/java/Account/Account.java72
-rw-r--r--app/src/main/java/Account/AccountDao.java22
-rw-r--r--app/src/main/java/Account/AccountRepository.java40
-rw-r--r--app/src/main/java/Account/AccountRoomDatabase.java27
-rw-r--r--app/src/main/java/Account/AccountViewModel.java47
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/FetchMyInfo.java27
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/LoginActivity.java73
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/ParseAndInsertAccount.java50
-rw-r--r--app/src/main/res/values/strings.xml6
10 files changed, 358 insertions, 21 deletions
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000..9223ff2c
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,15 @@
+<component name="InspectionProjectProfileManager">
+ <profile version="1.0">
+ <option name="myName" value="Project Default" />
+ <inspection_tool class="FieldCanBeLocal" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="EXCLUDE_ANNOS">
+ <value>
+ <list size="1">
+ <item index="0" class="java.lang.String" itemvalue="androidx.room.ColumnInfo" />
+ </list>
+ </value>
+ </option>
+ <option name="IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS" value="true" />
+ </inspection_tool>
+ </profile>
+</component> \ No newline at end of file
diff --git a/app/src/main/java/Account/Account.java b/app/src/main/java/Account/Account.java
new file mode 100644
index 00000000..95873c61
--- /dev/null
+++ b/app/src/main/java/Account/Account.java
@@ -0,0 +1,72 @@
+package Account;
+
+import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "accounts")
+public class Account {
+ @PrimaryKey
+ @NonNull
+ @ColumnInfo(name = "username")
+ private String username;
+ @ColumnInfo(name = "profile_image_url")
+ private String profileImageUrl;
+ @ColumnInfo(name = "banner_image_url")
+ private String bannerImageUrl;
+ @ColumnInfo(name = "karma")
+ private int karma;
+ @ColumnInfo(name = "access_token")
+ private String accessToken;
+ @ColumnInfo(name = "refresh_token")
+ private String refreshToken;
+ @ColumnInfo(name = "code")
+ private String code;
+ @ColumnInfo(name = "is_current_user")
+ private boolean isCurrentUser;
+
+ public Account(@NonNull String username, String accessToken, String refreshToken, String code,
+ String profileImageUrl, String bannerImageUrl, int karma, boolean isCurrentUser) {
+ this.username = username;
+ this.accessToken = accessToken;
+ this.refreshToken = refreshToken;
+ this.code = code;
+ this.profileImageUrl = profileImageUrl;
+ this.bannerImageUrl = bannerImageUrl;
+ this.karma = karma;
+ this.isCurrentUser = isCurrentUser;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getProfileImageUrl() {
+ return profileImageUrl;
+ }
+
+ public String getBannerImageUrl() {
+ return bannerImageUrl;
+ }
+
+ public int getKarma() {
+ return karma;
+ }
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public boolean isCurrentUser() {
+ return isCurrentUser;
+ }
+}
diff --git a/app/src/main/java/Account/AccountDao.java b/app/src/main/java/Account/AccountDao.java
new file mode 100644
index 00000000..bd53b92b
--- /dev/null
+++ b/app/src/main/java/Account/AccountDao.java
@@ -0,0 +1,22 @@
+package Account;
+
+import androidx.lifecycle.LiveData;
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+
+@Dao
+public interface AccountDao {
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void insert(Account account);
+
+ @Query("DELETE FROM accounts")
+ void deleteAllAccounts();
+
+ @Query("SELECT * FROM accounts WHERE username = :userName COLLATE NOCASE LIMIT 1")
+ LiveData<Account> getAccountLiveData(String userName);
+
+ @Query("SELECT * FROM accounts WHERE username = :userName COLLATE NOCASE LIMIT 1")
+ Account getAccountData(String userName);
+}
diff --git a/app/src/main/java/Account/AccountRepository.java b/app/src/main/java/Account/AccountRepository.java
new file mode 100644
index 00000000..49bdfacf
--- /dev/null
+++ b/app/src/main/java/Account/AccountRepository.java
@@ -0,0 +1,40 @@
+package Account;
+
+import android.app.Application;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.LiveData;
+
+public class AccountRepository {
+ private AccountDao mAccountDao;
+ private LiveData<Account> mAccountLiveData;
+
+ AccountRepository(Application application, String username) {
+ mAccountDao = AccountRoomDatabase.getDatabase(application).accountDao();
+
+ mAccountLiveData = mAccountDao.getAccountLiveData(username);
+ }
+
+ LiveData<Account> getAccountLiveData() {
+ return mAccountLiveData;
+ }
+
+ public void insert(Account Account) {
+ new InsertAsyncTask(mAccountDao).execute(Account);
+ }
+
+ private static class InsertAsyncTask extends AsyncTask<Account, Void, Void> {
+
+ private AccountDao mAsyncTaskDao;
+
+ InsertAsyncTask(AccountDao dao) {
+ mAsyncTaskDao = dao;
+ }
+
+ @Override
+ protected Void doInBackground(final Account... params) {
+ mAsyncTaskDao.insert(params[0]);
+ return null;
+ }
+ }
+}
diff --git a/app/src/main/java/Account/AccountRoomDatabase.java b/app/src/main/java/Account/AccountRoomDatabase.java
new file mode 100644
index 00000000..2f5d0120
--- /dev/null
+++ b/app/src/main/java/Account/AccountRoomDatabase.java
@@ -0,0 +1,27 @@
+package Account;
+
+import android.content.Context;
+
+import androidx.room.Database;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+
+@Database(entities = {Account.class}, version = 1)
+public abstract class AccountRoomDatabase extends RoomDatabase {
+ private static AccountRoomDatabase INSTANCE;
+
+ public abstract AccountDao accountDao();
+
+ public static AccountRoomDatabase getDatabase(final Context context) {
+ if(INSTANCE == null) {
+ synchronized (AccountRoomDatabase.class) {
+ if(INSTANCE == null) {
+ INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
+ AccountRoomDatabase.class, "accounts")
+ .build();
+ }
+ }
+ }
+ return INSTANCE;
+ }
+}
diff --git a/app/src/main/java/Account/AccountViewModel.java b/app/src/main/java/Account/AccountViewModel.java
new file mode 100644
index 00000000..b649d9a7
--- /dev/null
+++ b/app/src/main/java/Account/AccountViewModel.java
@@ -0,0 +1,47 @@
+package Account;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+
+public class AccountViewModel extends AndroidViewModel {
+ private AccountRepository mAccountRepository;
+ private LiveData<Account> mAccountLiveData;
+
+ public AccountViewModel(Application application, String id) {
+ super(application);
+ mAccountRepository = new AccountRepository(application, id);
+ mAccountLiveData = mAccountRepository.getAccountLiveData();
+ }
+
+ public LiveData<Account> getAccountLiveData() {
+ return mAccountLiveData;
+ }
+
+ public void insert(Account userData) {
+ mAccountRepository.insert(userData);
+ }
+
+ public static class Factory extends ViewModelProvider.NewInstanceFactory {
+
+ @NonNull
+ private final Application mApplication;
+
+ private final String userName;
+
+ public Factory(@NonNull Application application, String userName) {
+ mApplication = application;
+ this.userName = userName;
+ }
+
+ @Override
+ public <T extends ViewModel> T create(Class<T> modelClass) {
+ //noinspection unchecked
+ return (T) new AccountViewModel(mApplication, userName);
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMyInfo.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMyInfo.java
index 393349a1..63b80532 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMyInfo.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMyInfo.java
@@ -1,9 +1,10 @@
package ml.docilealligator.infinityforreddit;
import android.content.SharedPreferences;
-import androidx.annotation.NonNull;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
@@ -39,4 +40,28 @@ class FetchMyInfo {
}
});
}
+
+ static void fetchMyInfo(final Retrofit retrofit, String accessToken,
+ final FetchUserMyListener fetchUserMyListener) {
+ RedditAPI api = retrofit.create(RedditAPI.class);
+
+ Call<String> userInfo = api.getMyInfo(RedditUtils.getOAuthHeader(accessToken));
+ userInfo.enqueue(new Callback<String>() {
+ @Override
+ public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
+ if(response.isSuccessful()) {
+ fetchUserMyListener.onFetchMyInfoSuccess(response.body());
+ } else {
+ Log.i("call failed", response.message());
+ fetchUserMyListener.onFetchMyInfoFail();
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
+ Log.i("call failed", t.getMessage());
+ fetchUserMyListener.onFetchMyInfoFail();
+ }
+ });
+ }
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/LoginActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/LoginActivity.java
index 53b0e143..20fa44fa 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/LoginActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/LoginActivity.java
@@ -12,6 +12,9 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -21,8 +24,7 @@ import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
+import Account.AccountRoomDatabase;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@@ -36,6 +38,10 @@ public class LoginActivity extends AppCompatActivity {
@Named("no_oauth")
Retrofit mRetrofit;
+ @Inject
+ @Named("oauth")
+ Retrofit mOauthRetrofit;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -85,41 +91,69 @@ public class LoginActivity extends AppCompatActivity {
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if(response.isSuccessful()) {
try {
- JSONObject responseJSON = new JSONObject(response.body());
+ String accountResponse = response.body();
+ if(accountResponse == null) {
+ //Handle error
+ return;
+ }
+
+ JSONObject responseJSON = new JSONObject(accountResponse);
String accessToken = responseJSON.getString(RedditUtils.ACCESS_TOKEN_KEY);
String refreshToken = responseJSON.getString(RedditUtils.REFRESH_TOKEN_KEY);
- editor.putString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, accessToken);
- editor.putString(SharedPreferencesUtils.REFRESH_TOKEN_KEY, refreshToken);
- editor.apply();
-
- Intent resultIntent = new Intent();
- setResult(Activity.RESULT_OK, resultIntent);
- finish();
+ FetchMyInfo.fetchMyInfo(mOauthRetrofit, accessToken, new FetchMyInfo.FetchUserMyListener() {
+ @Override
+ public void onFetchMyInfoSuccess(String response) {
+ ParseMyInfo.parseMyInfo(response, new ParseMyInfo.ParseMyInfoListener() {
+ @Override
+ public void onParseMyInfoSuccess(String name, String profileImageUrl, String bannerImageUrl, int karma) {
+ new ParseAndInsertAccount(name, accessToken, refreshToken, profileImageUrl, bannerImageUrl,
+ karma, authCode, AccountRoomDatabase.getDatabase(LoginActivity.this).accountDao(),
+ () -> {
+ Intent resultIntent = new Intent();
+ setResult(Activity.RESULT_OK, resultIntent);
+ finish();
+ }).execute();
+ }
+
+ @Override
+ public void onParseMyInfoFail() {
+ Toast.makeText(LoginActivity.this, R.string.parse_user_info_error, Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ });
+ }
+
+ @Override
+ public void onFetchMyInfoFail() {
+ Toast.makeText(LoginActivity.this, R.string.cannot_fetch_user_info, Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ });
} catch (JSONException e) {
e.printStackTrace();
- Toast.makeText(LoginActivity.this, "Error occurred when parsing the JSON response", Toast.LENGTH_SHORT).show();
+ Toast.makeText(LoginActivity.this, R.string.parse_json_response_error, Toast.LENGTH_SHORT).show();
finish();
}
} else {
- Toast.makeText(LoginActivity.this, "Error Retrieving the token", Toast.LENGTH_SHORT).show();
+ Toast.makeText(LoginActivity.this, R.string.retrieve_token_error, Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
- public void onFailure(Call<String> call, Throwable t) {
- Toast.makeText(LoginActivity.this, "Error Retrieving the token", Toast.LENGTH_SHORT).show();
+ public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
+ Toast.makeText(LoginActivity.this, R.string.retrieve_token_error, Toast.LENGTH_SHORT).show();
finish();
}
});
} else {
- Toast.makeText(LoginActivity.this, "Something went wrong. Try again later.", Toast.LENGTH_SHORT).show();
+ Toast.makeText(LoginActivity.this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show();
finish();
}
} else if (url.contains("error=access_denied")) {
- Toast.makeText(LoginActivity.this, "Access denied", Toast.LENGTH_SHORT).show();
+ Toast.makeText(LoginActivity.this, R.string.access_denied, Toast.LENGTH_SHORT).show();
finish();
} else {
view.loadUrl(url);
@@ -142,10 +176,9 @@ public class LoginActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
}
return false;
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseAndInsertAccount.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseAndInsertAccount.java
new file mode 100644
index 00000000..e86fbada
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseAndInsertAccount.java
@@ -0,0 +1,50 @@
+package ml.docilealligator.infinityforreddit;
+
+import android.os.AsyncTask;
+
+import Account.Account;
+import Account.AccountDao;
+
+class ParseAndInsertAccount extends AsyncTask<Void, Void, Void> {
+
+ interface ParseAndInsertAccountListener {
+ void success();
+ }
+
+ private String username;
+ private String accessToken;
+ private String refreshToken;
+ private String profileImageUrl;
+ private String bannerImageUrl;
+ private int karma;
+ private String code;
+ private AccountDao accountDao;
+ private ParseAndInsertAccountListener parseAndInsertAccountListener;
+
+ ParseAndInsertAccount(String username, String accessToken, String refreshToken, String profileImageUrl, String bannerImageUrl,
+ int karma, String code, AccountDao accountDao,
+ ParseAndInsertAccountListener parseAndInsertAccountListener) {
+ this.username = username;
+ this.accessToken = accessToken;
+ this.refreshToken = refreshToken;
+ this.profileImageUrl = profileImageUrl;
+ this.bannerImageUrl = bannerImageUrl;
+ this.karma = karma;
+ this.code = code;
+ this.accountDao = accountDao;
+ this.parseAndInsertAccountListener = parseAndInsertAccountListener;
+ }
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+ Account account = new Account(username, accessToken, refreshToken, code, profileImageUrl,
+ bannerImageUrl, karma, true);
+ accountDao.insert(account);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ parseAndInsertAccountListener.success();
+ }
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 93de5843..2801d12b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -25,6 +25,12 @@
<string name="action_send">Send</string>
<string name="action_sort">Sort</string>
+ <string name="parse_json_response_error">Error occurred when parsing the JSON response</string>
+ <string name="retrieve_token_error">Error Retrieving the token</string>
+ <string name="something_went_wrong">Something went wrong. Try again later.</string>
+ <string name="access_denied">Access denied</string>
+ <string name="parse_user_info_error">Error occurred when parsing the user info</string>
+
<string name="tap_to_retry">Error loading image. Tap to retry.</string>
<string name="load_posts_error">Error loading posts.\nTap to retry.</string>
<string name="search_subreddits_error">Error searching subreddits.\nTap to retry.</string>