Submit posts using another account is available in PostTextActivity.

This commit is contained in:
Docile-Alligator 2022-04-24 11:11:15 +08:00
parent 3fa86984dc
commit be4e73c504
21 changed files with 517 additions and 55 deletions

View File

@ -0,0 +1,101 @@
package ml.docilealligator.infinityforreddit;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import ml.docilealligator.infinityforreddit.account.Account;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
import okhttp3.Authenticator;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
import retrofit2.Call;
import retrofit2.Retrofit;
public class AnyAccountAccessTokenAuthenticator implements Authenticator {
private Retrofit mRetrofit;
private RedditDataRoomDatabase mRedditDataRoomDatabase;
private Account mAccount;
private SharedPreferences mCurrentAccountSharedPreferences;
public AnyAccountAccessTokenAuthenticator(Retrofit retrofit, RedditDataRoomDatabase accountRoomDatabase, Account account,
SharedPreferences currentAccountSharedPreferences) {
mRetrofit = retrofit;
mRedditDataRoomDatabase = accountRoomDatabase;
mAccount = account;
mCurrentAccountSharedPreferences = currentAccountSharedPreferences;
}
@Nullable
@Override
public Request authenticate(Route route, @NonNull Response response) {
if (response.code() == 401) {
String accessToken = response.request().header(APIUtils.AUTHORIZATION_KEY).substring(APIUtils.AUTHORIZATION_BASE.length());
synchronized (this) {
if (mAccount == null) {
return null;
}
String accessTokenFromDatabase = mAccount.getAccessToken();
if (accessToken.equals(accessTokenFromDatabase)) {
String newAccessToken = refreshAccessToken(mAccount);
if (!newAccessToken.equals("")) {
return response.request().newBuilder().headers(Headers.of(APIUtils.getOAuthHeader(newAccessToken))).build();
} else {
return null;
}
} else {
return response.request().newBuilder().headers(Headers.of(APIUtils.getOAuthHeader(accessTokenFromDatabase))).build();
}
}
}
return null;
}
private String refreshAccessToken(Account account) {
String refreshToken = account.getRefreshToken();
RedditAPI api = mRetrofit.create(RedditAPI.class);
Map<String, String> params = new HashMap<>();
params.put(APIUtils.GRANT_TYPE_KEY, APIUtils.GRANT_TYPE_REFRESH_TOKEN);
params.put(APIUtils.REFRESH_TOKEN_KEY, refreshToken);
Call<String> accessTokenCall = api.getAccessToken(APIUtils.getHttpBasicAuthHeader(), params);
try {
retrofit2.Response<String> response = accessTokenCall.execute();
if (response.isSuccessful() && response.body() != null) {
JSONObject jsonObject = new JSONObject(response.body());
String newAccessToken = jsonObject.getString(APIUtils.ACCESS_TOKEN_KEY);
String newRefreshToken = jsonObject.has(APIUtils.REFRESH_TOKEN_KEY) ? jsonObject.getString(APIUtils.REFRESH_TOKEN_KEY) : null;
if (newRefreshToken == null) {
mRedditDataRoomDatabase.accountDao().updateAccessToken(account.getAccountName(), newAccessToken);
} else {
mRedditDataRoomDatabase.accountDao().updateAccessTokenAndRefreshToken(account.getAccountName(), newAccessToken, newRefreshToken);
}
Account currentAccount = mRedditDataRoomDatabase.accountDao().getCurrentAccount();
if (currentAccount != null && mAccount.getAccountName().equals(currentAccount.getAccountName()) && mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCOUNT_NAME, "").equals(account.getAccountName())) {
mCurrentAccountSharedPreferences.edit().putString(SharedPreferencesUtils.ACCESS_TOKEN, newAccessToken).apply();
}
return newAccessToken;
}
return "";
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return "";
}
}

View File

@ -13,8 +13,8 @@ import ml.docilealligator.infinityforreddit.activities.CustomizePostFilterActivi
import ml.docilealligator.infinityforreddit.activities.CustomizeThemeActivity;
import ml.docilealligator.infinityforreddit.activities.EditCommentActivity;
import ml.docilealligator.infinityforreddit.activities.EditMultiRedditActivity;
import ml.docilealligator.infinityforreddit.activities.EditProfileActivity;
import ml.docilealligator.infinityforreddit.activities.EditPostActivity;
import ml.docilealligator.infinityforreddit.activities.EditProfileActivity;
import ml.docilealligator.infinityforreddit.activities.FetchRandomSubredditOrPostActivity;
import ml.docilealligator.infinityforreddit.activities.FilteredPostsActivity;
import ml.docilealligator.infinityforreddit.activities.FullMarkdownActivity;
@ -61,6 +61,7 @@ import ml.docilealligator.infinityforreddit.activities.ViewUserDetailActivity;
import ml.docilealligator.infinityforreddit.activities.ViewVideoActivity;
import ml.docilealligator.infinityforreddit.activities.WebViewActivity;
import ml.docilealligator.infinityforreddit.activities.WikiActivity;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.AccountChooserBottomSheetFragment;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.FlairBottomSheetFragment;
import ml.docilealligator.infinityforreddit.fragments.CommentsListingFragment;
import ml.docilealligator.infinityforreddit.fragments.FollowedUsersListingFragment;
@ -298,4 +299,6 @@ public interface AppComponent {
void inject(CommentPreferenceFragment commentPreferenceFragment);
void inject(PostPollActivity postPollActivity);
void inject(AccountChooserBottomSheetFragment accountChooserBottomSheetFragment);
}

View File

@ -1,5 +1,8 @@
package ml.docilealligator.infinityforreddit.account;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
@ -7,7 +10,7 @@ import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity(tableName = "accounts")
public class Account {
public class Account implements Parcelable {
@PrimaryKey
@NonNull
@ColumnInfo(name = "username")
@ -27,6 +30,30 @@ public class Account {
@ColumnInfo(name = "is_current_user")
private boolean isCurrentUser;
@Ignore
protected Account(Parcel in) {
accountName = in.readString();
profileImageUrl = in.readString();
bannerImageUrl = in.readString();
karma = in.readInt();
accessToken = in.readString();
refreshToken = in.readString();
code = in.readString();
isCurrentUser = in.readByte() != 0;
}
public static final Creator<Account> CREATOR = new Creator<Account>() {
@Override
public Account createFromParcel(Parcel in) {
return new Account(in);
}
@Override
public Account[] newArray(int size) {
return new Account[size];
}
};
@Ignore
public static Account getAnonymousAccount() {
return new Account("-", null, null, null, null, null, 0, false);
@ -80,4 +107,21 @@ public class Account {
public boolean isCurrentUser() {
return isCurrentUser;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(accountName);
dest.writeString(profileImageUrl);
dest.writeString(bannerImageUrl);
dest.writeInt(karma);
dest.writeString(accessToken);
dest.writeString(refreshToken);
dest.writeString(code);
dest.writeByte((byte) (isCurrentUser ? 1 : 0));
}
}

View File

@ -16,6 +16,9 @@ public interface AccountDao {
@Query("SELECT EXISTS (SELECT 1 FROM accounts WHERE username = '-')")
boolean isAnonymousAccountInserted();
@Query("SELECT * FROM accounts WHERE username != '-'")
LiveData<List<Account>> getAllAccountsLiveData();
@Query("SELECT * FROM accounts WHERE username != '-'")
List<Account> getAllAccounts();

View File

@ -12,11 +12,13 @@ public class AccountRepository {
private AccountDao mAccountDao;
private LiveData<List<Account>> mAccountsExceptCurrentAccountLiveData;
private LiveData<Account> mCurrentAccountLiveData;
private LiveData<List<Account>> mAllAccountsLiveData;
AccountRepository(RedditDataRoomDatabase redditDataRoomDatabase, String username) {
AccountRepository(RedditDataRoomDatabase redditDataRoomDatabase) {
mAccountDao = redditDataRoomDatabase.accountDao();
mAccountsExceptCurrentAccountLiveData = mAccountDao.getAccountsExceptCurrentAccountLiveData();
mCurrentAccountLiveData = mAccountDao.getCurrentAccountLiveData();
mAllAccountsLiveData = mAccountDao.getAllAccountsLiveData();
}
public LiveData<List<Account>> getAccountsExceptCurrentAccountLiveData() {
@ -27,6 +29,10 @@ public class AccountRepository {
return mCurrentAccountLiveData;
}
public LiveData<List<Account>> getAllAccountsLiveData() {
return mAllAccountsLiveData;
}
public void insert(Account Account) {
new InsertAsyncTask(mAccountDao).execute(Account);
}

View File

@ -1,9 +1,5 @@
package ml.docilealligator.infinityforreddit.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;
@ -12,16 +8,17 @@ import java.util.List;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
public class AccountViewModel extends AndroidViewModel {
public class AccountViewModel extends ViewModel {
private AccountRepository mAccountRepository;
private LiveData<List<Account>> mAccountsExceptCurrentAccountLiveData;
private LiveData<Account> mCurrentAccountLiveData;
private LiveData<List<Account>> mAllAccountsLiveData;
public AccountViewModel(Application application, RedditDataRoomDatabase redditDataRoomDatabase, String id) {
super(application);
mAccountRepository = new AccountRepository(redditDataRoomDatabase, id);
public AccountViewModel(RedditDataRoomDatabase redditDataRoomDatabase) {
mAccountRepository = new AccountRepository(redditDataRoomDatabase);
mAccountsExceptCurrentAccountLiveData = mAccountRepository.getAccountsExceptCurrentAccountLiveData();
mCurrentAccountLiveData = mAccountRepository.getCurrentAccountLiveData();
mAllAccountsLiveData = mAccountRepository.getAllAccountsLiveData();
}
public LiveData<List<Account>> getAccountsExceptCurrentAccountLiveData() {
@ -32,27 +29,26 @@ public class AccountViewModel extends AndroidViewModel {
return mCurrentAccountLiveData;
}
public LiveData<List<Account>> getAllAccountsLiveData() {
return mAllAccountsLiveData;
}
public void insert(Account userData) {
mAccountRepository.insert(userData);
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
@NonNull
private final Application mApplication;
private final RedditDataRoomDatabase mRedditDataRoomDatabase;
private final String mUsername;
public Factory(@NonNull Application application, RedditDataRoomDatabase redditDataRoomDatabase, String username) {
mApplication = application;
public Factory(RedditDataRoomDatabase redditDataRoomDatabase) {
mRedditDataRoomDatabase = redditDataRoomDatabase;
mUsername = username;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
//noinspection unchecked
return (T) new AccountViewModel(mApplication, mRedditDataRoomDatabase, mUsername);
return (T) new AccountViewModel(mRedditDataRoomDatabase);
}
}
}

View File

@ -564,7 +564,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
}
private void bindView() {
if (isDestroyed()) {
if (isFinishing() || isDestroyed()) {
return;
}
@ -935,7 +935,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
});
accountViewModel = new ViewModelProvider(this,
new AccountViewModel.Factory(getApplication(), mRedditDataRoomDatabase, mAccountName)).get(AccountViewModel.class);
new AccountViewModel.Factory(mRedditDataRoomDatabase)).get(AccountViewModel.class);
accountViewModel.getAccountsExceptCurrentAccountLiveData().observe(this, adapter::changeAccountsDataset);
accountViewModel.getCurrentAccountLiveData().observe(this, account -> {
if (account != null) {

View File

@ -579,7 +579,7 @@ public class PostGalleryActivity extends BaseActivity implements FlairBottomShee
}
Intent intent = new Intent(this, SubmitPostService.class);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_POST_TYPE, SubmitPostService.EXTRA_POST_TYPE_GALLERY);
ArrayList<RedditGalleryPayload.Item> items = new ArrayList<>();

View File

@ -519,7 +519,7 @@ public class PostImageActivity extends BaseActivity implements FlairBottomSheetF
Intent intent = new Intent(this, SubmitPostService.class);
intent.setData(imageUri);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_TITLE, titleEditText.getText().toString());
intent.putExtra(SubmitPostService.EXTRA_FLAIR, flair);

View File

@ -489,7 +489,7 @@ public class PostLinkActivity extends BaseActivity implements FlairBottomSheetFr
}
Intent intent = new Intent(this, SubmitPostService.class);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_TITLE, titleEditText.getText().toString());
intent.putExtra(SubmitPostService.EXTRA_CONTENT, linkEditText.getText().toString());

View File

@ -580,7 +580,7 @@ public class PostPollActivity extends BaseActivity implements FlairBottomSheetFr
mPostingSnackbar.show();
Intent intent = new Intent(this, SubmitPostService.class);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_POST_TYPE, SubmitPostService.EXTRA_POST_TYPE_POLL);
PollPayload payload = new PollPayload(subredditName, titleEditText.getText().toString(),

View File

@ -58,8 +58,10 @@ import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
import ml.docilealligator.infinityforreddit.UploadImageEnabledActivity;
import ml.docilealligator.infinityforreddit.UploadedImage;
import ml.docilealligator.infinityforreddit.account.Account;
import ml.docilealligator.infinityforreddit.adapters.MarkdownBottomBarRecyclerViewAdapter;
import ml.docilealligator.infinityforreddit.asynctasks.LoadSubredditIcon;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.AccountChooserBottomSheetFragment;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.FlairBottomSheetFragment;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.UploadedImagesBottomSheetFragment;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
@ -74,11 +76,12 @@ import pl.droidsonroids.gif.GifImageView;
import retrofit2.Retrofit;
public class PostTextActivity extends BaseActivity implements FlairBottomSheetFragment.FlairSelectionCallback,
UploadImageEnabledActivity {
UploadImageEnabledActivity, AccountChooserBottomSheetFragment.AccountChooserListener {
static final String EXTRA_SUBREDDIT_NAME = "ESN";
static final String EXTRA_CONTENT = "EC";
private static final String SELECTED_ACCOUNT_STATE = "SAS";
private static final String SUBREDDIT_NAME_STATE = "SNS";
private static final String SUBREDDIT_ICON_STATE = "SIS";
private static final String SUBREDDIT_SELECTED_STATE = "SSS";
@ -101,6 +104,12 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
AppBarLayout appBarLayout;
@BindView(R.id.toolbar_post_text_activity)
Toolbar toolbar;
@BindView(R.id.account_linear_layout_post_text_activity)
LinearLayout accountLinearLayout;
@BindView(R.id.account_icon_gif_image_view_post_text_activity)
GifImageView accountIconImageView;
@BindView(R.id.account_name_text_view_post_text_activity)
TextView accountNameTextView;
@BindView(R.id.subreddit_icon_gif_image_view_post_text_activity)
GifImageView iconGifImageView;
@BindView(R.id.subreddit_name_text_view_post_text_activity)
@ -150,6 +159,7 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
CustomThemeWrapper mCustomThemeWrapper;
@Inject
Executor mExecutor;
private Account selectedAccount;
private String mAccessToken;
private String iconUrl;
private String subredditName;
@ -207,6 +217,7 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
if (savedInstanceState != null) {
selectedAccount = savedInstanceState.getParcelable(SELECTED_ACCOUNT_STATE);
subredditName = savedInstanceState.getString(SUBREDDIT_NAME_STATE);
iconUrl = savedInstanceState.getString(SUBREDDIT_ICON_STATE);
subredditSelected = savedInstanceState.getBoolean(SUBREDDIT_SELECTED_STATE);
@ -218,6 +229,16 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
isNSFW = savedInstanceState.getBoolean(IS_NSFW_STATE);
uploadedImages = savedInstanceState.getParcelableArrayList(UPLOADED_IMAGES_STATE);
if (selectedAccount != null) {
mGlide.load(selectedAccount.getProfileImageUrl())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(accountIconImageView);
accountNameTextView.setText(selectedAccount.getAccountName());
}
if (subredditName != null) {
subredditNameTextView.setTextColor(primaryTextColor);
subredditNameTextView.setText(subredditName);
@ -251,6 +272,23 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
} else {
isPosting = false;
Handler handler = new Handler();
mExecutor.execute(() -> {
Account account = mRedditDataRoomDatabase.accountDao().getCurrentAccount();
selectedAccount = account;
handler.post(() -> {
if (!isFinishing() && !isDestroyed() && account != null) {
mGlide.load(account.getProfileImageUrl())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(accountIconImageView);
accountNameTextView.setText(account.getAccountName());
}
});
});
if (getIntent().hasExtra(EXTRA_SUBREDDIT_NAME)) {
loadSubredditIconSuccessful = false;
subredditName = getIntent().getStringExtra(EXTRA_SUBREDDIT_NAME);
@ -271,6 +309,11 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
}
}
accountLinearLayout.setOnClickListener(view -> {
AccountChooserBottomSheetFragment fragment = new AccountChooserBottomSheetFragment();
fragment.show(getSupportFragmentManager(), fragment.getTag());
});
iconGifImageView.setOnClickListener(view -> {
Intent intent = new Intent(this, SubredditSelectionActivity.class);
startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE);
@ -384,11 +427,12 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
protected void applyCustomTheme() {
coordinatorLayout.setBackgroundColor(mCustomThemeWrapper.getBackgroundColor());
applyAppBarLayoutAndCollapsingToolbarLayoutAndToolbarTheme(appBarLayout, null, toolbar);
primaryTextColor = mCustomThemeWrapper.getPrimaryTextColor();
accountNameTextView.setTextColor(primaryTextColor);
int secondaryTextColor = mCustomThemeWrapper.getSecondaryTextColor();
subredditNameTextView.setTextColor(secondaryTextColor);
rulesButton.setTextColor(mCustomThemeWrapper.getButtonTextColor());
rulesButton.setBackgroundColor(mCustomThemeWrapper.getColorPrimaryLightTheme());
primaryTextColor = mCustomThemeWrapper.getPrimaryTextColor();
receivePostReplyNotificationsTextView.setTextColor(primaryTextColor);
int dividerColor = mCustomThemeWrapper.getDividerColor();
divider1.setDividerColor(dividerColor);
@ -521,7 +565,7 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
}
Intent intent = new Intent(this, SubmitPostService.class);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, selectedAccount);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_TITLE, titleEditText.getText().toString());
intent.putExtra(SubmitPostService.EXTRA_CONTENT, contentEditText.getText().toString());
@ -550,6 +594,7 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(SELECTED_ACCOUNT_STATE, selectedAccount);
outState.putString(SUBREDDIT_NAME_STATE, subredditName);
outState.putString(SUBREDDIT_ICON_STATE, iconUrl);
outState.putBoolean(SUBREDDIT_SELECTED_STATE, subredditSelected);
@ -672,4 +717,19 @@ public class PostTextActivity extends BaseActivity implements FlairBottomSheetFr
"[" + uploadedImage.imageName + "](" + uploadedImage.imageUrl + ")",
0, "[]()".length() + uploadedImage.imageName.length() + uploadedImage.imageUrl.length());
}
@Override
public void onAccountSelected(Account account) {
if (account != null) {
selectedAccount = account;
mGlide.load(selectedAccount.getProfileImageUrl())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(accountIconImageView);
accountNameTextView.setText(selectedAccount.getAccountName());
}
}
}

View File

@ -536,7 +536,7 @@ public class PostVideoActivity extends BaseActivity implements FlairBottomSheetF
Intent intent = new Intent(this, SubmitPostService.class);
intent.setData(videoUri);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_TITLE, titleEditText.getText().toString());
intent.putExtra(SubmitPostService.EXTRA_FLAIR, flair);

View File

@ -518,7 +518,7 @@ public class SubmitCrosspostActivity extends BaseActivity implements FlairBottom
}
Intent intent = new Intent(this, SubmitPostService.class);
intent.putExtra(SubmitPostService.EXTRA_ACCESS_TOKEN, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_ACCOUNT, mAccessToken);
intent.putExtra(SubmitPostService.EXTRA_SUBREDDIT_NAME, subredditName);
intent.putExtra(SubmitPostService.EXTRA_TITLE, titleEditText.getText().toString());
if (post.isCrosspost()) {

View File

@ -0,0 +1,91 @@
package ml.docilealligator.infinityforreddit.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.account.Account;
import ml.docilealligator.infinityforreddit.activities.BaseActivity;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import pl.droidsonroids.gif.GifImageView;
public class AccountChooserRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private BaseActivity baseActivity;
private ArrayList<Account> accounts;
private RequestManager glide;
private int primaryTextColor;
private ItemClickListener itemClickListener;
public AccountChooserRecyclerViewAdapter(BaseActivity baseActivity, CustomThemeWrapper customThemeWrapper,
RequestManager glide, ItemClickListener itemClickListener) {
this.baseActivity = baseActivity;
this.glide = glide;
primaryTextColor = customThemeWrapper.getPrimaryTextColor();
this.itemClickListener = itemClickListener;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new AccountViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_nav_drawer_account, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof AccountViewHolder) {
glide.load(accounts.get(position).getProfileImageUrl())
.error(glide.load(R.drawable.subreddit_default_icon))
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(128, 0)))
.into(((AccountViewHolder) holder).profileImageGifImageView);
((AccountViewHolder) holder).usernameTextView.setText(accounts.get(position).getAccountName());
holder.itemView.setOnClickListener(view ->
itemClickListener.onClick(accounts.get(position)));
}
}
@Override
public int getItemCount() {
return accounts == null ? 0 : accounts.size();
}
public void changeAccountsDataset(List<Account> accounts) {
this.accounts = (ArrayList<Account>) 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);
if (baseActivity.typeface != null) {
usernameTextView.setTypeface(baseActivity.typeface);
}
usernameTextView.setTextColor(primaryTextColor);
}
}
public interface ItemClickListener {
void onClick(Account account);
}
}

View File

@ -0,0 +1,78 @@
package ml.docilealligator.infinityforreddit.bottomsheetfragments;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import javax.inject.Inject;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
import ml.docilealligator.infinityforreddit.account.Account;
import ml.docilealligator.infinityforreddit.account.AccountViewModel;
import ml.docilealligator.infinityforreddit.activities.BaseActivity;
import ml.docilealligator.infinityforreddit.adapters.AccountChooserRecyclerViewAdapter;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.customviews.LandscapeExpandedBottomSheetDialogFragment;
public class AccountChooserBottomSheetFragment extends LandscapeExpandedBottomSheetDialogFragment {
@Inject
RedditDataRoomDatabase redditDataRoomDatabase;
@Inject
CustomThemeWrapper customThemeWrapper;
BaseActivity activity;
RecyclerView recyclerView;
AccountChooserRecyclerViewAdapter adapter;
AccountViewModel accountViewModel;
public AccountChooserBottomSheetFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_account_chooser_bottom_sheet, container, false);
((Infinity) activity.getApplication()).getAppComponent().inject(this);
recyclerView = rootView.findViewById(R.id.recycler_view_account_chooser_bottom_sheet_fragment);
adapter = new AccountChooserRecyclerViewAdapter(activity, customThemeWrapper, Glide.with(this),
account -> {
if (activity instanceof AccountChooserListener) {
((AccountChooserListener) activity).onAccountSelected(account);
}
dismiss();
});
recyclerView.setAdapter(adapter);
accountViewModel = new ViewModelProvider(this,
new AccountViewModel.Factory(redditDataRoomDatabase)).get(AccountViewModel.class);
accountViewModel.getAllAccountsLiveData().observe(getViewLifecycleOwner(), accounts -> {
adapter.changeAccountsDataset(accounts);
});
return rootView;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
activity = (BaseActivity) context;
}
public interface AccountChooserListener {
void onAccountSelected(Account account);
}
}

View File

@ -14,7 +14,6 @@ import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.greenrobot.eventbus.EventBus;
@ -32,6 +31,7 @@ import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.activities.BaseActivity;
import ml.docilealligator.infinityforreddit.adapters.FlairBottomSheetRecyclerViewAdapter;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.customviews.LandscapeExpandedBottomSheetDialogFragment;
import ml.docilealligator.infinityforreddit.events.FlairSelectedEvent;
import ml.docilealligator.infinityforreddit.utils.Utils;
import retrofit2.Retrofit;
@ -40,7 +40,7 @@ import retrofit2.Retrofit;
/**
* A simple {@link Fragment} subclass.
*/
public class FlairBottomSheetFragment extends BottomSheetDialogFragment {
public class FlairBottomSheetFragment extends LandscapeExpandedBottomSheetDialogFragment {
public static final String EXTRA_ACCESS_TOKEN = "EAT";
public static final String EXTRA_SUBREDDIT_NAME = "ESN";

View File

@ -0,0 +1,16 @@
package ml.docilealligator.infinityforreddit.customviews;
import android.view.View;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
public class LandscapeExpandedBottomSheetDialogFragment extends BottomSheetDialogFragment {
@Override
public void onStart() {
super.onStart();
View parentView = (View) requireView().getParent();
BottomSheetBehavior.from(parentView).setState(BottomSheetBehavior.STATE_EXPANDED);
BottomSheetBehavior.from(parentView).setSkipCollapsed(true);
}
}

View File

@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.services;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
@ -35,13 +36,17 @@ import java.io.OutputStream;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import ml.docilealligator.infinityforreddit.AnyAccountAccessTokenAuthenticator;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
import ml.docilealligator.infinityforreddit.account.Account;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.events.SubmitCrosspostEvent;
@ -55,11 +60,13 @@ import ml.docilealligator.infinityforreddit.post.SubmitPost;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.JSONUtils;
import ml.docilealligator.infinityforreddit.utils.NotificationUtils;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import retrofit2.Response;
import retrofit2.Retrofit;
public class SubmitPostService extends Service {
public static final String EXTRA_ACCESS_TOKEN = "EAT";
public static final String EXTRA_ACCOUNT = "EA";
public static final String EXTRA_SUBREDDIT_NAME = "ESN";
public static final String EXTRA_TITLE = "ET";
public static final String EXTRA_CONTENT = "EC";
@ -80,6 +87,9 @@ public class SubmitPostService extends Service {
private static final String EXTRA_MEDIA_URI = "EU";
@Inject
@Named("no_oauth")
Retrofit mRetrofit;
@Inject
@Named("oauth")
Retrofit mOauthRetrofit;
@Inject
@ -89,6 +99,11 @@ public class SubmitPostService extends Service {
@Named("upload_video")
Retrofit mUploadVideoRetrofit;
@Inject
RedditDataRoomDatabase mRedditDataRoomDatabase;
@Inject
@Named("current_account")
SharedPreferences mCurrentAccountSharedPreferences;
@Inject
CustomThemeWrapper mCustomThemeWrapper;
@Inject
Executor mExecutor;
@ -113,7 +128,7 @@ public class SubmitPostService extends Service {
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String accessToken = bundle.getString(EXTRA_ACCESS_TOKEN);
Account account = bundle.getParcelable(EXTRA_ACCOUNT);
String subredditName = bundle.getString(EXTRA_SUBREDDIT_NAME);
String title = bundle.getString(EXTRA_TITLE);
Flair flair = bundle.getParcelable(EXTRA_FLAIR);
@ -122,27 +137,35 @@ public class SubmitPostService extends Service {
boolean receivePostReplyNotifications = bundle.getBoolean(EXTRA_RECEIVE_POST_REPLY_NOTIFICATIONS, true);
int postType = bundle.getInt(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK);
Retrofit newAuthenticatorOauthRetrofit = mOauthRetrofit.newBuilder().client(new OkHttpClient.Builder().authenticator(new AnyAccountAccessTokenAuthenticator(mRetrofit, mRedditDataRoomDatabase, account, mCurrentAccountSharedPreferences))
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(0, 1, TimeUnit.NANOSECONDS))
.build())
.build();
if (postType == EXTRA_POST_TEXT_OR_LINK) {
String content = bundle.getString(EXTRA_CONTENT);
String kind = bundle.getString(EXTRA_KIND);
submitTextOrLinkPost(accessToken, subredditName, title, content, flair, isSpoiler, isNSFW,
submitTextOrLinkPost(newAuthenticatorOauthRetrofit, account, subredditName, title, content, flair, isSpoiler, isNSFW,
receivePostReplyNotifications, kind);
} else if (postType == EXTRA_POST_TYPE_CROSSPOST) {
String content = bundle.getString(EXTRA_CONTENT);
submitCrosspost(mExecutor, handler, accessToken, subredditName, title, content,
submitCrosspost(mExecutor, handler, newAuthenticatorOauthRetrofit, account, subredditName, title, content,
flair, isSpoiler, isNSFW, receivePostReplyNotifications);
} else if (postType == EXTRA_POST_TYPE_IMAGE) {
Uri mediaUri = Uri.parse(bundle.getString(EXTRA_MEDIA_URI));
submitImagePost(accessToken, mediaUri, subredditName, title, flair, isSpoiler, isNSFW,
submitImagePost(newAuthenticatorOauthRetrofit, account, mediaUri, subredditName, title, flair, isSpoiler, isNSFW,
receivePostReplyNotifications);
} else if (postType == EXTRA_POST_TYPE_VIDEO) {
Uri mediaUri = Uri.parse(bundle.getString(EXTRA_MEDIA_URI));
submitVideoPost(accessToken, mediaUri, subredditName, title, flair, isSpoiler, isNSFW,
submitVideoPost(newAuthenticatorOauthRetrofit, account, mediaUri, subredditName, title, flair, isSpoiler, isNSFW,
receivePostReplyNotifications);
} else if (postType == EXTRA_POST_TYPE_GALLERY) {
submitGalleryPost(accessToken, bundle.getString(EXTRA_REDDIT_GALLERY_PAYLOAD));
submitGalleryPost(newAuthenticatorOauthRetrofit, account, bundle.getString(EXTRA_REDDIT_GALLERY_PAYLOAD));
} else {
submitPollPost(accessToken, bundle.getString(EXTRA_POLL_PAYLOAD));
submitPollPost(newAuthenticatorOauthRetrofit, account, bundle.getString(EXTRA_POLL_PAYLOAD));
}
}
}
@ -165,8 +188,6 @@ public class SubmitPostService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
((Infinity) getApplication()).getAppComponent().inject(this);
NotificationChannelCompat serviceChannel =
new NotificationChannelCompat.Builder(
NotificationUtils.CHANNEL_SUBMIT_POST,
@ -211,10 +232,10 @@ public class SubmitPostService extends Service {
.build();
}
private void submitTextOrLinkPost(String accessToken, String subredditName, String title, String content,
private void submitTextOrLinkPost(Retrofit newAuthenticatorOauthRetrofit, Account selectedAccount, String subredditName, String title, String content,
Flair flair, boolean isSpoiler, boolean isNSFW, boolean receivePostReplyNotifications,
String kind) {
SubmitPost.submitTextOrLinkPost(mExecutor, handler, mOauthRetrofit, accessToken,
SubmitPost.submitTextOrLinkPost(mExecutor, handler, newAuthenticatorOauthRetrofit, selectedAccount.getAccessToken(),
subredditName, title, content, flair, isSpoiler,
isNSFW, receivePostReplyNotifications, kind, new SubmitPost.SubmitPostListener() {
@Override
@ -233,10 +254,11 @@ public class SubmitPostService extends Service {
});
}
private void submitCrosspost(Executor executor, Handler handler, String accessToken, String subredditName,
private void submitCrosspost(Executor executor, Handler handler, Retrofit newAuthenticatorOauthRetrofit,
Account selectedAccount, String subredditName,
String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW,
boolean receivePostReplyNotifications) {
SubmitPost.submitCrosspost(executor, handler, mOauthRetrofit, accessToken, subredditName, title,
SubmitPost.submitCrosspost(executor, handler, newAuthenticatorOauthRetrofit, selectedAccount.getAccessToken(), subredditName, title,
content, flair, isSpoiler, isNSFW, receivePostReplyNotifications, APIUtils.KIND_CROSSPOST,
new SubmitPost.SubmitPostListener() {
@Override
@ -255,12 +277,12 @@ public class SubmitPostService extends Service {
});
}
private void submitImagePost(String accessToken, Uri mediaUri, String subredditName, String title,
private void submitImagePost(Retrofit newAuthenticatorOauthRetrofit, Account selectedAccount, Uri mediaUri, String subredditName, String title,
Flair flair, boolean isSpoiler, boolean isNSFW, boolean receivePostReplyNotifications) {
try {
Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get();
SubmitPost.submitImagePost(mExecutor, handler, mOauthRetrofit, mUploadMediaRetrofit,
accessToken, subredditName, title, resource, flair, isSpoiler, isNSFW, receivePostReplyNotifications,
SubmitPost.submitImagePost(mExecutor, handler, newAuthenticatorOauthRetrofit, mUploadMediaRetrofit,
selectedAccount.getAccessToken(), subredditName, title, resource, flair, isSpoiler, isNSFW, receivePostReplyNotifications,
new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
@ -286,7 +308,7 @@ public class SubmitPostService extends Service {
}
}
private void submitVideoPost(String accessToken, Uri mediaUri, String subredditName, String title,
private void submitVideoPost(Retrofit newAuthenticatorOauthRetrofit, Account selectedAccount, Uri mediaUri, String subredditName, String title,
Flair flair, boolean isSpoiler, boolean isNSFW, boolean receivePostReplyNotifications) {
try {
InputStream in = getContentResolver().openInputStream(mediaUri);
@ -303,8 +325,8 @@ public class SubmitPostService extends Service {
Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get();
if (type != null) {
SubmitPost.submitVideoPost(mExecutor, handler, mOauthRetrofit, mUploadMediaRetrofit,
mUploadVideoRetrofit, accessToken, subredditName, title, new File(cacheFilePath),
SubmitPost.submitVideoPost(mExecutor, handler, newAuthenticatorOauthRetrofit, mUploadMediaRetrofit,
mUploadVideoRetrofit, selectedAccount.getAccessToken(), subredditName, title, new File(cacheFilePath),
type, resource, flair, isSpoiler, isNSFW, receivePostReplyNotifications,
new SubmitPost.SubmitPostListener() {
@Override
@ -342,9 +364,9 @@ public class SubmitPostService extends Service {
}
}
private void submitGalleryPost(String accessToken, String payload) {
private void submitGalleryPost(Retrofit newAuthenticatorOauthRetrofit, Account selectedAccount, String payload) {
try {
Response<String> response = mOauthRetrofit.create(RedditAPI.class).submitGalleryPost(APIUtils.getOAuthHeader(accessToken), payload).execute();
Response<String> response = newAuthenticatorOauthRetrofit.create(RedditAPI.class).submitGalleryPost(APIUtils.getOAuthHeader(selectedAccount.getAccessToken()), payload).execute();
if (response.isSuccessful()) {
JSONObject responseObject = new JSONObject(response.body()).getJSONObject(JSONUtils.JSON_KEY);
if (responseObject.getJSONArray(JSONUtils.ERRORS_KEY).length() != 0) {
@ -378,9 +400,9 @@ public class SubmitPostService extends Service {
}
}
private void submitPollPost(String accessToken, String payload) {
private void submitPollPost(Retrofit newAuthenticatorOauthRetrofit, Account selectedAccount, String payload) {
try {
Response<String> response = mOauthRetrofit.create(RedditAPI.class).submitPollPost(APIUtils.getOAuthHeader(accessToken), payload).execute();
Response<String> response = newAuthenticatorOauthRetrofit.create(RedditAPI.class).submitPollPost(APIUtils.getOAuthHeader(selectedAccount.getAccessToken()), payload).execute();
if (response.isSuccessful()) {
JSONObject responseObject = new JSONObject(response.body()).getJSONObject(JSONUtils.JSON_KEY);
if (responseObject.getJSONArray(JSONUtils.ERRORS_KEY).length() != 0) {

View File

@ -39,6 +39,33 @@
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/account_linear_layout_post_text_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground">
<pl.droidsonroids.gif.GifImageView
android:id="@+id/account_icon_gif_image_view_post_text_activity"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp" />
<TextView
android:id="@+id/account_name_text_view_post_text_activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="32dp"
android:textSize="?attr/font_default"
android:fontFamily="?attr/font_family" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".bottomsheetfragments.AccountChooserBottomSheetFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view_account_chooser_bottom_sheet_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</FrameLayout>