Log in other reddit accounts are available. Add an account switcher in the navigation drawer in MainActivity.

This commit is contained in:
Alex Ning
2019-08-08 20:05:45 +08:00
parent 5b5da3d3fd
commit e542ac5138
21 changed files with 451 additions and 135 deletions

View File

@@ -34,4 +34,7 @@ public interface AccountDao {
@Query("UPDATE accounts SET profile_image_url = :profileImageUrl, banner_image_url = :bannerImageUrl, " +
"karma = :karma WHERE username = :username")
void updateAccountInfo(String username, String profileImageUrl, String bannerImageUrl, int karma);
@Query("SELECT * FROM accounts WHERE username != :username")
LiveData<List<Account>> getAccountsExceptCurrentAccountLiveData(String username);
}

View File

@@ -4,21 +4,29 @@ import android.os.AsyncTask;
import androidx.lifecycle.LiveData;
import java.util.List;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
public class AccountRepository {
private AccountDao mAccountDao;
private LiveData<Account> mAccountLiveData;
private LiveData<List<Account>> mAccountsExceptCurrentAccountLiveData;
AccountRepository(RedditDataRoomDatabase redditDataRoomDatabase, String username) {
mAccountDao = redditDataRoomDatabase.accountDao();
mAccountLiveData = mAccountDao.getAccountLiveData(username);
mAccountsExceptCurrentAccountLiveData = mAccountDao.getAccountsExceptCurrentAccountLiveData(username);
}
LiveData<Account> getAccountLiveData() {
return mAccountLiveData;
}
public LiveData<List<Account>> getAccountsExceptCurrentAccountLiveData() {
return mAccountsExceptCurrentAccountLiveData;
}
public void insert(Account Account) {
new InsertAsyncTask(mAccountDao).execute(Account);
}

View File

@@ -8,22 +8,30 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import java.util.List;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
public class AccountViewModel extends AndroidViewModel {
private AccountRepository mAccountRepository;
private LiveData<Account> mAccountLiveData;
private LiveData<List<Account>> mAccountsExceptCurrentAccountLiveData;
public AccountViewModel(Application application, RedditDataRoomDatabase redditDataRoomDatabase, String id) {
super(application);
mAccountRepository = new AccountRepository(redditDataRoomDatabase, id);
mAccountLiveData = mAccountRepository.getAccountLiveData();
mAccountsExceptCurrentAccountLiveData = mAccountRepository.getAccountsExceptCurrentAccountLiveData();
}
public LiveData<Account> getAccountLiveData() {
return mAccountLiveData;
}
public LiveData<List<Account>> getAccountsExceptCurrentAccountLiveData() {
return mAccountsExceptCurrentAccountLiveData;
}
public void insert(Account userData) {
mAccountRepository.insert(userData);
}

View File

@@ -0,0 +1,137 @@
package ml.docilealligator.infinityforreddit;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import java.util.List;
import Account.Account;
import butterknife.BindView;
import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
import pl.droidsonroids.gif.GifImageView;
class AccountRecyclerViewAdapter extends RecyclerView.Adapter<AccountRecyclerViewAdapter.AccountViewHolder> {
interface ItemSelectedListener {
void accountSelected(Account account);
void addAccountSelected();
void anonymousSelected();
void logoutSelected();
void manageAccountSelected();
}
private List<Account> mAccounts;
private String mCurrentAccountName;
private Context mContext;
private RequestManager mGlide;
private ItemSelectedListener mItemSelectedListener;
AccountRecyclerViewAdapter(Context context, RequestManager glide, String currentAccountName, ItemSelectedListener itemSelectedListener) {
mContext = context;
mGlide = glide;
mCurrentAccountName = currentAccountName;
mItemSelectedListener = itemSelectedListener;
}
@NonNull
@Override
public AccountViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new AccountViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_account, parent, false));
}
@Override
public void onBindViewHolder(@NonNull AccountViewHolder holder, int position) {
if(mAccounts == null) {
mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(holder.profileImageGifImageView);
holder.usernameTextView.setText(R.string.add_account);
holder.itemView.setOnClickListener(view -> mItemSelectedListener.addAccountSelected());
} else {
if(position < mAccounts.size()) {
mGlide.load(mAccounts.get(position).getProfileImageUrl())
.error(mGlide.load(R.drawable.subreddit_default_icon))
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(holder.profileImageGifImageView);
holder.usernameTextView.setText(mAccounts.get(position).getUsername());
holder.itemView.setOnClickListener(view -> {
mCurrentAccountName = mAccounts.get(position).getUsername();
mItemSelectedListener.accountSelected(mAccounts.get(position));
});
} else if(position == mAccounts.size()) {
holder.profileImageGifImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.primaryTextColor), android.graphics.PorterDuff.Mode.SRC_IN);
mGlide.load(R.drawable.ic_outline_add_circle_outline_24px)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(holder.profileImageGifImageView);
holder.usernameTextView.setText(R.string.add_account);
holder.itemView.setOnClickListener(view -> mItemSelectedListener.addAccountSelected());
} else if(position == mAccounts.size() + 1) {
holder.profileImageGifImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.primaryTextColor), android.graphics.PorterDuff.Mode.SRC_IN);
mGlide.load(R.drawable.ic_outline_public_24px)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(holder.profileImageGifImageView);
holder.usernameTextView.setText(R.string.anonymous_account);
holder.itemView.setOnClickListener(view -> mItemSelectedListener.anonymousSelected());
} else if(position == mAccounts.size() + 2){
holder.profileImageGifImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.primaryTextColor), android.graphics.PorterDuff.Mode.SRC_IN);
mGlide.load(R.drawable.ic_outline_settings_24px)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(holder.profileImageGifImageView);
holder.usernameTextView.setText(R.string.manage_accounts);
holder.itemView.setOnClickListener(view -> mItemSelectedListener.manageAccountSelected());
} else if(mCurrentAccountName != null) {
holder.profileImageGifImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.primaryTextColor), android.graphics.PorterDuff.Mode.SRC_IN);
mGlide.load(R.drawable.ic_outline_block_24px)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(holder.profileImageGifImageView);
holder.usernameTextView.setText(R.string.log_out);
holder.itemView.setOnClickListener(view -> mItemSelectedListener.logoutSelected());
}
}
}
@Override
public int getItemCount() {
if(mAccounts == null) {
return 1;
} else {
if(mCurrentAccountName == null) {
return mAccounts.size() + 3;
} else {
return mAccounts.size() + 4;
}
}
}
@Override
public void onViewRecycled(@NonNull AccountViewHolder holder) {
mGlide.clear(holder.profileImageGifImageView);
holder.profileImageGifImageView.clearColorFilter();
}
void changeAccountsDataset(List<Account> accounts) {
mAccounts = accounts;
notifyDataSetChanged();
}
class AccountViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.profile_image_item_account) GifImageView profileImageGifImageView;
@BindView(R.id.username_text_view_item_account) TextView usernameTextView;
AccountViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

View File

@@ -15,8 +15,8 @@ class FetchMyInfo {
void onFetchMyInfoFail();
}
static void fetchMyInfo(final Retrofit retrofit, String accessToken,
final FetchUserMyListener fetchUserMyListener) {
static void fetchAccountInfo(final Retrofit retrofit, String accessToken,
final FetchUserMyListener fetchUserMyListener) {
RedditAPI api = retrofit.create(RedditAPI.class);
Call<String> userInfo = api.getMyInfo(RedditUtils.getOAuthHeader(accessToken));

View File

@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.view.MenuItem;
import android.webkit.CookieManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
@@ -65,6 +66,8 @@ public class LoginActivity extends AppCompatActivity {
String url = uriBuilder.toString();
CookieManager.getInstance().removeAllCookies(aBoolean -> {});
webView.loadUrl(url);
webView.setWebViewClient(new WebViewClient() {
@Override
@@ -97,7 +100,7 @@ public class LoginActivity extends AppCompatActivity {
String accessToken = responseJSON.getString(RedditUtils.ACCESS_TOKEN_KEY);
String refreshToken = responseJSON.getString(RedditUtils.REFRESH_TOKEN_KEY);
FetchMyInfo.fetchMyInfo(mOauthRetrofit, accessToken, new FetchMyInfo.FetchUserMyListener() {
FetchMyInfo.fetchAccountInfo(mOauthRetrofit, accessToken, new FetchMyInfo.FetchUserMyListener() {
@Override
public void onFetchMyInfoSuccess(String response) {
ParseAndSaveAccountInfo.parseAndSaveAccountInfo(response, mRedditDataRoomDatabase, new ParseAndSaveAccountInfo.ParseAndSaveAccountInfoListener() {

View File

@@ -20,6 +20,9 @@ import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide;
@@ -33,6 +36,8 @@ import com.google.android.material.tabs.TabLayout;
import javax.inject.Inject;
import javax.inject.Named;
import Account.Account;
import Account.AccountViewModel;
import butterknife.BindView;
import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
@@ -45,6 +50,7 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
static final String EXTRA_POST_TYPE = "EPT";
private static final String FETCH_USER_INFO_STATE = "FUIS";
private static final String DRAWER_ON_ACCOUNT_SWITCH_STATE = "DOASS";
private static final String IS_IN_LAZY_MODE_STATE = "IILMS";
private static final String NULL_ACCESS_TOKEN_STATE = "NATS";
private static final String ACCESS_TOKEN_STATE = "ATS";
@@ -58,18 +64,22 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.view_pager_main_activity) ViewPager viewPager;
@BindView(R.id.collapsing_toolbar_layout_main_activity) CollapsingToolbarLayout collapsingToolbarLayout;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.all_drawer_items_linear_layout_main_activity) LinearLayout allDrawerItemsLinearLayout;
@BindView(R.id.profile_linear_layout_main_activity) LinearLayout profileLinearLayout;
@BindView(R.id.subscriptions_linear_layout_main_activity) LinearLayout subscriptionLinearLayout;
@BindView(R.id.settings_linear_layout_main_activity) LinearLayout settingsLinearLayout;
@BindView(R.id.account_recycler_view_main_activity) RecyclerView accountRecyclerView;
@BindView(R.id.tab_layout_main_activity) TabLayout tabLayout;
@BindView(R.id.fab_main_activity) FloatingActionButton fab;
private SectionsPagerAdapter sectionsPagerAdapter;
private TextView mNameTextView;
private TextView mAccountNameTextView;
private TextView mKarmaTextView;
private GifImageView mProfileImageView;
private ImageView mBannerImageView;
private ImageView mDropIconImageView;
private RequestManager glide;
private AppBarLayout.LayoutParams params;
@@ -79,16 +89,19 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
private boolean mNullAccessToken = false;
private String mAccessToken;
private String mName;
private String mAccountName;
private String mProfileImageUrl;
private String mBannerImageUrl;
private String mKarma;
private int mKarma;
private boolean mFetchUserInfoSuccess = false;
private boolean mDrawerOnAccountSwitch = false;
private Menu mMenu;
private boolean isInLazyMode = false;
AccountViewModel accountViewModel;
@Inject
@Named("oauth")
Retrofit mOauthRetrofit;
@@ -117,7 +130,6 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
popularBundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, true);
popularAndAllSortTypeBottomSheetFragment.setArguments(popularBundle);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
@@ -130,13 +142,14 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
if(savedInstanceState != null) {
mFetchUserInfoSuccess = savedInstanceState.getBoolean(FETCH_USER_INFO_STATE);
mDrawerOnAccountSwitch = savedInstanceState.getBoolean(DRAWER_ON_ACCOUNT_SWITCH_STATE);
isInLazyMode = savedInstanceState.getBoolean(IS_IN_LAZY_MODE_STATE);
mNullAccessToken = savedInstanceState.getBoolean(NULL_ACCESS_TOKEN_STATE);
mAccessToken = savedInstanceState.getString(ACCESS_TOKEN_STATE);
mName = savedInstanceState.getString(ACCOUNT_NAME_STATE);
mAccountName = savedInstanceState.getString(ACCOUNT_NAME_STATE);
mProfileImageUrl = savedInstanceState.getString(ACCOUNT_PROFILE_IMAGE_URL_STATE);
mBannerImageUrl = savedInstanceState.getString(ACCOUNT_BANNER_IMAGE_URL_STATE);
mKarma = savedInstanceState.getString(ACCOUNT_KARMA_STATE);
mKarma = savedInstanceState.getInt(ACCOUNT_KARMA_STATE);
if(!mNullAccessToken && mAccessToken == null) {
getCurrentAccountAndBindView();
} else {
@@ -157,10 +170,10 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
startActivityForResult(loginIntent, LOGIN_ACTIVITY_REQUEST_CODE);
} else {
mAccessToken = account.getAccessToken();
mName = account.getUsername();
mAccountName = account.getUsername();
mProfileImageUrl = account.getProfileImageUrl();
mBannerImageUrl = account.getBannerImageUrl();
mKarma = Integer.toString(account.getKarma());
mKarma = account.getKarma();
bindView();
}
}).execute();
@@ -172,6 +185,45 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
viewPager.setOffscreenPageLimit(2);
tabLayout.setupWithViewPager(viewPager);
glide = Glide.with(this);
AccountRecyclerViewAdapter adapter = new AccountRecyclerViewAdapter(this, glide, mAccountName,
new AccountRecyclerViewAdapter.ItemSelectedListener() {
@Override
public void accountSelected(Account account) {
}
@Override
public void addAccountSelected() {
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivityForResult(intent, LOGIN_ACTIVITY_REQUEST_CODE);
}
@Override
public void anonymousSelected() {
}
@Override
public void logoutSelected() {
}
@Override
public void manageAccountSelected() {
}
});
accountRecyclerView.setLayoutManager(new LinearLayoutManager(this));
accountRecyclerView.setNestedScrollingEnabled(false);
accountRecyclerView.setAdapter(adapter);
accountViewModel = ViewModelProviders.of(this,
new AccountViewModel.Factory(getApplication(), mRedditDataRoomDatabase, mAccountName)).get(AccountViewModel.class);
accountViewModel.getAccountsExceptCurrentAccountLiveData().observe(this, adapter::changeAccountsDataset);
if(getIntent().hasExtra(EXTRA_POST_TYPE)) {
if(getIntent().getExtras().getString(EXTRA_POST_TYPE).equals("popular")) {
viewPager.setCurrentItem(1);
@@ -180,18 +232,41 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
}
}
glide = Glide.with(this);
View header = findViewById(R.id.nav_header_main_activity);
mNameTextView = header.findViewById(R.id.name_text_view_nav_header_main);
mAccountNameTextView = header.findViewById(R.id.name_text_view_nav_header_main);
mKarmaTextView = header.findViewById(R.id.karma_text_view_nav_header_main);
mProfileImageView = header.findViewById(R.id.profile_image_view_nav_header_main);
mBannerImageView = header.findViewById(R.id.banner_image_view_nav_header_main);
mDropIconImageView = header.findViewById(R.id.account_switcher_image_view_nav_header_main);
if(mDrawerOnAccountSwitch) {
mDropIconImageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_baseline_arrow_drop_up_24px));
accountRecyclerView.setVisibility(View.VISIBLE);
allDrawerItemsLinearLayout.setVisibility(View.GONE);
} else {
mDropIconImageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_baseline_arrow_drop_down_24px));
accountRecyclerView.setVisibility(View.GONE);
allDrawerItemsLinearLayout.setVisibility(View.VISIBLE);
}
header.setOnClickListener(view -> {
if(mDrawerOnAccountSwitch) {
mDrawerOnAccountSwitch = false;
mDropIconImageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_baseline_arrow_drop_down_24px));
accountRecyclerView.setVisibility(View.GONE);
allDrawerItemsLinearLayout.setVisibility(View.VISIBLE);
} else {
mDrawerOnAccountSwitch = true;
mDropIconImageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_baseline_arrow_drop_up_24px));
accountRecyclerView.setVisibility(View.VISIBLE);
allDrawerItemsLinearLayout.setVisibility(View.GONE);
}
});
loadUserData();
mNameTextView.setText(mName);
mKarmaTextView.setText(mKarma);
mAccountNameTextView.setText(mAccountName);
mKarmaTextView.setText(getString(R.string.karma_info, mKarma));
if (mProfileImageUrl != null && !mProfileImageUrl.equals("")) {
glide.load(mProfileImageUrl)
@@ -211,7 +286,7 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
profileLinearLayout.setOnClickListener(view -> {
Intent intent = new Intent(this, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mName);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mAccountName);
startActivity(intent);
});
@@ -227,13 +302,13 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
private void loadUserData() {
if (!mFetchUserInfoSuccess) {
FetchMyInfo.fetchMyInfo(mOauthRetrofit, mAccessToken, new FetchMyInfo.FetchUserMyListener() {
FetchMyInfo.fetchAccountInfo(mOauthRetrofit, mAccessToken, new FetchMyInfo.FetchUserMyListener() {
@Override
public void onFetchMyInfoSuccess(String response) {
ParseAndSaveAccountInfo.parseAndSaveAccountInfo(response, mRedditDataRoomDatabase, new ParseAndSaveAccountInfo.ParseAndSaveAccountInfoListener() {
@Override
public void onParseMyInfoSuccess(String name, String profileImageUrl, String bannerImageUrl, int karma) {
mNameTextView.setText(name);
mAccountNameTextView.setText(name);
if (profileImageUrl != null && !profileImageUrl.equals("")) {
glide.load(profileImageUrl)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
@@ -249,12 +324,12 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
glide.load(bannerImageUrl).into(mBannerImageView);
}
mName = name;
mAccountName = name;
mProfileImageUrl = profileImageUrl;
mBannerImageUrl = bannerImageUrl;
mKarma = getString(R.string.karma_info, karma);
mKarma = karma;
mKarmaTextView.setText(mKarma);
mKarmaTextView.setText(getString(R.string.karma_info, karma));
mFetchUserInfoSuccess = true;
}
@@ -358,13 +433,14 @@ public class MainActivity extends AppCompatActivity implements SortTypeBottomShe
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(FETCH_USER_INFO_STATE, mFetchUserInfoSuccess);
outState.putBoolean(DRAWER_ON_ACCOUNT_SWITCH_STATE, mDrawerOnAccountSwitch);
outState.putBoolean(IS_IN_LAZY_MODE_STATE, isInLazyMode);
outState.putBoolean(NULL_ACCESS_TOKEN_STATE, mNullAccessToken);
outState.putString(ACCESS_TOKEN_STATE, mAccessToken);
outState.putString(ACCOUNT_NAME_STATE, mName);
outState.putString(ACCOUNT_NAME_STATE, mAccountName);
outState.putString(ACCOUNT_PROFILE_IMAGE_URL_STATE, mProfileImageUrl);
outState.putString(ACCOUNT_BANNER_IMAGE_URL_STATE, mBannerImageUrl);
outState.putString(ACCOUNT_KARMA_STATE, mKarma);
outState.putInt(ACCOUNT_KARMA_STATE, mKarma);
}
@Override