diff options
Diffstat (limited to 'app')
17 files changed, 2313 insertions, 2148 deletions
diff --git a/app/build.gradle b/app/build.gradle index f3b260ca..432949dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,7 +37,7 @@ android { dependencies { /** AndroidX **/ implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.biometric:biometric:1.1.0-rc01' + implementation 'androidx.biometric:biometric:1.2.0-alpha01' implementation 'androidx.browser:browser:1.3.0' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' @@ -52,7 +52,8 @@ dependencies { implementation "androidx.room:room-runtime:$roomVersion" annotationProcessor "androidx.room:room-compiler:$roomVersion" implementation 'androidx.work:work-runtime:2.4.0' - implementation 'com.google.android.material:material:1.3.0-alpha04' + implementation 'com.google.android.material:material:1.3.0-rc01' + implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01" /** ExoPlayer **/ def exoplayerVersion = "2.10.8" diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java index 05aa69fd..9e7ac3aa 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java @@ -64,6 +64,7 @@ import ml.docilealligator.infinityforreddit.fragments.SubscribedSubredditsListin import ml.docilealligator.infinityforreddit.fragments.UserListingFragment; import ml.docilealligator.infinityforreddit.fragments.ViewImgurImageFragment; import ml.docilealligator.infinityforreddit.fragments.ViewImgurVideoFragment; +import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment; import ml.docilealligator.infinityforreddit.fragments.ViewRedditGalleryImageOrGifFragment; import ml.docilealligator.infinityforreddit.fragments.ViewRedditGalleryVideoFragment; import ml.docilealligator.infinityforreddit.services.DownloadMediaService; @@ -248,4 +249,6 @@ public interface AppComponent { void inject(ViewImgurImageFragment viewImgurImageFragment); void inject(ViewRedditGalleryImageOrGifFragment viewRedditGalleryImageOrGifFragment); + + void inject(ViewPostDetailFragment viewPostDetailFragment); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditCommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditCommentActivity.java index 368d58cc..07c0c2af 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditCommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditCommentActivity.java @@ -52,8 +52,8 @@ public class EditCommentActivity extends BaseActivity { public static final String EXTRA_FULLNAME = "EF"; public static final String EXTRA_POSITION = "EP"; - static final String EXTRA_EDITED_COMMENT_CONTENT = "EECC"; - static final String EXTRA_EDITED_COMMENT_POSITION = "EECP"; + public static final String EXTRA_EDITED_COMMENT_CONTENT = "EECC"; + public static final String EXTRA_EDITED_COMMENT_POSITION = "EECP"; @BindView(R.id.coordinator_layout_edit_comment_activity) CoordinatorLayout coordinatorLayout; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditPostActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditPostActivity.java index 0f40fcc7..5c8ea02f 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditPostActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/EditPostActivity.java @@ -50,9 +50,9 @@ import retrofit2.Retrofit; public class EditPostActivity extends BaseActivity { - static final String EXTRA_TITLE = "ET"; - static final String EXTRA_CONTENT = "EC"; - static final String EXTRA_FULLNAME = "EF"; + public static final String EXTRA_TITLE = "ET"; + public static final String EXTRA_CONTENT = "EC"; + public static final String EXTRA_FULLNAME = "EF"; @BindView(R.id.coordinator_layout_edit_post_activity) CoordinatorLayout coordinatorLayout; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java index 5dfc00d3..83b8a2c9 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java @@ -968,11 +968,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb private void changeSortType() { int currentPostType = sectionsPagerAdapter.getCurrentPostType(); Bundle bundle = new Bundle(); - if (currentPostType != PostDataSource.TYPE_FRONT_PAGE) { - bundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, true); - } else { - bundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, false); - } + bundle.putBoolean(SortTypeBottomSheetFragment.EXTRA_NO_BEST_TYPE, currentPostType != PostDataSource.TYPE_FRONT_PAGE); SortTypeBottomSheetFragment sortTypeBottomSheetFragment = new SortTypeBottomSheetFragment(); sortTypeBottomSheetFragment.setArguments(bundle); sortTypeBottomSheetFragment.show(getSupportFragmentManager(), sortTypeBottomSheetFragment.getTag()); @@ -980,43 +976,43 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { - switch (item.getItemId()) { - case R.id.action_search_main_activity: - Intent intent = new Intent(this, SearchActivity.class); - startActivity(intent); - return true; - case R.id.action_sort_main_activity: - changeSortType(); - return true; - case R.id.action_refresh_main_activity: - if (mMenu != null) { - mMenu.findItem(R.id.action_lazy_mode_main_activity).setTitle(R.string.action_start_lazy_mode); - } - sectionsPagerAdapter.refresh(); - mFetchUserInfoSuccess = false; - loadUserData(); - return true; - case R.id.action_lazy_mode_main_activity: - MenuItem lazyModeItem = mMenu.findItem(R.id.action_lazy_mode_main_activity); - if (isInLazyMode) { - sectionsPagerAdapter.stopLazyMode(); - isInLazyMode = false; - lazyModeItem.setTitle(R.string.action_start_lazy_mode); - params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); + int itemId = item.getItemId(); + if (itemId == R.id.action_search_main_activity) { + Intent intent = new Intent(this, SearchActivity.class); + startActivity(intent); + return true; + } else if (itemId == R.id.action_sort_main_activity) { + changeSortType(); + return true; + } else if (itemId == R.id.action_refresh_main_activity) { + if (mMenu != null) { + mMenu.findItem(R.id.action_lazy_mode_main_activity).setTitle(R.string.action_start_lazy_mode); + } + sectionsPagerAdapter.refresh(); + mFetchUserInfoSuccess = false; + loadUserData(); + return true; + } else if (itemId == R.id.action_lazy_mode_main_activity) { + MenuItem lazyModeItem = mMenu.findItem(R.id.action_lazy_mode_main_activity); + if (isInLazyMode) { + sectionsPagerAdapter.stopLazyMode(); + isInLazyMode = false; + lazyModeItem.setTitle(R.string.action_start_lazy_mode); + params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); + collapsingToolbarLayout.setLayoutParams(params); + } else { + if (sectionsPagerAdapter.startLazyMode()) { + isInLazyMode = true; + lazyModeItem.setTitle(R.string.action_stop_lazy_mode); + params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL); collapsingToolbarLayout.setLayoutParams(params); - } else { - if (sectionsPagerAdapter.startLazyMode()) { - isInLazyMode = true; - lazyModeItem.setTitle(R.string.action_stop_lazy_mode); - params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL); - collapsingToolbarLayout.setLayoutParams(params); - } } - return true; - case R.id.action_change_post_layout_main_activity: - PostLayoutBottomSheetFragment postLayoutBottomSheetFragment = new PostLayoutBottomSheetFragment(); - postLayoutBottomSheetFragment.show(getSupportFragmentManager(), postLayoutBottomSheetFragment.getTag()); - return true; + } + return true; + } else if (itemId == R.id.action_change_post_layout_main_activity) { + PostLayoutBottomSheetFragment postLayoutBottomSheetFragment = new PostLayoutBottomSheetFragment(); + postLayoutBottomSheetFragment.show(getSupportFragmentManager(), postLayoutBottomSheetFragment.getTag()); + return true; } return false; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewPostDetailActivity.java index a9e83270..3e395af8 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewPostDetailActivity.java @@ -1,61 +1,41 @@ package ml.docilealligator.infinityforreddit.activities; +import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.util.DisplayMetrics; -import android.view.HapticFeedbackConstants; import android.view.KeyEvent; -import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.content.res.ResourcesCompat; -import androidx.core.graphics.drawable.DrawableCompat; -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.LinearSmoothScroller; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import androidx.transition.AutoTransition; -import androidx.transition.TransitionManager; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.RequestManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; + import com.evernote.android.state.State; import com.github.piasy.biv.BigImageViewer; import com.github.piasy.biv.loader.glide.GlideImageLoader; import com.google.android.material.appbar.AppBarLayout; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import com.livefront.bridge.Bridge; -import com.r0adkll.slidr.Slidr; import com.r0adkll.slidr.model.SlidrInterface; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -63,181 +43,71 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; -import im.ene.toro.exoplayer.ExoCreator; -import im.ene.toro.media.PlaybackInfo; -import im.ene.toro.media.VolumeInfo; import ml.docilealligator.infinityforreddit.ActivityToolbarInterface; -import ml.docilealligator.infinityforreddit.DeleteThing; import ml.docilealligator.infinityforreddit.Flair; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; -import ml.docilealligator.infinityforreddit.SaveThing; import ml.docilealligator.infinityforreddit.SortType; import ml.docilealligator.infinityforreddit.SortTypeSelectionCallback; -import ml.docilealligator.infinityforreddit.adapters.CommentAndPostRecyclerViewAdapter; -import ml.docilealligator.infinityforreddit.apis.RedditAPI; import ml.docilealligator.infinityforreddit.asynctasks.SwitchAccount; import ml.docilealligator.infinityforreddit.bottomsheetfragments.FlairBottomSheetFragment; -import ml.docilealligator.infinityforreddit.bottomsheetfragments.PostCommentSortTypeBottomSheetFragment; import ml.docilealligator.infinityforreddit.comment.Comment; -import ml.docilealligator.infinityforreddit.comment.FetchComment; -import ml.docilealligator.infinityforreddit.comment.FetchRemovedComment; -import ml.docilealligator.infinityforreddit.comment.ParseComment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; -import ml.docilealligator.infinityforreddit.customviews.CustomToroContainer; -import ml.docilealligator.infinityforreddit.events.ChangeNSFWBlurEvent; -import ml.docilealligator.infinityforreddit.events.ChangeNetworkStatusEvent; -import ml.docilealligator.infinityforreddit.events.ChangeSpoilerBlurEvent; -import ml.docilealligator.infinityforreddit.events.PostUpdateEventToDetailActivity; -import ml.docilealligator.infinityforreddit.events.PostUpdateEventToPostList; import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent; -import ml.docilealligator.infinityforreddit.message.ReadMessage; -import ml.docilealligator.infinityforreddit.post.FetchPost; -import ml.docilealligator.infinityforreddit.post.FetchRemovedPost; -import ml.docilealligator.infinityforreddit.post.HidePost; -import ml.docilealligator.infinityforreddit.post.ParsePost; +import ml.docilealligator.infinityforreddit.fragments.PostFragment; +import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment; import ml.docilealligator.infinityforreddit.post.Post; -import ml.docilealligator.infinityforreddit.subreddit.FetchSubredditData; -import ml.docilealligator.infinityforreddit.subreddit.SubredditData; -import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; -import ml.docilealligator.infinityforreddit.utils.Utils; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; - -import static im.ene.toro.media.PlaybackInfo.INDEX_UNSET; -import static im.ene.toro.media.PlaybackInfo.TIME_UNSET; -import static ml.docilealligator.infinityforreddit.activities.CommentActivity.RETURN_EXTRA_COMMENT_DATA_KEY; -import static ml.docilealligator.infinityforreddit.activities.CommentActivity.WRITE_COMMENT_REQUEST_CODE; public class ViewPostDetailActivity extends BaseActivity implements FlairBottomSheetFragment.FlairSelectionCallback, SortTypeSelectionCallback, ActivityToolbarInterface { + public static final String EXTRA_POST_LIST = "EPL"; public static final String EXTRA_POST_DATA = "EPD"; - public static final String EXTRA_POST_LIST_POSITION = "EPLI"; public static final String EXTRA_POST_ID = "EPI"; + public static final String EXTRA_POST_LIST_POSITION = "EPLP"; public static final String EXTRA_SINGLE_COMMENT_ID = "ESCI"; public static final String EXTRA_MESSAGE_FULLNAME = "ENI"; public static final String EXTRA_NEW_ACCOUNT_NAME = "ENAN"; public static final int EDIT_COMMENT_REQUEST_CODE = 3; public static final int GIVE_AWARD_REQUEST_CODE = 100; - private static final int EDIT_POST_REQUEST_CODE = 2; - String mAccessToken; @State String mAccountName; @State - Post mPost; - @State - boolean isLoadingMoreChildren = false; - @State - boolean isRefreshing = false; - @State - boolean isSingleCommentThreadMode = false; - @State - ArrayList<Comment> comments; - @State - ArrayList<String> children; - @State - int mChildrenStartingIndex = 0; - @State - boolean loadMoreChildrenSuccess = true; - @State - boolean hasMoreChildren; - @State - boolean isFetchingComments = false; - @State - String mMessageFullname; - @State String mNewAccountName; - @State - String sortType; - @State - boolean mRespectSubredditRecommendedSortType; @BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout; @BindView(R.id.appbar_layout_view_post_detail_activity) AppBarLayout mAppBarLayout; @BindView(R.id.toolbar_view_post_detail_activity) Toolbar mToolbar; - @BindView(R.id.swipe_refresh_layout_view_post_detail_activity) - SwipeRefreshLayout mSwipeRefreshLayout; - @BindView(R.id.recycler_view_view_post_detail) - CustomToroContainer mRecyclerView; - @BindView(R.id.fetch_post_info_linear_layout_view_post_detail_activity) - LinearLayout mFetchPostInfoLinearLayout; - @BindView(R.id.fetch_post_info_image_view_view_post_detail_activity) - ImageView mFetchPostInfoImageView; - @BindView(R.id.fetch_post_info_text_view_view_post_detail_activity) - TextView mFetchPostInfoTextView; + @BindView(R.id.view_pager_2_view_post_detail_activity) + ViewPager2 viewPager2; @BindView(R.id.fab_view_post_detail_activity) FloatingActionButton fab; @Inject - @Named("no_oauth") - Retrofit mRetrofit; - @Inject - @Named("pushshift") - Retrofit pushshiftRetrofit; - @Inject - @Named("oauth") - Retrofit mOauthRetrofit; - @Inject - @Named("gfycat") - Retrofit mGfycatRetrofit; - @Inject - @Named("redgifs") - Retrofit mRedgifsRetrofit; - @Inject RedditDataRoomDatabase mRedditDataRoomDatabase; @Inject @Named("default") SharedPreferences mSharedPreferences; @Inject - @Named("sort_type") - SharedPreferences mSortTypeSharedPreferences; - @Inject - @Named("nsfw_and_spoiler") - SharedPreferences mNsfwAndSpoilerSharedPreferences; - @Inject @Named("current_account") SharedPreferences mCurrentAccountSharedPreferences; @Inject CustomThemeWrapper mCustomThemeWrapper; @Inject - ExoCreator mExoCreator; - @Inject Executor mExecutor; - private RequestManager mGlide; - private Locale mLocale; - private Menu mMenu; + @State + ArrayList<Post> posts; + @State + Post post; + private FragmentManager fragmentManager; + private SlidrInterface mSlidrInterface; + private SectionsPagerAdapter sectionsPagerAdapter; private int orientation; - private int postListPosition = -1; - private String mSingleCommentId; - private boolean showToast = false; - private boolean isSortingComments = false; private boolean mVolumeKeysNavigateComments; - private boolean mIsSmoothScrolling = false; - private boolean mLockFab; - private boolean mSwipeUpToHideFab; - private boolean mExpandChildren; - private int mWindowWidth; - private LinearLayoutManager mLinearLayoutManager; - private CommentAndPostRecyclerViewAdapter mAdapter; - private RecyclerView.SmoothScroller mSmoothScroller; - private PostCommentSortTypeBottomSheetFragment mPostCommentSortTypeBottomSheetFragment; - private SlidrInterface mSlidrInterface; - private Drawable mSavedIcon; - private Drawable mUnsavedIcon; - private ColorDrawable backgroundSwipeRight; - private ColorDrawable backgroundSwipeLeft; - private Drawable drawableSwipeRight; - private Drawable drawableSwipeLeft; - private int swipeLeftAction; - private int swipeRightAction; - private float swipeActionThreshold; - private ItemTouchHelper touchHelper; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -257,12 +127,9 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS applyCustomTheme(); - mSavedIcon = getMenuItemIcon(R.drawable.ic_bookmark_toolbar_24dp); - mUnsavedIcon = getMenuItemIcon(R.drawable.ic_bookmark_border_toolbar_24dp); - - if (mSharedPreferences.getBoolean(SharedPreferencesUtils.SWIPE_RIGHT_TO_GO_BACK, true)) { + /*if (mSharedPreferences.getBoolean(SharedPreferencesUtils.SWIPE_RIGHT_TO_GO_BACK, true)) { mSlidrInterface = Slidr.attach(this); - } + }*/ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Window window = getWindow(); @@ -286,288 +153,59 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); params.bottomMargin += navBarHeight; fab.setLayoutParams(params); - mRecyclerView.setPadding(0, 0, 0, navBarHeight + mRecyclerView.getPaddingBottom()); - showToast = true; } } } - DisplayMetrics displayMetrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - mWindowWidth = displayMetrics.widthPixels; + fragmentManager = getSupportFragmentManager(); - mToolbar.setTitle(""); - setSupportActionBar(mToolbar); - setToolbarGoToTop(mToolbar); - - mVolumeKeysNavigateComments = mSharedPreferences.getBoolean(SharedPreferencesUtils.VOLUME_KEYS_NAVIGATE_COMMENTS, false); - mLockFab = mSharedPreferences.getBoolean(SharedPreferencesUtils.LOCK_JUMP_TO_NEXT_TOP_LEVEL_COMMENT_BUTTON, false); - mSwipeUpToHideFab = mSharedPreferences.getBoolean(SharedPreferencesUtils.SWIPE_UP_TO_HIDE_JUMP_TO_NEXT_TOP_LEVEL_COMMENT_BUTTON, false); - mExpandChildren = !mSharedPreferences.getBoolean(SharedPreferencesUtils.SHOW_TOP_LEVEL_COMMENTS_FIRST, false); if (savedInstanceState == null) { - mRespectSubredditRecommendedSortType = mSharedPreferences.getBoolean(SharedPreferencesUtils.RESPECT_SUBREDDIT_RECOMMENDED_COMMENT_SORT_TYPE, false); + posts = getIntent().getParcelableArrayListExtra(EXTRA_POST_LIST); + post = getIntent().getParcelableExtra(EXTRA_POST_DATA); } - mGlide = Glide.with(this); - Resources resources = getResources(); - mLocale = getResources().getConfiguration().locale; - - mLinearLayoutManager = new LinearLayoutManager(this); - mRecyclerView.setLayoutManager(mLinearLayoutManager); - - if (children != null && children.size() > 0) { - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (!mIsSmoothScrolling && !mLockFab) { - if (!recyclerView.canScrollVertically(1)) { - fab.hide(); - } else { - if (dy > 0) { - if (mSwipeUpToHideFab) { - fab.show(); - } else { - fab.hide(); - } - } else { - if (mSwipeUpToHideFab) { - fab.hide(); - } else { - fab.show(); - } - } - } - } - - if (!isLoadingMoreChildren && loadMoreChildrenSuccess) { - int visibleItemCount = mLinearLayoutManager.getChildCount(); - int totalItemCount = mLinearLayoutManager.getItemCount(); - int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); - - if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { - fetchMoreComments(); - } - } - } + orientation = getResources().getConfiguration().orientation; - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - mIsSmoothScrolling = false; - } - } - }); - } else { - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (!mIsSmoothScrolling && !mLockFab) { - if (!recyclerView.canScrollVertically(1)) { - fab.hide(); - } else { - if (dy > 0) { - if (mSwipeUpToHideFab) { - fab.show(); - } else { - fab.hide(); - } - } else { - if (mSwipeUpToHideFab) { - fab.hide(); - } else { - fab.show(); - } - } - } - } - } - - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - mIsSmoothScrolling = false; - } - } - }); - } - - boolean enableSwipeAction = mSharedPreferences.getBoolean(SharedPreferencesUtils.ENABLE_SWIPE_ACTION, false); - boolean vibrateWhenActionTriggered = mSharedPreferences.getBoolean(SharedPreferencesUtils.VIBRATE_WHEN_ACTION_TRIGGERED, true); - swipeActionThreshold = Float.parseFloat(mSharedPreferences.getString(SharedPreferencesUtils.SWIPE_ACTION_THRESHOLD, "0.3")); - swipeRightAction = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.SWIPE_RIGHT_ACTION, "1")); - swipeLeftAction = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.SWIPE_LEFT_ACTION, "0")); - initializeSwipeActionDrawable(); - touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { - boolean exceedThreshold = false; - - @Override - public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { - if (!(viewHolder instanceof CommentAndPostRecyclerViewAdapter.CommentViewHolder)) { - return makeMovementFlags(0, 0); - } - int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; - return makeMovementFlags(0, swipeFlags); - } - - @Override - public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { - return false; - } - - @Override - public boolean isItemViewSwipeEnabled() { - return true; - } - - @Override - public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { - if (touchHelper != null) { - touchHelper.attachToRecyclerView(null); - touchHelper.attachToRecyclerView(mRecyclerView); - if (mAdapter != null) { - mAdapter.onItemSwipe(viewHolder, direction, swipeLeftAction, swipeRightAction); - } - } - } - - @Override - public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { - super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); - - View itemView = viewHolder.itemView; - int horizontalOffset = (int) Utils.convertDpToPixel(16, ViewPostDetailActivity.this); - if (dX > 0) { - if (dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { - if (!exceedThreshold) { - exceedThreshold = true; - if (vibrateWhenActionTriggered) { - viewHolder.itemView.setHapticFeedbackEnabled(true); - viewHolder.itemView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } - } - backgroundSwipeRight.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); - } else { - exceedThreshold = false; - backgroundSwipeRight.setBounds(0, 0, 0, 0); - } - - drawableSwipeRight.setBounds(itemView.getLeft() + ((int) dX) - horizontalOffset - drawableSwipeRight.getIntrinsicWidth(), - (itemView.getBottom() + itemView.getTop() - drawableSwipeRight.getIntrinsicHeight()) / 2, - itemView.getLeft() + ((int) dX) - horizontalOffset, - (itemView.getBottom() + itemView.getTop() + drawableSwipeRight.getIntrinsicHeight()) / 2); - backgroundSwipeRight.draw(c); - drawableSwipeRight.draw(c); - } else if (dX < 0) { - if (-dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { - if (!exceedThreshold) { - exceedThreshold = true; - if (vibrateWhenActionTriggered) { - viewHolder.itemView.setHapticFeedbackEnabled(true); - viewHolder.itemView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } - } - backgroundSwipeLeft.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); - } else { - exceedThreshold = false; - backgroundSwipeLeft.setBounds(0, 0, 0, 0); - } - drawableSwipeLeft.setBounds(itemView.getRight() + ((int) dX) + horizontalOffset, - (itemView.getBottom() + itemView.getTop() - drawableSwipeLeft.getIntrinsicHeight()) / 2, - itemView.getRight() + ((int) dX) + horizontalOffset + drawableSwipeLeft.getIntrinsicWidth(), - (itemView.getBottom() + itemView.getTop() + drawableSwipeLeft.getIntrinsicHeight()) / 2); - backgroundSwipeLeft.draw(c); - drawableSwipeLeft.draw(c); - } - } - - @Override - public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { - return swipeActionThreshold; - } - }); - - if (enableSwipeAction) { - touchHelper.attachToRecyclerView(mRecyclerView); - } - - mSwipeRefreshLayout.setOnRefreshListener(() -> refresh(true, true)); - - mSmoothScroller = new LinearSmoothScroller(this) { - @Override - protected int getVerticalSnapPreference() { - return LinearSmoothScroller.SNAP_TO_START; - } - }; + mToolbar.setTitle(""); + setSupportActionBar(mToolbar); + setToolbarGoToTop(mToolbar); - mSingleCommentId = getIntent().getStringExtra(EXTRA_SINGLE_COMMENT_ID); if (savedInstanceState == null) { - if (mSingleCommentId != null) { - isSingleCommentThreadMode = true; - } - mMessageFullname = getIntent().getStringExtra(EXTRA_MESSAGE_FULLNAME); mNewAccountName = getIntent().getStringExtra(EXTRA_NEW_ACCOUNT_NAME); - - if (!mRespectSubredditRecommendedSortType || isSingleCommentThreadMode) { - sortType = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, SortType.Type.BEST.value.toUpperCase()); - if (sortType != null) { - mToolbar.setTitle(new SortType(SortType.Type.valueOf(sortType)).getType().fullName); - sortType = sortType.toLowerCase(); - } - } - } else { - if (sortType != null) { - mToolbar.setTitle(new SortType(SortType.Type.valueOf(sortType.toUpperCase())).getType().fullName); - } } - orientation = resources.getConfiguration().orientation; - - mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null); mAccountName = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCOUNT_NAME, null); - checkNewAccountAndBindView(); + mVolumeKeysNavigateComments = mSharedPreferences.getBoolean(SharedPreferencesUtils.VOLUME_KEYS_NAVIGATE_COMMENTS, false); - if (getIntent().hasExtra(EXTRA_POST_LIST_POSITION)) { - postListPosition = getIntent().getIntExtra(EXTRA_POST_LIST_POSITION, -1); - } + fab.setOnClickListener(view -> { + if (sectionsPagerAdapter != null) { + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.scrollToNextParentComment(); + } + } + }); - mPostCommentSortTypeBottomSheetFragment = new PostCommentSortTypeBottomSheetFragment(); + checkNewAccountAndBindView(savedInstanceState); } - private void initializeSwipeActionDrawable() { - if (swipeRightAction == SharedPreferencesUtils.SWIPE_ACITON_DOWNVOTE) { - backgroundSwipeRight = new ColorDrawable(mCustomThemeWrapper.getDownvoted()); - drawableSwipeRight = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_downward_black_24dp, null); - } else { - backgroundSwipeRight = new ColorDrawable(mCustomThemeWrapper.getUpvoted()); - drawableSwipeRight = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_upward_black_24dp, null); + public void setTitle(String title) { + if (mToolbar != null) { + mToolbar.setTitle(title); } + } - if (swipeLeftAction == SharedPreferencesUtils.SWIPE_ACITON_UPVOTE) { - backgroundSwipeLeft = new ColorDrawable(mCustomThemeWrapper.getUpvoted()); - drawableSwipeLeft = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_upward_black_24dp, null); - } else { - backgroundSwipeLeft = new ColorDrawable(mCustomThemeWrapper.getDownvoted()); - drawableSwipeLeft = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_downward_black_24dp, null); - } + public void showFab() { + fab.show(); } - @Override - protected void onResume() { - super.onResume(); - if (mAdapter != null && mRecyclerView != null) { - mRecyclerView.onWindowVisibilityChanged(View.VISIBLE); - } + public void hideFab() { + fab.hide(); } - @Override - protected void onPause() { - super.onPause(); - if (mAdapter != null && mRecyclerView != null) { - mRecyclerView.onWindowVisibilityChanged(View.GONE); - } + public void showSnackBar(int resId) { + Snackbar.make(mCoordinatorLayout, resId, Snackbar.LENGTH_SHORT).show(); } @Override @@ -584,13 +222,10 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS protected void applyCustomTheme() { mCoordinatorLayout.setBackgroundColor(mCustomThemeWrapper.getBackgroundColor()); applyAppBarLayoutAndToolbarTheme(mAppBarLayout, mToolbar); - mSwipeRefreshLayout.setProgressBackgroundColorSchemeColor(mCustomThemeWrapper.getCircularProgressBarBackground()); - mSwipeRefreshLayout.setColorSchemeColors(mCustomThemeWrapper.getColorAccent()); - mFetchPostInfoTextView.setTextColor(mCustomThemeWrapper.getSecondaryTextColor()); applyFABTheme(fab); } - private void checkNewAccountAndBindView() { + private void checkNewAccountAndBindView(Bundle savedInstanceState) { if (mNewAccountName != null) { if (mAccountName == null || !mAccountName.equals(mNewAccountName)) { SwitchAccount.switchAccount(mRedditDataRoomDatabase, mCurrentAccountSharedPreferences, @@ -599,823 +234,58 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS Toast.makeText(this, R.string.account_switched, Toast.LENGTH_SHORT).show(); mNewAccountName = null; - if (newAccount != null) { - mAccessToken = newAccount.getAccessToken(); - mAccountName = newAccount.getAccountName(); - } - bindView(); + bindView(savedInstanceState); }); } else { - bindView(); + bindView(savedInstanceState); } } else { - bindView(); - } - } - - private void bindView() { - if (mAccessToken != null && mMessageFullname != null) { - ReadMessage.readMessage(mOauthRetrofit, mAccessToken, mMessageFullname, new ReadMessage.ReadMessageListener() { - @Override - public void readSuccess() { - mMessageFullname = null; - } - - @Override - public void readFailed() { - - } - }); - } - - if (mPost == null) { - mPost = getIntent().getParcelableExtra(EXTRA_POST_DATA); - } - - if (mPost == null) { - fetchPostAndCommentsById(getIntent().getStringExtra(EXTRA_POST_ID)); - } else { - setupMenu(); - - mAdapter = new CommentAndPostRecyclerViewAdapter(ViewPostDetailActivity.this, - mExecutor, mCustomThemeWrapper, mRetrofit, mOauthRetrofit, mGfycatRetrofit, - mRedgifsRetrofit, mRedditDataRoomDatabase, mGlide, - mWindowWidth, mAccessToken, mAccountName, mPost, mLocale, mSingleCommentId, - isSingleCommentThreadMode, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mExoCreator, - new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { - @Override - public void updatePost(Post post) { - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - - @Override - public void retryFetchingComments() { - fetchCommentsRespectRecommendedSort(false); - } - - @Override - public void retryFetchingMoreComments() { - isLoadingMoreChildren = false; - loadMoreChildrenSuccess = true; - - fetchMoreComments(); - } - }); - mRecyclerView.setAdapter(mAdapter); - - if (comments == null) { - fetchCommentsRespectRecommendedSort(false); - } else { - if (isRefreshing) { - isRefreshing = false; - refresh(true, true); - } else if (isFetchingComments) { - fetchCommentsRespectRecommendedSort(false); - } else { - mAdapter.addComments(comments, hasMoreChildren); - if (isLoadingMoreChildren) { - isLoadingMoreChildren = false; - fetchMoreComments(); - } - } - } + bindView(savedInstanceState); } - - mRecyclerView.setCacheManager(mAdapter); - mRecyclerView.setPlayerInitializer(order -> { - VolumeInfo volumeInfo = new VolumeInfo(true, 0f); - return new PlaybackInfo(INDEX_UNSET, TIME_UNSET, volumeInfo); - }); - - fab.setOnClickListener(view -> scrollToNextParentComment()); } - private void setupMenu() { - if (mMenu != null) { - MenuItem saveItem = mMenu.findItem(R.id.action_save_view_post_detail_activity); - MenuItem hideItem = mMenu.findItem(R.id.action_hide_view_post_detail_activity); - - mMenu.findItem(R.id.action_comment_view_post_detail_activity).setVisible(true); - mMenu.findItem(R.id.action_sort_view_post_detail_activity).setVisible(true); - - if (mAccessToken != null) { - if (mPost.isSaved()) { - saveItem.setVisible(true); - saveItem.setIcon(mSavedIcon); - } else { - saveItem.setVisible(true); - saveItem.setIcon(mUnsavedIcon); - } - - if (mPost.isHidden()) { - hideItem.setVisible(true); - hideItem.setTitle(R.string.action_unhide_post); - } else { - hideItem.setVisible(true); - hideItem.setTitle(R.string.action_hide_post); - } - } else { - saveItem.setVisible(false); - hideItem.setVisible(false); - } - - if (mPost.getAuthor().equals(mAccountName)) { - if (mPost.getPostType() == Post.TEXT_TYPE) { - mMenu.findItem(R.id.action_edit_view_post_detail_activity).setVisible(true); - } - mMenu.findItem(R.id.action_delete_view_post_detail_activity).setVisible(true); - - MenuItem nsfwItem = mMenu.findItem(R.id.action_nsfw_view_post_detail_activity); - nsfwItem.setVisible(true); - if (mPost.isNSFW()) { - nsfwItem.setTitle(R.string.action_unmark_nsfw); - } else { - nsfwItem.setTitle(R.string.action_mark_nsfw); - } - - MenuItem spoilerItem = mMenu.findItem(R.id.action_spoiler_view_post_detail_activity); - spoilerItem.setVisible(true); - if (mPost.isSpoiler()) { - spoilerItem.setTitle(R.string.action_unmark_spoiler); - } else { - spoilerItem.setTitle(R.string.action_mark_spoiler); - } - - mMenu.findItem(R.id.action_edit_flair_view_post_detail_activity).setVisible(true); - } - - mMenu.findItem(R.id.action_view_crosspost_parent_view_post_detail_activity).setVisible(mPost.getCrosspostParentId() != null); - - if ("[deleted]".equals(mPost.getAuthor()) || - "[deleted]".equals(mPost.getSelfText()) || - "[removed]".equals(mPost.getSelfText()) - ) { - mMenu.findItem(R.id.action_see_removed_view_post_detail_activity).setVisible(true); - } - } - } - - private Drawable getMenuItemIcon(int drawableId) { - Drawable icon = getDrawable(drawableId); - if (icon != null) { - DrawableCompat.setTint(icon, mCustomThemeWrapper.getToolbarPrimaryTextAndIconColor()); + private void bindView(Bundle savedInstanceState) { + sectionsPagerAdapter = new SectionsPagerAdapter(this); + viewPager2.setAdapter(sectionsPagerAdapter); + if (savedInstanceState == null) { + viewPager2.setCurrentItem(getIntent().getIntExtra(EXTRA_POST_LIST_POSITION, 0), false); } - - return icon; } - private void fetchPostAndCommentsById(String subredditId) { - mFetchPostInfoLinearLayout.setVisibility(View.GONE); - mSwipeRefreshLayout.setRefreshing(true); - mGlide.clear(mFetchPostInfoImageView); - - Call<String> postAndComments; - if (mAccessToken == null) { - if (isSingleCommentThreadMode && mSingleCommentId != null) { - postAndComments = mRetrofit.create(RedditAPI.class).getPostAndCommentsSingleThreadById( - subredditId, mSingleCommentId, sortType); - } else { - postAndComments = mRetrofit.create(RedditAPI.class).getPostAndCommentsById(subredditId, - sortType); - } - } else { - if (isSingleCommentThreadMode && mSingleCommentId != null) { - postAndComments = mOauthRetrofit.create(RedditAPI.class).getPostAndCommentsSingleThreadByIdOauth(subredditId, - mSingleCommentId, sortType, APIUtils.getOAuthHeader(mAccessToken)); - } else { - postAndComments = mOauthRetrofit.create(RedditAPI.class).getPostAndCommentsByIdOauth(subredditId, - sortType, APIUtils.getOAuthHeader(mAccessToken)); - } - } - postAndComments.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - mSwipeRefreshLayout.setRefreshing(false); - - if (response.isSuccessful()) { - ParsePost.parsePost(response.body(), new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(Post post) { - mPost = post; - - setupMenu(); - - mAdapter = new CommentAndPostRecyclerViewAdapter(ViewPostDetailActivity.this, - mExecutor, mCustomThemeWrapper, mRetrofit, mOauthRetrofit, mGfycatRetrofit, - mRedgifsRetrofit, mRedditDataRoomDatabase, mGlide, - mWindowWidth, mAccessToken, mAccountName, mPost, mLocale, - mSingleCommentId, isSingleCommentThreadMode, mSharedPreferences, - mNsfwAndSpoilerSharedPreferences, mExoCreator, - new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { - @Override - public void updatePost(Post post) { - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - - @Override - public void retryFetchingComments() { - fetchCommentsRespectRecommendedSort(false); - } - - @Override - public void retryFetchingMoreComments() { - isLoadingMoreChildren = false; - loadMoreChildrenSuccess = true; - - fetchMoreComments(); - } - }); - mRecyclerView.setAdapter(mAdapter); - - if (mRespectSubredditRecommendedSortType) { - fetchCommentsRespectRecommendedSort(false); - } else { - ParseComment.parseComment(response.body(), new ArrayList<>(), mLocale, - mExpandChildren, new ParseComment.ParseCommentListener() { - @Override - public void onParseCommentSuccess(ArrayList<Comment> expandedComments, String parentId, ArrayList<String> moreChildrenFullnames) { - ViewPostDetailActivity.this.children = moreChildrenFullnames; - - hasMoreChildren = children.size() != 0; - mAdapter.addComments(expandedComments, hasMoreChildren); - - if (children.size() > 0) { - mRecyclerView.clearOnScrollListeners(); - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (!mIsSmoothScrolling && !mLockFab) { - if (!recyclerView.canScrollVertically(1)) { - fab.hide(); - } else { - if (dy > 0) { - if (mSwipeUpToHideFab) { - fab.show(); - } else { - fab.hide(); - } - } else { - if (mSwipeUpToHideFab) { - fab.hide(); - } else { - fab.show(); - } - } - } - } - - if (!isLoadingMoreChildren && loadMoreChildrenSuccess) { - int visibleItemCount = mLinearLayoutManager.getChildCount(); - int totalItemCount = mLinearLayoutManager.getItemCount(); - int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); - - if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { - fetchMoreComments(); - } - } - } - - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - mIsSmoothScrolling = false; - } - } - }); - } - } - - @Override - public void onParseCommentFailed() { - mAdapter.initiallyLoadCommentsFailed(); - } - }); - } - } - - @Override - public void onParsePostFail() { - showErrorView(subredditId); - } - }); - } else { - showErrorView(subredditId); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - showErrorView(subredditId); + private void editComment(String commentAuthor, String commentContentMarkdown, int position) { + if (sectionsPagerAdapter != null) { + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.editComment(commentAuthor, commentContentMarkdown, position); } - }); - } - - private void fetchCommentsRespectRecommendedSort(boolean changeRefreshState, boolean checkSortState, String sortType) { - if (mRespectSubredditRecommendedSortType && mPost != null) { - FetchSubredditData.fetchSubredditData(mRetrofit, mPost.getSubredditName(), - new FetchSubredditData.FetchSubredditDataListener() { - @Override - public void onFetchSubredditDataSuccess(SubredditData subredditData, int nCurrentOnlineSubscribers) { - if (subredditData.getSuggestedCommentSort() == null || subredditData.getSuggestedCommentSort().equals("null") || subredditData.getSuggestedCommentSort().equals("")) { - mRespectSubredditRecommendedSortType = false; - ViewPostDetailActivity.this.sortType = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, SortType.Type.BEST.value.toUpperCase()); - if (ViewPostDetailActivity.this.sortType != null) { - mToolbar.setTitle(new SortType(SortType.Type.valueOf(ViewPostDetailActivity.this.sortType)).getType().fullName); - ViewPostDetailActivity.this.sortType = ViewPostDetailActivity.this.sortType.toLowerCase(); - } - fetchComments(changeRefreshState, checkSortState, ViewPostDetailActivity.this.sortType); - } else { - ViewPostDetailActivity.this.sortType = subredditData.getSuggestedCommentSort(); - String sortTypeTemp = ViewPostDetailActivity.this.sortType.toLowerCase().substring(0, 1).toUpperCase() + ViewPostDetailActivity.this.sortType.substring(1); - mToolbar.setTitle(sortTypeTemp); - fetchComments(changeRefreshState, checkSortState, subredditData.getSuggestedCommentSort()); - } - } - - @Override - public void onFetchSubredditDataFail() { - mRespectSubredditRecommendedSortType = false; - ViewPostDetailActivity.this.sortType = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, SortType.Type.BEST.value.toUpperCase()); - if (ViewPostDetailActivity.this.sortType != null) { - mToolbar.setTitle(new SortType(SortType.Type.valueOf(ViewPostDetailActivity.this.sortType)).getType().fullName); - ViewPostDetailActivity.this.sortType = ViewPostDetailActivity.this.sortType.toLowerCase(); - } - } - }); - } else { - fetchComments(changeRefreshState, checkSortState, sortType); - } - } - - private void fetchComments(boolean changeRefreshState, boolean checkSortState, String sortType) { - isFetchingComments = true; - mAdapter.setSingleComment(mSingleCommentId, isSingleCommentThreadMode); - mAdapter.initiallyLoading(); - String commentId = null; - if (isSingleCommentThreadMode) { - commentId = mSingleCommentId; - } - - Retrofit retrofit = mAccessToken == null ? mRetrofit : mOauthRetrofit; - FetchComment.fetchComments(retrofit, mAccessToken, mPost.getId(), commentId, sortType, mExpandChildren, - mLocale, new FetchComment.FetchCommentListener() { - @Override - public void onFetchCommentSuccess(ArrayList<Comment> expandedComments, - String parentId, ArrayList<String> children) { - if (checkSortState && isSortingComments) { - if (changeRefreshState) { - isRefreshing = false; - } - - return; - } - - ViewPostDetailActivity.this.children = children; - - comments = expandedComments; - hasMoreChildren = children.size() != 0; - mAdapter.addComments(expandedComments, hasMoreChildren); - - if (children.size() > 0) { - mRecyclerView.clearOnScrollListeners(); - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (!mIsSmoothScrolling && !mLockFab) { - if (!recyclerView.canScrollVertically(1)) { - fab.hide(); - } else { - if (dy > 0) { - if (mSwipeUpToHideFab) { - fab.show(); - } else { - fab.hide(); - } - } else { - if (mSwipeUpToHideFab) { - fab.hide(); - } else { - fab.show(); - } - } - } - } - - if (!isLoadingMoreChildren && loadMoreChildrenSuccess) { - int visibleItemCount = mLinearLayoutManager.getChildCount(); - int totalItemCount = mLinearLayoutManager.getItemCount(); - int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); - - if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { - fetchMoreComments(); - } - } - } - - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - mIsSmoothScrolling = false; - } - } - }); - } - if (changeRefreshState) { - isRefreshing = false; - } - - isFetchingComments = false; - } - - @Override - public void onFetchCommentFailed() { - isFetchingComments = false; - if (checkSortState && isSortingComments) { - if (changeRefreshState) { - isRefreshing = false; - } - - return; - } - - mAdapter.initiallyLoadCommentsFailed(); - if (changeRefreshState) { - isRefreshing = false; - } - } - }); - } - - private void fetchCommentsRespectRecommendedSort(boolean changeRefreshState) { - fetchCommentsRespectRecommendedSort(changeRefreshState, true, sortType); - } - - void fetchMoreComments() { - if (isFetchingComments || isLoadingMoreChildren || !loadMoreChildrenSuccess) { - return; } - - isLoadingMoreChildren = true; - - Retrofit retrofit = mAccessToken == null ? mRetrofit : mOauthRetrofit; - FetchComment.fetchMoreComment(retrofit, mAccessToken, children, mChildrenStartingIndex, - 0, mExpandChildren, mLocale, new FetchComment.FetchMoreCommentListener() { - @Override - public void onFetchMoreCommentSuccess(ArrayList<Comment> expandedComments, int childrenStartingIndex) { - hasMoreChildren = childrenStartingIndex < children.size(); - mAdapter.addComments(expandedComments, hasMoreChildren); - mChildrenStartingIndex = childrenStartingIndex; - isLoadingMoreChildren = false; - loadMoreChildrenSuccess = true; - } - - @Override - public void onFetchMoreCommentFailed() { - isLoadingMoreChildren = false; - loadMoreChildrenSuccess = false; - mAdapter.loadMoreCommentsFailed(); - } - }); } - private void refresh(boolean fetchPost, boolean fetchComments) { - if (mAdapter != null && !isRefreshing) { - isRefreshing = true; - mChildrenStartingIndex = 0; - - mFetchPostInfoLinearLayout.setVisibility(View.GONE); - mGlide.clear(mFetchPostInfoImageView); - - if (fetchComments) { - fetchCommentsRespectRecommendedSort(!fetchPost); - } - - if (fetchPost) { - Retrofit retrofit; - if (mAccessToken == null) { - retrofit = mRetrofit; - } else { - retrofit = mOauthRetrofit; - } - FetchPost.fetchPost(retrofit, mPost.getId(), mAccessToken, mLocale, - new FetchPost.FetchPostListener() { - @Override - public void fetchPostSuccess(Post post) { - mPost = post; - mAdapter.updatePost(mPost); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - isRefreshing = false; - setupMenu(); - mSwipeRefreshLayout.setRefreshing(false); - } - - @Override - public void fetchPostFailed() { - showMessage(R.string.refresh_post_failed); - isRefreshing = false; - } - }); + private void awardGiven(String awardsHTML, int awardCount, int position) { + if (sectionsPagerAdapter != null) { + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.awardGiven(awardsHTML, awardCount, position); } } } - private void showErrorView(String subredditId) { - mSwipeRefreshLayout.setRefreshing(false); - mFetchPostInfoLinearLayout.setVisibility(View.VISIBLE); - mFetchPostInfoLinearLayout.setOnClickListener(view -> fetchPostAndCommentsById(subredditId)); - mFetchPostInfoTextView.setText(R.string.load_post_error); - mGlide.load(R.drawable.error_image).into(mFetchPostInfoImageView); - } - - private void showMessage(int resId) { - if (showToast) { - Toast.makeText(ViewPostDetailActivity.this, resId, Toast.LENGTH_SHORT).show(); - } else { - Snackbar.make(mCoordinatorLayout, resId, Snackbar.LENGTH_SHORT).show(); - } - } - - private void markNSFW() { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_unmark_nsfw); - } - - Map<String, String> params = new HashMap<>(); - params.put(APIUtils.ID_KEY, mPost.getFullName()); - mOauthRetrofit.create(RedditAPI.class).markNSFW(APIUtils.getOAuthHeader(mAccessToken), params) - .enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_unmark_nsfw); - } - - refresh(true, false); - showMessage(R.string.mark_nsfw_success); - } else { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_mark_nsfw); - } - - showMessage(R.string.mark_nsfw_failed); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_mark_nsfw); - } - - showMessage(R.string.mark_nsfw_failed); - } - }); - } - - private void unmarkNSFW() { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_mark_nsfw); - } - - Map<String, String> params = new HashMap<>(); - params.put(APIUtils.ID_KEY, mPost.getFullName()); - mOauthRetrofit.create(RedditAPI.class).unmarkNSFW(APIUtils.getOAuthHeader(mAccessToken), params) - .enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_mark_nsfw); - } - - refresh(true, false); - showMessage(R.string.unmark_nsfw_success); - } else { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_unmark_nsfw); - } - - showMessage(R.string.unmark_nsfw_failed); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - if (mMenu != null) { - mMenu.findItem(R.id.action_nsfw_view_post_detail_activity).setTitle(R.string.action_unmark_nsfw); - } - - showMessage(R.string.unmark_nsfw_failed); - } - }); - } - - private void markSpoiler() { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_unmark_spoiler); - } - - Map<String, String> params = new HashMap<>(); - params.put(APIUtils.ID_KEY, mPost.getFullName()); - mOauthRetrofit.create(RedditAPI.class).markSpoiler(APIUtils.getOAuthHeader(mAccessToken), params) - .enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_unmark_spoiler); - } - - refresh(true, false); - showMessage(R.string.mark_spoiler_success); - } else { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_mark_spoiler); - } - - showMessage(R.string.mark_spoiler_failed); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_mark_spoiler); - } - - showMessage(R.string.mark_spoiler_failed); - } - }); - } - - private void unmarkSpoiler() { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_mark_spoiler); - } - - Map<String, String> params = new HashMap<>(); - params.put(APIUtils.ID_KEY, mPost.getFullName()); - mOauthRetrofit.create(RedditAPI.class).unmarkSpoiler(APIUtils.getOAuthHeader(mAccessToken), params) - .enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_mark_spoiler); - } - - refresh(true, false); - showMessage(R.string.unmark_spoiler_success); - } else { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_unmark_spoiler); - } - - showMessage(R.string.unmark_spoiler_failed); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - if (mMenu != null) { - mMenu.findItem(R.id.action_spoiler_view_post_detail_activity).setTitle(R.string.action_unmark_spoiler); - } - - showMessage(R.string.unmark_spoiler_failed); - } - }); - } - public void deleteComment(String fullName, int position) { - new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) - .setTitle(R.string.delete_this_comment) - .setMessage(R.string.are_you_sure) - .setPositiveButton(R.string.delete, (dialogInterface, i) - -> DeleteThing.delete(mOauthRetrofit, fullName, mAccessToken, new DeleteThing.DeleteThingListener() { - @Override - public void deleteSuccess() { - Toast.makeText(ViewPostDetailActivity.this, R.string.delete_post_success, Toast.LENGTH_SHORT).show(); - mAdapter.deleteComment(position); - } - - @Override - public void deleteFailed() { - Toast.makeText(ViewPostDetailActivity.this, R.string.delete_post_failed, Toast.LENGTH_SHORT).show(); - } - })) - .setNegativeButton(R.string.cancel, null) - .show(); - } - - public void showRemovedComment(Comment comment, int position) { - Toast.makeText(ViewPostDetailActivity.this, R.string.fetching_removed_comment, Toast.LENGTH_SHORT).show(); - FetchRemovedComment.fetchRemovedComment( - pushshiftRetrofit, - comment, - new FetchRemovedComment.FetchRemovedCommentListener() { - @Override - public void fetchSuccess(Comment comment) { - mAdapter.editComment(comment.getAuthor(), comment.getCommentMarkdown(), position); - } - - @Override - public void fetchFailed() { - Toast.makeText(ViewPostDetailActivity.this, R.string.show_removed_comment_failed, Toast.LENGTH_SHORT).show(); - } - }); - } - - public void changeToNomalThreadMode() { - isSingleCommentThreadMode = false; - mSingleCommentId = null; - mRespectSubredditRecommendedSortType = mSharedPreferences.getBoolean(SharedPreferencesUtils.RESPECT_SUBREDDIT_RECOMMENDED_COMMENT_SORT_TYPE, false); - refresh(false, true); - } - - public void scrollToNextParentComment() { - if (mLinearLayoutManager != null) { - int currentPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); - if (mAdapter != null) { - int nextParentPosition = mAdapter.getNextParentCommentPosition(currentPosition); - if (nextParentPosition < 0) { - return; - } - mSmoothScroller.setTargetPosition(nextParentPosition); - if (mLinearLayoutManager != null) { - mIsSmoothScrolling = true; - mLinearLayoutManager.startSmoothScroll(mSmoothScroller); - } + if (sectionsPagerAdapter != null) { + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.deleteComment(fullName, position); } } } - public void scrollToPreviousParentComment() { - if (mLinearLayoutManager != null) { - int currentPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); - if (mAdapter != null) { - int nextParentPosition = mAdapter.getPreviousParentCommentPosition(currentPosition); - if (nextParentPosition < 0) { - return; - } - mSmoothScroller.setTargetPosition(nextParentPosition); - if (mLinearLayoutManager != null) { - mIsSmoothScrolling = true; - mLinearLayoutManager.startSmoothScroll(mSmoothScroller); - } - } - } - } - - public void delayTransition() { - TransitionManager.beginDelayedTransition(mRecyclerView, new AutoTransition()); - } - - @Subscribe - public void onPostUpdateEvent(PostUpdateEventToDetailActivity event) { - if (mPost.getId().equals(event.post.getId())) { - mPost.setVoteType(event.post.getVoteType()); - mPost.setSaved(event.post.isSaved()); - if (mMenu != null) { - if (event.post.isSaved()) { - mMenu.findItem(R.id.action_save_view_post_detail_activity).setIcon(mSavedIcon); - } else { - mMenu.findItem(R.id.action_save_view_post_detail_activity).setIcon(mUnsavedIcon); - } + public void showRemovedComment(Comment comment, int position) { + if (sectionsPagerAdapter != null) { + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.showRemovedComment(comment, position); } - mAdapter.updatePost(mPost); - } - } - - @Subscribe - public void onChangeNSFWBlurEvent(ChangeNSFWBlurEvent event) { - mAdapter.setBlurNSFW(event.needBlurNSFW); - refreshAdapter(); - } - - @Subscribe - public void onChangeSpoilerBlurEvent(ChangeSpoilerBlurEvent event) { - mAdapter.setBlurSpoiler(event.needBlurSpoiler); - refreshAdapter(); - } - - private void refreshAdapter() { - int previousPosition = -1; - if (mLinearLayoutManager != null) { - previousPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); - } - - RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); - mRecyclerView.setAdapter(null); - mRecyclerView.setLayoutManager(null); - mRecyclerView.setAdapter(mAdapter); - mRecyclerView.setLayoutManager(layoutManager); - - if (previousPosition > 0) { - mRecyclerView.scrollToPosition(previousPosition); } } @@ -1426,271 +296,11 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS } } - @Subscribe - public void onChangeNetworkStatusEvent(ChangeNetworkStatusEvent changeNetworkStatusEvent) { - if (mAdapter != null) { - String autoplay = mSharedPreferences.getString(SharedPreferencesUtils.VIDEO_AUTOPLAY, SharedPreferencesUtils.VIDEO_AUTOPLAY_VALUE_NEVER); - String dataSavingMode = mSharedPreferences.getString(SharedPreferencesUtils.DATA_SAVING_MODE, SharedPreferencesUtils.DATA_SAVING_MODE_OFF); - boolean stateChanged = false; - if (autoplay.equals(SharedPreferencesUtils.VIDEO_AUTOPLAY_VALUE_ON_WIFI)) { - mAdapter.setAutoplay(changeNetworkStatusEvent.connectedNetwork == Utils.NETWORK_TYPE_WIFI); - stateChanged = true; - } - if (dataSavingMode.equals(SharedPreferencesUtils.DATA_SAVING_MODE_ONLY_ON_CELLULAR_DATA)) { - mAdapter.setDataSavingMode(changeNetworkStatusEvent.connectedNetwork == Utils.NETWORK_TYPE_CELLULAR); - stateChanged = true; - } - - if (stateChanged) { - refreshAdapter(); - } - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.view_post_detail_activity, menu); - applyMenuItemTheme(menu); - mMenu = menu; - if (mPost != null) { - setupMenu(); - } - return true; - } - - public void showRemovedPost() { - Toast.makeText(ViewPostDetailActivity.this, R.string.fetching_removed_post, Toast.LENGTH_SHORT).show(); - FetchRemovedPost.fetchRemovedPost( - pushshiftRetrofit, - mPost, - new FetchRemovedPost.FetchRemovedPostListener() { - @Override - public void fetchSuccess(Post post) { - mPost = post; - mAdapter.updatePost(post); - } - - @Override - public void fetchFailed() { - Toast.makeText(ViewPostDetailActivity.this, R.string.show_removed_post_failed, Toast.LENGTH_SHORT).show(); - } - }); - } - @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { - switch (item.getItemId()) { - case R.id.action_refresh_view_post_detail_activity: - refresh(true, true); - return true; - case R.id.action_comment_view_post_detail_activity: - if (mPost != null) { - if (mPost.isArchived()) { - showMessage(R.string.archived_post_reply_unavailable); - return true; - } - - if (mPost.isLocked()) { - showMessage(R.string.locked_post_comment_unavailable); - return true; - } - - if (mAccessToken == null) { - showMessage(R.string.login_first); - return true; - } - - Intent intent = new Intent(this, CommentActivity.class); - intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_MARKDOWN_KEY, mPost.getTitle()); - intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_BODY_MARKDOWN_KEY, mPost.getSelfText()); - intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_BODY_KEY, mPost.getSelfTextPlain()); - intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, mPost.getFullName()); - intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, 0); - intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, false); - startActivityForResult(intent, WRITE_COMMENT_REQUEST_CODE); - } - return true; - case R.id.action_save_view_post_detail_activity: - if (mPost != null && mAccessToken != null) { - if (mPost.isSaved()) { - item.setIcon(mUnsavedIcon); - SaveThing.unsaveThing(mOauthRetrofit, mAccessToken, mPost.getFullName(), - new SaveThing.SaveThingListener() { - @Override - public void success() { - mPost.setSaved(false); - item.setIcon(mUnsavedIcon); - showMessage(R.string.post_unsaved_success); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - - @Override - public void failed() { - mPost.setSaved(true); - item.setIcon(mSavedIcon); - showMessage(R.string.post_unsaved_failed); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - }); - } else { - item.setIcon(mSavedIcon); - SaveThing.saveThing(mOauthRetrofit, mAccessToken, mPost.getFullName(), - new SaveThing.SaveThingListener() { - @Override - public void success() { - mPost.setSaved(true); - item.setIcon(mSavedIcon); - showMessage(R.string.post_saved_success); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - - @Override - public void failed() { - mPost.setSaved(false); - item.setIcon(mUnsavedIcon); - showMessage(R.string.post_saved_failed); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - }); - } - } - return true; - case R.id.action_sort_view_post_detail_activity: - if (mPost != null) { - mPostCommentSortTypeBottomSheetFragment.show(getSupportFragmentManager(), mPostCommentSortTypeBottomSheetFragment.getTag()); - } - return true; - case R.id.action_view_crosspost_parent_view_post_detail_activity: - Intent crosspostIntent = new Intent(this, ViewPostDetailActivity.class); - crosspostIntent.putExtra(ViewPostDetailActivity.EXTRA_POST_ID, mPost.getCrosspostParentId()); - startActivity(crosspostIntent); - return true; - case R.id.action_hide_view_post_detail_activity: - if (mPost != null && mAccessToken != null) { - if (mPost.isHidden()) { - item.setTitle(R.string.action_hide_post); - - HidePost.unhidePost(mOauthRetrofit, mAccessToken, mPost.getFullName(), new HidePost.HidePostListener() { - @Override - public void success() { - mPost.setHidden(false); - item.setTitle(R.string.action_hide_post); - showMessage(R.string.post_unhide_success); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - - @Override - public void failed() { - mPost.setHidden(true); - item.setTitle(R.string.action_unhide_post); - showMessage(R.string.post_unhide_failed); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - }); - } else { - item.setTitle(R.string.action_unhide_post); - - HidePost.hidePost(mOauthRetrofit, mAccessToken, mPost.getFullName(), new HidePost.HidePostListener() { - @Override - public void success() { - mPost.setHidden(true); - item.setTitle(R.string.action_unhide_post); - showMessage(R.string.post_hide_success); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - - @Override - public void failed() { - mPost.setHidden(false); - item.setTitle(R.string.action_hide_post); - showMessage(R.string.post_hide_failed); - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } - }); - } - } - return true; - case R.id.action_edit_view_post_detail_activity: - Intent editPostIntent = new Intent(this, EditPostActivity.class); - editPostIntent.putExtra(EditPostActivity.EXTRA_FULLNAME, mPost.getFullName()); - editPostIntent.putExtra(EditPostActivity.EXTRA_TITLE, mPost.getTitle()); - editPostIntent.putExtra(EditPostActivity.EXTRA_CONTENT, mPost.getSelfText()); - startActivityForResult(editPostIntent, EDIT_POST_REQUEST_CODE); - return true; - case R.id.action_delete_view_post_detail_activity: - new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) - .setTitle(R.string.delete_this_post) - .setMessage(R.string.are_you_sure) - .setPositiveButton(R.string.delete, (dialogInterface, i) - -> DeleteThing.delete(mOauthRetrofit, mPost.getFullName(), mAccessToken, new DeleteThing.DeleteThingListener() { - @Override - public void deleteSuccess() { - Toast.makeText(ViewPostDetailActivity.this, R.string.delete_post_success, Toast.LENGTH_SHORT).show(); - finish(); - } - - @Override - public void deleteFailed() { - showMessage(R.string.delete_post_failed); - } - })) - .setNegativeButton(R.string.cancel, null) - .show(); - return true; - case R.id.action_nsfw_view_post_detail_activity: - if (mPost.isNSFW()) { - unmarkNSFW(); - } else { - markNSFW(); - } - return true; - case R.id.action_spoiler_view_post_detail_activity: - if (mPost.isSpoiler()) { - unmarkSpoiler(); - } else { - markSpoiler(); - } - return true; - case R.id.action_edit_flair_view_post_detail_activity: - FlairBottomSheetFragment flairBottomSheetFragment = new FlairBottomSheetFragment(); - Bundle bundle = new Bundle(); - bundle.putString(FlairBottomSheetFragment.EXTRA_ACCESS_TOKEN, mAccessToken); - bundle.putString(FlairBottomSheetFragment.EXTRA_SUBREDDIT_NAME, mPost.getSubredditName()); - flairBottomSheetFragment.setArguments(bundle); - flairBottomSheetFragment.show(getSupportFragmentManager(), flairBottomSheetFragment.getTag()); - return true; - case R.id.action_give_award_view_post_detail_activity: - if (mAccessToken == null) { - Toast.makeText(this, R.string.login_first, Toast.LENGTH_SHORT).show(); - return true; - } - - Intent giveAwardIntent = new Intent(this, GiveAwardActivity.class); - giveAwardIntent.putExtra(GiveAwardActivity.EXTRA_THING_FULLNAME, mPost.getFullName()); - giveAwardIntent.putExtra(GiveAwardActivity.EXTRA_ITEM_POSITION, 0); - startActivityForResult(giveAwardIntent, GIVE_AWARD_REQUEST_CODE); - return true; - case R.id.action_report_view_post_detail_activity: - if (mAccessToken == null) { - Toast.makeText(this, R.string.login_first, Toast.LENGTH_SHORT).show(); - return true; - } - Intent intent = new Intent(this, ReportActivity.class); - intent.putExtra(ReportActivity.EXTRA_SUBREDDIT_NAME, mPost.getSubredditName()); - intent.putExtra(ReportActivity.EXTRA_THING_FULLNAME, mPost.getFullName()); - startActivity(intent); - return true; - case R.id.action_see_removed_view_post_detail_activity: - showRemovedPost(); - return true; - case R.id.action_crosspost_view_post_detail_activity: - Intent submitCrosspostIntent = new Intent(this, SubmitCrosspostActivity.class); - submitCrosspostIntent.putExtra(SubmitCrosspostActivity.EXTRA_POST, mPost); - startActivity(submitCrosspostIntent); - return true; - case android.R.id.home: - onBackPressed(); - return true; + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; } return false; } @@ -1698,42 +308,19 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == WRITE_COMMENT_REQUEST_CODE) { - if (data != null && resultCode == RESULT_OK) { - if (data.hasExtra(RETURN_EXTRA_COMMENT_DATA_KEY)) { - Comment comment = data.getParcelableExtra(RETURN_EXTRA_COMMENT_DATA_KEY); - if (comment != null && comment.getDepth() == 0) { - mAdapter.addComment(comment); - } else { - String parentFullname = data.getStringExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY); - int parentPosition = data.getIntExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, -1); - if (parentFullname != null && parentPosition >= 0) { - mAdapter.addChildComment(comment, parentFullname, parentPosition); - } - } - } else { - Toast.makeText(this, R.string.send_comment_failed, Toast.LENGTH_SHORT).show(); - } - } - } else if (requestCode == EDIT_POST_REQUEST_CODE) { - if (resultCode == RESULT_OK) { - refresh(true, false); - } - } else if (requestCode == EDIT_COMMENT_REQUEST_CODE) { - if (data != null && resultCode == RESULT_OK) { - mAdapter.editComment(null, + if (requestCode == EDIT_COMMENT_REQUEST_CODE) { + if (data != null && resultCode == Activity.RESULT_OK) { + editComment(null, data.getStringExtra(EditCommentActivity.EXTRA_EDITED_COMMENT_CONTENT), data.getExtras().getInt(EditCommentActivity.EXTRA_EDITED_COMMENT_POSITION)); } } else if (requestCode == GIVE_AWARD_REQUEST_CODE) { - if (data != null && resultCode == RESULT_OK) { + if (data != null && resultCode == Activity.RESULT_OK) { Toast.makeText(this, R.string.give_award_success, Toast.LENGTH_SHORT).show(); int position = data.getIntExtra(GiveAwardActivity.EXTRA_RETURN_ITEM_POSITION, 0); String newAwardsHTML = data.getStringExtra(GiveAwardActivity.EXTRA_RETURN_NEW_AWARDS); int newAwardsCount = data.getIntExtra(GiveAwardActivity.EXTRA_RETURN_NEW_AWARDS_COUNT, 0); - if (mAdapter != null) { - mAdapter.giveAward(newAwardsHTML, newAwardsCount, position); - } + awardGiven(newAwardsHTML, newAwardsCount, position); } } } @@ -1741,7 +328,6 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); - comments = mAdapter == null ? null : mAdapter.getVisibleComments(); Bridge.saveInstanceState(this, outState); } @@ -1765,13 +351,16 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mVolumeKeysNavigateComments) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - scrollToPreviousParentComment(); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - scrollToNextParentComment(); - return true; + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + fragment.scrollToPreviousParentComment(); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + fragment.scrollToNextParentComment(); + return true; + } } } return super.onKeyDown(keyCode, event); @@ -1779,46 +368,19 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS @Override public void flairSelected(Flair flair) { - Map<String, String> params = new HashMap<>(); - params.put(APIUtils.API_TYPE_KEY, APIUtils.API_TYPE_JSON); - params.put(APIUtils.FLAIR_TEMPLATE_ID_KEY, flair.getId()); - params.put(APIUtils.LINK_KEY, mPost.getFullName()); - params.put(APIUtils.TEXT_KEY, flair.getText()); - - mOauthRetrofit.create(RedditAPI.class).selectFlair(mPost.getSubredditNamePrefixed(), - APIUtils.getOAuthHeader(mAccessToken), params).enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - refresh(true, false); - showMessage(R.string.update_flair_success); - } else { - showMessage(R.string.update_flair_failed); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - showMessage(R.string.update_flair_failed); - } - }); + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.changeFlair(flair); + } } @Override public void sortTypeSelected(SortType sortType) { - mFetchPostInfoLinearLayout.setVisibility(View.GONE); - mGlide.clear(mFetchPostInfoImageView); - mChildrenStartingIndex = 0; - if (children != null) { - children.clear(); - } - this.sortType = sortType.getType().value; - if (!mSharedPreferences.getBoolean(SharedPreferencesUtils.RESPECT_SUBREDDIT_RECOMMENDED_COMMENT_SORT_TYPE, false)) { - mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, sortType.getType().name()).apply(); + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.changeSortType(sortType); + mToolbar.setTitle(sortType.getType().fullName); } - fetchCommentsRespectRecommendedSort(false, false, sortType.getType().value); - - mToolbar.setTitle(sortType.getType().fullName); } public void lockSwipeRightToGoBack() { @@ -1835,8 +397,51 @@ public class ViewPostDetailActivity extends BaseActivity implements FlairBottomS @Override public void onLongPress() { - if (mLinearLayoutManager != null) { - mLinearLayoutManager.scrollToPositionWithOffset(0, 0); + ViewPostDetailFragment fragment = sectionsPagerAdapter.getCurrentFragment(); + if (fragment != null) { + fragment.goToTop(); + } + } + + private class SectionsPagerAdapter extends FragmentStateAdapter { + + public SectionsPagerAdapter(@NonNull FragmentActivity fragmentActivity) { + super(fragmentActivity); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + ViewPostDetailFragment fragment = new ViewPostDetailFragment(); + Bundle bundle = new Bundle(); + if (posts != null) { + bundle.putParcelable(ViewPostDetailFragment.EXTRA_POST_DATA, posts.get(position)); + } else { + if (post == null) { + bundle.putString(ViewPostDetailFragment.EXTRA_POST_ID, getIntent().getStringExtra(EXTRA_POST_ID)); + } else { + bundle.putParcelable(ViewPostDetailFragment.EXTRA_POST_DATA, post); + } + } + fragment.setArguments(bundle); + return fragment; + } + + @Override + public int getItemCount() { + return posts == null ? 1 : posts.size(); + } + + @Nullable + ViewPostDetailFragment getCurrentFragment() { + if (viewPager2 == null || fragmentManager == null) { + return null; + } + Fragment fragment = fragmentManager.findFragmentByTag("f" + viewPager2.getCurrentItem()); + if (fragment instanceof PostFragment) { + return (ViewPostDetailFragment) fragment; + } + return null; } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentAndPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentAndPostRecyclerViewAdapter.java index 0d4569ca..11a9df06 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentAndPostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentAndPostRecyclerViewAdapter.java @@ -113,6 +113,7 @@ import ml.docilealligator.infinityforreddit.comment.FetchComment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.customviews.AspectRatioGifImageView; import ml.docilealligator.infinityforreddit.customviews.MarkwonLinearLayoutManager; +import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment; import ml.docilealligator.infinityforreddit.post.Post; import ml.docilealligator.infinityforreddit.post.PostDataSource; import ml.docilealligator.infinityforreddit.utils.APIUtils; @@ -143,6 +144,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy private static final int VIEW_TYPE_VIEW_ALL_COMMENTS = 17; private AppCompatActivity mActivity; + private ViewPostDetailFragment mFragment; private Executor mExecutor; private Retrofit mRetrofit; private Retrofit mOauthRetrofit; @@ -238,7 +240,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy private float mScale; private ExoCreator mExoCreator; - public CommentAndPostRecyclerViewAdapter(AppCompatActivity activity, Executor executor, CustomThemeWrapper customThemeWrapper, + public CommentAndPostRecyclerViewAdapter(AppCompatActivity activity, ViewPostDetailFragment fragment, Executor executor, CustomThemeWrapper customThemeWrapper, Retrofit retrofit, Retrofit oauthRetrofit, Retrofit gfycatRetrofit, Retrofit redgifsRetrofit, RedditDataRoomDatabase redditDataRoomDatabase, RequestManager glide, @@ -249,6 +251,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy SharedPreferences nsfwAndSpoilerSharedPreferences, ExoCreator exoCreator, CommentRecyclerViewAdapterCallback commentRecyclerViewAdapterCallback) { mActivity = activity; + mFragment = fragment; mExecutor = executor; mRetrofit = retrofit; mOauthRetrofit = oauthRetrofit; @@ -3765,9 +3768,9 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy if (bottomConstraintLayout.getLayoutParams().height == 0) { bottomConstraintLayout.getLayoutParams().height = LinearLayout.LayoutParams.WRAP_CONTENT; topScoreTextView.setVisibility(View.GONE); - ((ViewPostDetailActivity) mActivity).delayTransition(); + mFragment.delayTransition(); } else { - ((ViewPostDetailActivity) mActivity).delayTransition(); + mFragment.delayTransition(); bottomConstraintLayout.getLayoutParams().height = 0; topScoreTextView.setVisibility(View.VISIBLE); } @@ -3944,7 +3947,7 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy if (mActivity != null && mActivity instanceof ViewPostDetailActivity) { mIsSingleCommentThreadMode = false; mSingleCommentId = null; - ((ViewPostDetailActivity) mActivity).changeToNomalThreadMode(); + mFragment.changeToNomalThreadMode(); } }); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java index 515d0552..60043539 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostRecyclerViewAdapter.java @@ -92,6 +92,7 @@ import ml.docilealligator.infinityforreddit.bottomsheetfragments.ShareLinkBottom import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.customviews.AspectRatioGifImageView; import ml.docilealligator.infinityforreddit.events.PostUpdateEventToDetailActivity; +import ml.docilealligator.infinityforreddit.fragments.PostFragment; import ml.docilealligator.infinityforreddit.post.Post; import ml.docilealligator.infinityforreddit.post.PostDataSource; import ml.docilealligator.infinityforreddit.user.UserDao; @@ -128,6 +129,7 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView } }; private AppCompatActivity mActivity; + private PostFragment mFragment; private Executor mExecutor; private Retrofit mOauthRetrofit; private Retrofit mRetrofit; @@ -207,7 +209,7 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView private ExoCreator mExoCreator; private Callback mCallback; - public PostRecyclerViewAdapter(AppCompatActivity activity, Executor executor, Retrofit oauthRetrofit, Retrofit retrofit, + public PostRecyclerViewAdapter(AppCompatActivity activity, PostFragment fragment, Executor executor, Retrofit oauthRetrofit, Retrofit retrofit, Retrofit gfycatRetrofit, Retrofit redgifsRetrofit, RedditDataRoomDatabase redditDataRoomDatabase, CustomThemeWrapper customThemeWrapper, Locale locale, int imageViewWidth, @@ -218,6 +220,7 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView super(DIFF_CALLBACK); if (activity != null) { mActivity = activity; + mFragment = fragment; mExecutor = executor; mOauthRetrofit = oauthRetrofit; mRetrofit = retrofit; @@ -1629,7 +1632,7 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView canStartActivity = false; Intent intent = new Intent(mActivity, ViewPostDetailActivity.class); - intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, post); + intent.putExtra(ViewPostDetailActivity.EXTRA_POST_LIST, mFragment.getPostList()); intent.putExtra(ViewPostDetailActivity.EXTRA_POST_LIST_POSITION, getAdapterPosition()); mActivity.startActivity(intent); } @@ -2645,7 +2648,7 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView canStartActivity = false; Intent intent = new Intent(mActivity, ViewPostDetailActivity.class); - intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, post); + intent.putExtra(ViewPostDetailActivity.EXTRA_POST_LIST, mFragment.getPostList()); intent.putExtra(ViewPostDetailActivity.EXTRA_POST_LIST_POSITION, getAdapterPosition()); mActivity.startActivity(intent); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java index 90b1a798..eb69cbee 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/PostFragment.java @@ -437,7 +437,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { sortType = new SortType(SortType.Type.valueOf(sort), SortType.Time.valueOf(sortTime)); postLayout = mPostLayoutSharedPreferences.getInt(SharedPreferencesUtils.POST_LAYOUT_SEARCH_POST, defaultPostLayout); - mAdapter = new PostRecyclerViewAdapter(activity, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, + mAdapter = new PostRecyclerViewAdapter(activity, this, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, mRedgifsRetrofit, mRedditDataRoomDatabase, mCustomThemeWrapper, locale, windowWidth, accessToken, accountName, postType, postLayout, true, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mPostHistorySharedPreferences, @@ -503,7 +503,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { sortType = new SortType(SortType.Type.valueOf(sort)); } - mAdapter = new PostRecyclerViewAdapter(activity, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, + mAdapter = new PostRecyclerViewAdapter(activity, this, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, mRedgifsRetrofit, mRedditDataRoomDatabase, mCustomThemeWrapper, locale, windowWidth, accessToken, accountName, postType, postLayout, displaySubredditName, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mPostHistorySharedPreferences, @@ -567,7 +567,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { sortType = new SortType(SortType.Type.valueOf(sort)); } - mAdapter = new PostRecyclerViewAdapter(activity, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, + mAdapter = new PostRecyclerViewAdapter(activity, this, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, mRedgifsRetrofit, mRedditDataRoomDatabase, mCustomThemeWrapper, locale, windowWidth, accessToken, accountName, postType, postLayout, true, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mPostHistorySharedPreferences, @@ -631,7 +631,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } postLayout = mPostLayoutSharedPreferences.getInt(SharedPreferencesUtils.POST_LAYOUT_USER_POST_BASE + username, defaultPostLayout); - mAdapter = new PostRecyclerViewAdapter(activity, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, + mAdapter = new PostRecyclerViewAdapter(activity, this, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, mRedgifsRetrofit, mRedditDataRoomDatabase, mCustomThemeWrapper, locale, windowWidth, accessToken, accountName, postType, postLayout, true, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mPostHistorySharedPreferences, @@ -686,7 +686,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } postLayout = mPostLayoutSharedPreferences.getInt(SharedPreferencesUtils.POST_LAYOUT_FRONT_PAGE_POST, defaultPostLayout); - mAdapter = new PostRecyclerViewAdapter(activity, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, + mAdapter = new PostRecyclerViewAdapter(activity, this, mExecutor, mOauthRetrofit, mRetrofit, mGfycatRetrofit, mRedgifsRetrofit, mRedditDataRoomDatabase, mCustomThemeWrapper, locale, windowWidth, accessToken, accountName, postType, postLayout, true, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mPostHistorySharedPreferences, @@ -1061,6 +1061,10 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } } + public ArrayList<Post> getPostList() { + return new ArrayList<>(mPostViewModel.getPosts().getValue()); + } + @Override public void onAttach(@NonNull Context context) { super.onAttach(context); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewPostDetailFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewPostDetailFragment.java new file mode 100644 index 00000000..18b95b8b --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewPostDetailFragment.java @@ -0,0 +1,1739 @@ +package ml.docilealligator.infinityforreddit.fragments; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.HapticFeedbackConstants; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.view.menu.MenuItemImpl; +import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import androidx.transition.AutoTransition; +import androidx.transition.TransitionManager; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; +import com.evernote.android.state.State; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.livefront.bridge.Bridge; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.Executor; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import im.ene.toro.exoplayer.ExoCreator; +import im.ene.toro.media.PlaybackInfo; +import im.ene.toro.media.VolumeInfo; +import ml.docilealligator.infinityforreddit.DeleteThing; +import ml.docilealligator.infinityforreddit.Flair; +import ml.docilealligator.infinityforreddit.FragmentCommunicator; +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; +import ml.docilealligator.infinityforreddit.SaveThing; +import ml.docilealligator.infinityforreddit.SortType; +import ml.docilealligator.infinityforreddit.activities.CommentActivity; +import ml.docilealligator.infinityforreddit.activities.EditPostActivity; +import ml.docilealligator.infinityforreddit.activities.GiveAwardActivity; +import ml.docilealligator.infinityforreddit.activities.ReportActivity; +import ml.docilealligator.infinityforreddit.activities.SubmitCrosspostActivity; +import ml.docilealligator.infinityforreddit.activities.ViewPostDetailActivity; +import ml.docilealligator.infinityforreddit.adapters.CommentAndPostRecyclerViewAdapter; +import ml.docilealligator.infinityforreddit.apis.RedditAPI; +import ml.docilealligator.infinityforreddit.bottomsheetfragments.FlairBottomSheetFragment; +import ml.docilealligator.infinityforreddit.bottomsheetfragments.PostCommentSortTypeBottomSheetFragment; +import ml.docilealligator.infinityforreddit.comment.Comment; +import ml.docilealligator.infinityforreddit.comment.FetchComment; +import ml.docilealligator.infinityforreddit.comment.FetchRemovedComment; +import ml.docilealligator.infinityforreddit.comment.ParseComment; +import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; +import ml.docilealligator.infinityforreddit.customviews.CustomToroContainer; +import ml.docilealligator.infinityforreddit.events.ChangeNSFWBlurEvent; +import ml.docilealligator.infinityforreddit.events.ChangeNetworkStatusEvent; +import ml.docilealligator.infinityforreddit.events.ChangeSpoilerBlurEvent; +import ml.docilealligator.infinityforreddit.events.PostUpdateEventToDetailActivity; +import ml.docilealligator.infinityforreddit.events.PostUpdateEventToPostList; +import ml.docilealligator.infinityforreddit.message.ReadMessage; +import ml.docilealligator.infinityforreddit.post.FetchPost; +import ml.docilealligator.infinityforreddit.post.FetchRemovedPost; +import ml.docilealligator.infinityforreddit.post.HidePost; +import ml.docilealligator.infinityforreddit.post.ParsePost; +import ml.docilealligator.infinityforreddit.post.Post; +import ml.docilealligator.infinityforreddit.subreddit.FetchSubredditData; +import ml.docilealligator.infinityforreddit.subreddit.SubredditData; +import ml.docilealligator.infinityforreddit.utils.APIUtils; +import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; +import ml.docilealligator.infinityforreddit.utils.Utils; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +import static im.ene.toro.media.PlaybackInfo.INDEX_UNSET; +import static im.ene.toro.media.PlaybackInfo.TIME_UNSET; +import static ml.docilealligator.infinityforreddit.activities.CommentActivity.RETURN_EXTRA_COMMENT_DATA_KEY; +import static ml.docilealligator.infinityforreddit.activities.CommentActivity.WRITE_COMMENT_REQUEST_CODE; + +public class ViewPostDetailFragment extends Fragment implements FragmentCommunicator { + + public static final String EXTRA_POST_DATA = "EPD"; + public static final String EXTRA_POST_ID = "EPI"; + public static final String EXTRA_SINGLE_COMMENT_ID = "ESCI"; + public static final String EXTRA_MESSAGE_FULLNAME = "EMF"; + public static final String EXTRA_POST_LIST_POSITION = "EPLP"; + private static final int EDIT_POST_REQUEST_CODE = 2; + + @BindView(R.id.swipe_refresh_layout_view_post_detail_fragment) + SwipeRefreshLayout mSwipeRefreshLayout; + @BindView(R.id.recycler_view_view_post_detail_fragment) + CustomToroContainer mRecyclerView; + @BindView(R.id.fetch_post_info_linear_layout_view_post_detail_fragment) + LinearLayout mFetchPostInfoLinearLayout; + @BindView(R.id.fetch_post_info_image_view_view_post_detail_fragment) + ImageView mFetchPostInfoImageView; + @BindView(R.id.fetch_post_info_text_view_view_post_detail_fragment) + TextView mFetchPostInfoTextView; + @Inject + @Named("no_oauth") + Retrofit mRetrofit; + @Inject + @Named("pushshift") + Retrofit pushshiftRetrofit; + @Inject + @Named("oauth") + Retrofit mOauthRetrofit; + @Inject + @Named("gfycat") + Retrofit mGfycatRetrofit; + @Inject + @Named("redgifs") + Retrofit mRedgifsRetrofit; + @Inject + RedditDataRoomDatabase mRedditDataRoomDatabase; + @Inject + @Named("default") + SharedPreferences mSharedPreferences; + @Inject + @Named("sort_type") + SharedPreferences mSortTypeSharedPreferences; + @Inject + @Named("nsfw_and_spoiler") + SharedPreferences mNsfwAndSpoilerSharedPreferences; + @Inject + @Named("current_account") + SharedPreferences mCurrentAccountSharedPreferences; + @Inject + CustomThemeWrapper mCustomThemeWrapper; + @Inject + ExoCreator mExoCreator; + @Inject + Executor mExecutor; + @State + Post mPost; + @State + boolean isLoadingMoreChildren = false; + @State + boolean isRefreshing = false; + @State + boolean isSingleCommentThreadMode = false; + @State + ArrayList<Comment> comments; + @State + ArrayList<String> children; + @State + int mChildrenStartingIndex = 0; + @State + boolean loadMoreChildrenSuccess = true; + @State + boolean hasMoreChildren; + @State + boolean isFetchingComments = false; + @State + String mMessageFullname; + @State + String sortType; + @State + boolean mRespectSubredditRecommendedSortType; + private ViewPostDetailActivity activity; + private RequestManager mGlide; + private Locale mLocale; + private Menu mMenu; + private String mAccessToken; + private String mAccountName; + private int postListPosition = -1; + private String mSingleCommentId; + private boolean showToast = false; + private boolean isSortingComments = false; + private boolean mIsSmoothScrolling = false; + private boolean mLockFab; + private boolean mSwipeUpToHideFab; + private boolean mExpandChildren; + private int mWindowWidth; + private LinearLayoutManager mLinearLayoutManager; + private CommentAndPostRecyclerViewAdapter mAdapter; + private RecyclerView.SmoothScroller mSmoothScroller; + private Drawable mSavedIcon; + private Drawable mUnsavedIcon; + private ColorDrawable backgroundSwipeRight; + private ColorDrawable backgroundSwipeLeft; + private Drawable drawableSwipeRight; + private Drawable drawableSwipeLeft; + private int swipeLeftAction; + private int swipeRightAction; + private float swipeActionThreshold; + private ItemTouchHelper touchHelper; + + public ViewPostDetailFragment() { + // 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_view_post_detail, container, false); + + ((Infinity) activity.getApplication()).getAppComponent().inject(this); + + setHasOptionsMenu(true); + + Bridge.restoreInstanceState(this, savedInstanceState); + + ButterKnife.bind(this, rootView); + + EventBus.getDefault().register(this); + + applyTheme(); + + mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null); + mAccountName = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCOUNT_NAME, null); + + mSavedIcon = getMenuItemIcon(R.drawable.ic_bookmark_toolbar_24dp); + mUnsavedIcon = getMenuItemIcon(R.drawable.ic_bookmark_border_toolbar_24dp); + + if (activity != null && activity.isImmersiveInterface()) { + mRecyclerView.setPadding(0, 0, 0, activity.getNavBarHeight() + mRecyclerView.getPaddingBottom()); + showToast = true; + } + + DisplayMetrics displayMetrics = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + mWindowWidth = displayMetrics.widthPixels; + + mLockFab = mSharedPreferences.getBoolean(SharedPreferencesUtils.LOCK_JUMP_TO_NEXT_TOP_LEVEL_COMMENT_BUTTON, false); + mSwipeUpToHideFab = mSharedPreferences.getBoolean(SharedPreferencesUtils.SWIPE_UP_TO_HIDE_JUMP_TO_NEXT_TOP_LEVEL_COMMENT_BUTTON, false); + mExpandChildren = !mSharedPreferences.getBoolean(SharedPreferencesUtils.SHOW_TOP_LEVEL_COMMENTS_FIRST, false); + if (savedInstanceState == null) { + mRespectSubredditRecommendedSortType = mSharedPreferences.getBoolean(SharedPreferencesUtils.RESPECT_SUBREDDIT_RECOMMENDED_COMMENT_SORT_TYPE, false); + } + + mGlide = Glide.with(this); + Resources resources = getResources(); + mLocale = getResources().getConfiguration().locale; + + mLinearLayoutManager = new LinearLayoutManager(activity); + mRecyclerView.setLayoutManager(mLinearLayoutManager); + + if (children != null && children.size() > 0) { + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (!mIsSmoothScrolling && !mLockFab) { + if (!recyclerView.canScrollVertically(1)) { + activity.hideFab(); + } else { + if (dy > 0) { + if (mSwipeUpToHideFab) { + activity.showFab(); + } else { + activity.hideFab(); + } + } else { + if (mSwipeUpToHideFab) { + activity.hideFab(); + } else { + activity.showFab(); + } + } + } + } + + if (!isLoadingMoreChildren && loadMoreChildrenSuccess) { + int visibleItemCount = mLinearLayoutManager.getChildCount(); + int totalItemCount = mLinearLayoutManager.getItemCount(); + int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + + if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { + fetchMoreComments(); + } + } + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + mIsSmoothScrolling = false; + } + } + }); + } else { + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (!mIsSmoothScrolling && !mLockFab) { + if (!recyclerView.canScrollVertically(1)) { + activity.hideFab(); + } else { + if (dy > 0) { + if (mSwipeUpToHideFab) { + activity.showFab(); + } else { + activity.hideFab(); + } + } else { + if (mSwipeUpToHideFab) { + activity.hideFab(); + } else { + activity.showFab(); + } + } + } + } + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + mIsSmoothScrolling = false; + } + } + }); + } + + boolean enableSwipeAction = mSharedPreferences.getBoolean(SharedPreferencesUtils.ENABLE_SWIPE_ACTION, false); + boolean vibrateWhenActionTriggered = mSharedPreferences.getBoolean(SharedPreferencesUtils.VIBRATE_WHEN_ACTION_TRIGGERED, true); + swipeActionThreshold = Float.parseFloat(mSharedPreferences.getString(SharedPreferencesUtils.SWIPE_ACTION_THRESHOLD, "0.3")); + swipeRightAction = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.SWIPE_RIGHT_ACTION, "1")); + swipeLeftAction = Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.SWIPE_LEFT_ACTION, "0")); + initializeSwipeActionDrawable(); + touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { + boolean exceedThreshold = false; + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + if (!(viewHolder instanceof CommentAndPostRecyclerViewAdapter.CommentViewHolder)) { + return makeMovementFlags(0, 0); + } + int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(0, swipeFlags); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + if (touchHelper != null) { + touchHelper.attachToRecyclerView(null); + touchHelper.attachToRecyclerView(mRecyclerView); + if (mAdapter != null) { + mAdapter.onItemSwipe(viewHolder, direction, swipeLeftAction, swipeRightAction); + } + } + } + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + + View itemView = viewHolder.itemView; + int horizontalOffset = (int) Utils.convertDpToPixel(16, activity); + if (dX > 0) { + if (dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (vibrateWhenActionTriggered) { + viewHolder.itemView.setHapticFeedbackEnabled(true); + viewHolder.itemView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + backgroundSwipeRight.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundSwipeRight.setBounds(0, 0, 0, 0); + } + + drawableSwipeRight.setBounds(itemView.getLeft() + ((int) dX) - horizontalOffset - drawableSwipeRight.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() - drawableSwipeRight.getIntrinsicHeight()) / 2, + itemView.getLeft() + ((int) dX) - horizontalOffset, + (itemView.getBottom() + itemView.getTop() + drawableSwipeRight.getIntrinsicHeight()) / 2); + backgroundSwipeRight.draw(c); + drawableSwipeRight.draw(c); + } else if (dX < 0) { + if (-dX > (itemView.getRight() - itemView.getLeft()) * swipeActionThreshold) { + if (!exceedThreshold) { + exceedThreshold = true; + if (vibrateWhenActionTriggered) { + viewHolder.itemView.setHapticFeedbackEnabled(true); + viewHolder.itemView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + backgroundSwipeLeft.setBounds(0, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + } else { + exceedThreshold = false; + backgroundSwipeLeft.setBounds(0, 0, 0, 0); + } + drawableSwipeLeft.setBounds(itemView.getRight() + ((int) dX) + horizontalOffset, + (itemView.getBottom() + itemView.getTop() - drawableSwipeLeft.getIntrinsicHeight()) / 2, + itemView.getRight() + ((int) dX) + horizontalOffset + drawableSwipeLeft.getIntrinsicWidth(), + (itemView.getBottom() + itemView.getTop() + drawableSwipeLeft.getIntrinsicHeight()) / 2); + backgroundSwipeLeft.draw(c); + drawableSwipeLeft.draw(c); + } + } + + @Override + public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { + return swipeActionThreshold; + } + }); + + if (enableSwipeAction) { + touchHelper.attachToRecyclerView(mRecyclerView); + } + + mSwipeRefreshLayout.setOnRefreshListener(() -> refresh(true, true)); + + mSmoothScroller = new LinearSmoothScroller(activity) { + @Override + protected int getVerticalSnapPreference() { + return LinearSmoothScroller.SNAP_TO_START; + } + }; + + mSingleCommentId = getArguments().getString(EXTRA_SINGLE_COMMENT_ID); + if (savedInstanceState == null) { + if (mSingleCommentId != null) { + isSingleCommentThreadMode = true; + } + mMessageFullname = getArguments().getString(EXTRA_MESSAGE_FULLNAME); + + if (!mRespectSubredditRecommendedSortType || isSingleCommentThreadMode) { + sortType = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, SortType.Type.BEST.value.toUpperCase()); + if (sortType != null) { + activity.setTitle(new SortType(SortType.Type.valueOf(sortType)).getType().fullName); + sortType = sortType.toLowerCase(); + } + } + } else { + if (sortType != null) { + activity.setTitle(new SortType(SortType.Type.valueOf(sortType.toUpperCase())).getType().fullName); + } + } + + if (getArguments().containsKey(EXTRA_POST_LIST_POSITION)) { + postListPosition = getArguments().getInt(EXTRA_POST_LIST_POSITION, -1); + } + + bindView(); + + return rootView; + } + + private void bindView() { + if (mAccessToken != null && mMessageFullname != null) { + ReadMessage.readMessage(mOauthRetrofit, mAccessToken, mMessageFullname, new ReadMessage.ReadMessageListener() { + @Override + public void readSuccess() { + mMessageFullname = null; + } + + @Override + public void readFailed() { + + } + }); + } + + if (mPost == null) { + mPost = getArguments().getParcelable(EXTRA_POST_DATA); + } + + if (mPost == null) { + fetchPostAndCommentsById(getArguments().getString(EXTRA_POST_ID)); + } else { + setupMenu(); + + mAdapter = new CommentAndPostRecyclerViewAdapter(activity, + this, mExecutor, mCustomThemeWrapper, mRetrofit, mOauthRetrofit, mGfycatRetrofit, + mRedgifsRetrofit, mRedditDataRoomDatabase, mGlide, + mWindowWidth, mAccessToken, mAccountName, mPost, mLocale, mSingleCommentId, + isSingleCommentThreadMode, mSharedPreferences, mNsfwAndSpoilerSharedPreferences, mExoCreator, + new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { + @Override + public void updatePost(Post post) { + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void retryFetchingComments() { + fetchCommentsRespectRecommendedSort(false); + } + + @Override + public void retryFetchingMoreComments() { + isLoadingMoreChildren = false; + loadMoreChildrenSuccess = true; + + fetchMoreComments(); + } + }); + mRecyclerView.setAdapter(mAdapter); + + if (comments == null) { + fetchCommentsRespectRecommendedSort(false); + } else { + if (isRefreshing) { + isRefreshing = false; + refresh(true, true); + } else if (isFetchingComments) { + fetchCommentsRespectRecommendedSort(false); + } else { + mAdapter.addComments(comments, hasMoreChildren); + if (isLoadingMoreChildren) { + isLoadingMoreChildren = false; + fetchMoreComments(); + } + } + } + } + + mRecyclerView.setCacheManager(mAdapter); + mRecyclerView.setPlayerInitializer(order -> { + VolumeInfo volumeInfo = new VolumeInfo(true, 0f); + return new PlaybackInfo(INDEX_UNSET, TIME_UNSET, volumeInfo); + }); + } + + private void setupMenu() { + if (mMenu != null) { + MenuItem saveItem = mMenu.findItem(R.id.action_save_view_post_detail_fragment); + MenuItem hideItem = mMenu.findItem(R.id.action_hide_view_post_detail_fragment); + + mMenu.findItem(R.id.action_comment_view_post_detail_fragment).setVisible(true); + mMenu.findItem(R.id.action_sort_view_post_detail_fragment).setVisible(true); + + if (mAccessToken != null) { + if (mPost.isSaved()) { + saveItem.setVisible(true); + saveItem.setIcon(mSavedIcon); + } else { + saveItem.setVisible(true); + saveItem.setIcon(mUnsavedIcon); + } + + if (mPost.isHidden()) { + hideItem.setVisible(true); + hideItem.setTitle(R.string.action_unhide_post); + } else { + hideItem.setVisible(true); + hideItem.setTitle(R.string.action_hide_post); + } + } else { + saveItem.setVisible(false); + hideItem.setVisible(false); + } + + if (mPost.getAuthor().equals(mAccountName)) { + if (mPost.getPostType() == Post.TEXT_TYPE) { + mMenu.findItem(R.id.action_edit_view_post_detail_fragment).setVisible(true); + } + mMenu.findItem(R.id.action_delete_view_post_detail_fragment).setVisible(true); + + MenuItem nsfwItem = mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment); + nsfwItem.setVisible(true); + if (mPost.isNSFW()) { + nsfwItem.setTitle(R.string.action_unmark_nsfw); + } else { + nsfwItem.setTitle(R.string.action_mark_nsfw); + } + + MenuItem spoilerItem = mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment); + spoilerItem.setVisible(true); + if (mPost.isSpoiler()) { + spoilerItem.setTitle(R.string.action_unmark_spoiler); + } else { + spoilerItem.setTitle(R.string.action_mark_spoiler); + } + + mMenu.findItem(R.id.action_edit_flair_view_post_detail_fragment).setVisible(true); + } + + mMenu.findItem(R.id.action_view_crosspost_parent_view_post_detail_fragment).setVisible(mPost.getCrosspostParentId() != null); + + if ("[deleted]".equals(mPost.getAuthor()) || + "[deleted]".equals(mPost.getSelfText()) || + "[removed]".equals(mPost.getSelfText()) + ) { + mMenu.findItem(R.id.action_see_removed_view_post_detail_fragment).setVisible(true); + } + } + } + + private void initializeSwipeActionDrawable() { + if (swipeRightAction == SharedPreferencesUtils.SWIPE_ACITON_DOWNVOTE) { + backgroundSwipeRight = new ColorDrawable(mCustomThemeWrapper.getDownvoted()); + drawableSwipeRight = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_downward_black_24dp, null); + } else { + backgroundSwipeRight = new ColorDrawable(mCustomThemeWrapper.getUpvoted()); + drawableSwipeRight = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_upward_black_24dp, null); + } + + if (swipeLeftAction == SharedPreferencesUtils.SWIPE_ACITON_UPVOTE) { + backgroundSwipeLeft = new ColorDrawable(mCustomThemeWrapper.getUpvoted()); + drawableSwipeLeft = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_upward_black_24dp, null); + } else { + backgroundSwipeLeft = new ColorDrawable(mCustomThemeWrapper.getDownvoted()); + drawableSwipeLeft = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_downward_black_24dp, null); + } + } + + private Drawable getMenuItemIcon(int drawableId) { + Drawable icon = ContextCompat.getDrawable(activity, drawableId); + if (icon != null) { + DrawableCompat.setTint(icon, mCustomThemeWrapper.getToolbarPrimaryTextAndIconColor()); + } + + return icon; + } + + public void addComment(Comment comment) { + if (mAdapter != null) { + mAdapter.addComment(comment); + } + } + + public void addChildComment(Comment comment, String parentFullname, int parentPosition) { + if (mAdapter != null) { + mAdapter.addChildComment(comment, parentFullname, parentPosition); + } + } + + public void editComment(String commentAuthor, String commentContentMarkdown, int position) { + if (mAdapter != null) { + mAdapter.editComment(commentAuthor, + commentContentMarkdown, + position); + } + } + + public void awardGiven(String awardsHTML, int awardCount, int position) { + if (mAdapter != null) { + mAdapter.giveAward(awardsHTML, awardCount, position); + } + } + + public void changeFlair(Flair flair) { + Map<String, String> params = new HashMap<>(); + params.put(APIUtils.API_TYPE_KEY, APIUtils.API_TYPE_JSON); + params.put(APIUtils.FLAIR_TEMPLATE_ID_KEY, flair.getId()); + params.put(APIUtils.LINK_KEY, mPost.getFullName()); + params.put(APIUtils.TEXT_KEY, flair.getText()); + + mOauthRetrofit.create(RedditAPI.class).selectFlair(mPost.getSubredditNamePrefixed(), + APIUtils.getOAuthHeader(mAccessToken), params).enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + if (response.isSuccessful()) { + refresh(true, false); + showMessage(R.string.update_flair_success); + } else { + showMessage(R.string.update_flair_failed); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + showMessage(R.string.update_flair_failed); + } + }); + } + + public void changeSortType(SortType sortType) { + mFetchPostInfoLinearLayout.setVisibility(View.GONE); + mGlide.clear(mFetchPostInfoImageView); + mChildrenStartingIndex = 0; + if (children != null) { + children.clear(); + } + this.sortType = sortType.getType().value; + if (!mSharedPreferences.getBoolean(SharedPreferencesUtils.RESPECT_SUBREDDIT_RECOMMENDED_COMMENT_SORT_TYPE, false)) { + mSortTypeSharedPreferences.edit().putString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, sortType.getType().name()).apply(); + } + fetchCommentsRespectRecommendedSort(false, false, sortType.getType().value); + } + + public void goToTop() { + if (mLinearLayoutManager != null) { + mLinearLayoutManager.scrollToPositionWithOffset(0, 0); + } + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + inflater.inflate(R.menu.view_post_detail_fragment, menu); + applyMenuItemTheme(menu); + mMenu = menu; + if (mPost != null) { + setupMenu(); + } + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + int itemId = item.getItemId(); + if (itemId == R.id.action_refresh_view_post_detail_fragment) { + refresh(true, true); + return true; + } else if (itemId == R.id.action_comment_view_post_detail_fragment) { + if (mPost != null) { + if (mPost.isArchived()) { + showMessage(R.string.archived_post_reply_unavailable); + return true; + } + + if (mPost.isLocked()) { + showMessage(R.string.locked_post_comment_unavailable); + return true; + } + + if (mAccessToken == null) { + showMessage(R.string.login_first); + return true; + } + + Intent intent = new Intent(activity, CommentActivity.class); + intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_MARKDOWN_KEY, mPost.getTitle()); + intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_BODY_MARKDOWN_KEY, mPost.getSelfText()); + intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_BODY_KEY, mPost.getSelfTextPlain()); + intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, mPost.getFullName()); + intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, 0); + intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, false); + startActivityForResult(intent, WRITE_COMMENT_REQUEST_CODE); + } + return true; + } else if (itemId == R.id.action_save_view_post_detail_fragment) { + if (mPost != null && mAccessToken != null) { + if (mPost.isSaved()) { + item.setIcon(mUnsavedIcon); + SaveThing.unsaveThing(mOauthRetrofit, mAccessToken, mPost.getFullName(), + new SaveThing.SaveThingListener() { + @Override + public void success() { + mPost.setSaved(false); + item.setIcon(mUnsavedIcon); + showMessage(R.string.post_unsaved_success); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void failed() { + mPost.setSaved(true); + item.setIcon(mSavedIcon); + showMessage(R.string.post_unsaved_failed); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + }); + } else { + item.setIcon(mSavedIcon); + SaveThing.saveThing(mOauthRetrofit, mAccessToken, mPost.getFullName(), + new SaveThing.SaveThingListener() { + @Override + public void success() { + mPost.setSaved(true); + item.setIcon(mSavedIcon); + showMessage(R.string.post_saved_success); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void failed() { + mPost.setSaved(false); + item.setIcon(mUnsavedIcon); + showMessage(R.string.post_saved_failed); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + }); + } + } + return true; + } else if (itemId == R.id.action_sort_view_post_detail_fragment) { + if (mPost != null) { + PostCommentSortTypeBottomSheetFragment postCommentSortTypeBottomSheetFragment = new PostCommentSortTypeBottomSheetFragment(); + postCommentSortTypeBottomSheetFragment.show(activity.getSupportFragmentManager(), postCommentSortTypeBottomSheetFragment.getTag()); + } + return true; + } else if (itemId == R.id.action_view_crosspost_parent_view_post_detail_fragment) { + Intent crosspostIntent = new Intent(activity, ViewPostDetailActivity.class); + crosspostIntent.putExtra(ViewPostDetailActivity.EXTRA_POST_ID, mPost.getCrosspostParentId()); + startActivity(crosspostIntent); + return true; + } else if (itemId == R.id.action_hide_view_post_detail_fragment) { + if (mPost != null && mAccessToken != null) { + if (mPost.isHidden()) { + item.setTitle(R.string.action_hide_post); + + HidePost.unhidePost(mOauthRetrofit, mAccessToken, mPost.getFullName(), new HidePost.HidePostListener() { + @Override + public void success() { + mPost.setHidden(false); + item.setTitle(R.string.action_hide_post); + showMessage(R.string.post_unhide_success); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void failed() { + mPost.setHidden(true); + item.setTitle(R.string.action_unhide_post); + showMessage(R.string.post_unhide_failed); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + }); + } else { + item.setTitle(R.string.action_unhide_post); + + HidePost.hidePost(mOauthRetrofit, mAccessToken, mPost.getFullName(), new HidePost.HidePostListener() { + @Override + public void success() { + mPost.setHidden(true); + item.setTitle(R.string.action_unhide_post); + showMessage(R.string.post_hide_success); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void failed() { + mPost.setHidden(false); + item.setTitle(R.string.action_hide_post); + showMessage(R.string.post_hide_failed); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + }); + } + } + return true; + } else if (itemId == R.id.action_edit_view_post_detail_fragment) { + Intent editPostIntent = new Intent(activity, EditPostActivity.class); + editPostIntent.putExtra(EditPostActivity.EXTRA_FULLNAME, mPost.getFullName()); + editPostIntent.putExtra(EditPostActivity.EXTRA_TITLE, mPost.getTitle()); + editPostIntent.putExtra(EditPostActivity.EXTRA_CONTENT, mPost.getSelfText()); + startActivityForResult(editPostIntent, EDIT_POST_REQUEST_CODE); + return true; + } else if (itemId == R.id.action_delete_view_post_detail_fragment) { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.delete_this_post) + .setMessage(R.string.are_you_sure) + .setPositiveButton(R.string.delete, (dialogInterface, i) + -> DeleteThing.delete(mOauthRetrofit, mPost.getFullName(), mAccessToken, new DeleteThing.DeleteThingListener() { + @Override + public void deleteSuccess() { + Toast.makeText(activity, R.string.delete_post_success, Toast.LENGTH_SHORT).show(); + activity.finish(); + } + + @Override + public void deleteFailed() { + showMessage(R.string.delete_post_failed); + } + })) + .setNegativeButton(R.string.cancel, null) + .show(); + return true; + } else if (itemId == R.id.action_nsfw_view_post_detail_fragment) { + if (mPost.isNSFW()) { + unmarkNSFW(); + } else { + markNSFW(); + } + return true; + } else if (itemId == R.id.action_spoiler_view_post_detail_fragment) { + if (mPost.isSpoiler()) { + unmarkSpoiler(); + } else { + markSpoiler(); + } + return true; + } else if (itemId == R.id.action_edit_flair_view_post_detail_fragment) { + FlairBottomSheetFragment flairBottomSheetFragment = new FlairBottomSheetFragment(); + Bundle bundle = new Bundle(); + bundle.putString(FlairBottomSheetFragment.EXTRA_ACCESS_TOKEN, mAccessToken); + bundle.putString(FlairBottomSheetFragment.EXTRA_SUBREDDIT_NAME, mPost.getSubredditName()); + flairBottomSheetFragment.setArguments(bundle); + flairBottomSheetFragment.show(activity.getSupportFragmentManager(), flairBottomSheetFragment.getTag()); + return true; + } else if (itemId == R.id.action_give_award_view_post_detail_fragment) { + if (mAccessToken == null) { + Toast.makeText(activity, R.string.login_first, Toast.LENGTH_SHORT).show(); + return true; + } + + Intent giveAwardIntent = new Intent(activity, GiveAwardActivity.class); + giveAwardIntent.putExtra(GiveAwardActivity.EXTRA_THING_FULLNAME, mPost.getFullName()); + giveAwardIntent.putExtra(GiveAwardActivity.EXTRA_ITEM_POSITION, 0); + activity.startActivityForResult(giveAwardIntent, ViewPostDetailActivity.GIVE_AWARD_REQUEST_CODE); + return true; + } else if (itemId == R.id.action_report_view_post_detail_fragment) { + if (mAccessToken == null) { + Toast.makeText(activity, R.string.login_first, Toast.LENGTH_SHORT).show(); + return true; + } + Intent intent = new Intent(activity, ReportActivity.class); + intent.putExtra(ReportActivity.EXTRA_SUBREDDIT_NAME, mPost.getSubredditName()); + intent.putExtra(ReportActivity.EXTRA_THING_FULLNAME, mPost.getFullName()); + startActivity(intent); + return true; + } else if (itemId == R.id.action_see_removed_view_post_detail_fragment) { + showRemovedPost(); + return true; + } else if (itemId == R.id.action_crosspost_view_post_detail_fragment) { + Intent submitCrosspostIntent = new Intent(activity, SubmitCrosspostActivity.class); + submitCrosspostIntent.putExtra(SubmitCrosspostActivity.EXTRA_POST, mPost); + startActivity(submitCrosspostIntent); + return true; + } + return false; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + if (requestCode == WRITE_COMMENT_REQUEST_CODE) { + if (data != null && resultCode == Activity.RESULT_OK) { + if (data.hasExtra(RETURN_EXTRA_COMMENT_DATA_KEY)) { + Comment comment = data.getParcelableExtra(RETURN_EXTRA_COMMENT_DATA_KEY); + if (comment != null && comment.getDepth() == 0) { + addComment(comment); + } else { + String parentFullname = data.getStringExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY); + int parentPosition = data.getIntExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, -1); + if (parentFullname != null && parentPosition >= 0) { + addChildComment(comment, parentFullname, parentPosition); + } + } + } else { + Toast.makeText(activity, R.string.send_comment_failed, Toast.LENGTH_SHORT).show(); + } + } + } else if (requestCode == EDIT_POST_REQUEST_CODE) { + if (resultCode == Activity.RESULT_OK) { + refresh(true, false); + } + } + } + + @Override + public void onResume() { + super.onResume(); + if (mAdapter != null && mRecyclerView != null) { + mRecyclerView.onWindowVisibilityChanged(View.VISIBLE); + } + } + + @Override + public void onPause() { + super.onPause(); + if (mAdapter != null && mRecyclerView != null) { + mRecyclerView.onWindowVisibilityChanged(View.GONE); + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + comments = mAdapter == null ? null : mAdapter.getVisibleComments(); + Bridge.saveInstanceState(this, outState); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + Bridge.clear(this); + } + + @Override + public void onDestroy() { + EventBus.getDefault().unregister(this); + super.onDestroy(); + } + + @SuppressLint("RestrictedApi") + protected boolean applyMenuItemTheme(Menu menu) { + if (mCustomThemeWrapper != null) { + int size = Math.min(menu.size(), 2); + for (int i = 0; i < size; i++) { + MenuItem item = menu.getItem(i); + if (((MenuItemImpl) item).requestsActionButton()) { + Drawable drawable = item.getIcon(); + if (drawable != null) { + DrawableCompat.setTint(drawable, mCustomThemeWrapper.getToolbarPrimaryTextAndIconColor()); + item.setIcon(drawable); + } + } + } + } + return true; + } + + private void fetchPostAndCommentsById(String subredditId) { + mFetchPostInfoLinearLayout.setVisibility(View.GONE); + mSwipeRefreshLayout.setRefreshing(true); + mGlide.clear(mFetchPostInfoImageView); + + Call<String> postAndComments; + if (mAccessToken == null) { + if (isSingleCommentThreadMode && mSingleCommentId != null) { + postAndComments = mRetrofit.create(RedditAPI.class).getPostAndCommentsSingleThreadById( + subredditId, mSingleCommentId, sortType); + } else { + postAndComments = mRetrofit.create(RedditAPI.class).getPostAndCommentsById(subredditId, + sortType); + } + } else { + if (isSingleCommentThreadMode && mSingleCommentId != null) { + postAndComments = mOauthRetrofit.create(RedditAPI.class).getPostAndCommentsSingleThreadByIdOauth(subredditId, + mSingleCommentId, sortType, APIUtils.getOAuthHeader(mAccessToken)); + } else { + postAndComments = mOauthRetrofit.create(RedditAPI.class).getPostAndCommentsByIdOauth(subredditId, + sortType, APIUtils.getOAuthHeader(mAccessToken)); + } + } + postAndComments.enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + mSwipeRefreshLayout.setRefreshing(false); + + if (response.isSuccessful()) { + ParsePost.parsePost(response.body(), new ParsePost.ParsePostListener() { + @Override + public void onParsePostSuccess(Post post) { + mPost = post; + + setupMenu(); + + mAdapter = new CommentAndPostRecyclerViewAdapter(activity, + ViewPostDetailFragment.this, mExecutor, mCustomThemeWrapper, mRetrofit, mOauthRetrofit, mGfycatRetrofit, + mRedgifsRetrofit, mRedditDataRoomDatabase, mGlide, + mWindowWidth, mAccessToken, mAccountName, mPost, mLocale, + mSingleCommentId, isSingleCommentThreadMode, mSharedPreferences, + mNsfwAndSpoilerSharedPreferences, mExoCreator, + new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { + @Override + public void updatePost(Post post) { + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void retryFetchingComments() { + fetchCommentsRespectRecommendedSort(false); + } + + @Override + public void retryFetchingMoreComments() { + isLoadingMoreChildren = false; + loadMoreChildrenSuccess = true; + + fetchMoreComments(); + } + }); + mRecyclerView.setAdapter(mAdapter); + + if (mRespectSubredditRecommendedSortType) { + fetchCommentsRespectRecommendedSort(false); + } else { + ParseComment.parseComment(response.body(), new ArrayList<>(), mLocale, + mExpandChildren, new ParseComment.ParseCommentListener() { + @Override + public void onParseCommentSuccess(ArrayList<Comment> expandedComments, String parentId, ArrayList<String> moreChildrenFullnames) { + ViewPostDetailFragment.this.children = moreChildrenFullnames; + + hasMoreChildren = children.size() != 0; + mAdapter.addComments(expandedComments, hasMoreChildren); + + if (children.size() > 0) { + mRecyclerView.clearOnScrollListeners(); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (!mIsSmoothScrolling && !mLockFab) { + if (!recyclerView.canScrollVertically(1)) { + activity.hideFab(); + } else { + if (dy > 0) { + if (mSwipeUpToHideFab) { + activity.showFab(); + } else { + activity.hideFab(); + } + } else { + if (mSwipeUpToHideFab) { + activity.hideFab(); + } else { + activity.showFab(); + } + } + } + } + + if (!isLoadingMoreChildren && loadMoreChildrenSuccess) { + int visibleItemCount = mLinearLayoutManager.getChildCount(); + int totalItemCount = mLinearLayoutManager.getItemCount(); + int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + + if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { + fetchMoreComments(); + } + } + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + mIsSmoothScrolling = false; + } + } + }); + } + } + + @Override + public void onParseCommentFailed() { + mAdapter.initiallyLoadCommentsFailed(); + } + }); + } + } + + @Override + public void onParsePostFail() { + showErrorView(subredditId); + } + }); + } else { + showErrorView(subredditId); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + showErrorView(subredditId); + } + }); + } + + private void fetchCommentsRespectRecommendedSort(boolean changeRefreshState, boolean checkSortState, String sortType) { + if (mRespectSubredditRecommendedSortType && mPost != null) { + FetchSubredditData.fetchSubredditData(mRetrofit, mPost.getSubredditName(), + new FetchSubredditData.FetchSubredditDataListener() { + @Override + public void onFetchSubredditDataSuccess(SubredditData subredditData, int nCurrentOnlineSubscribers) { + if (subredditData.getSuggestedCommentSort() == null || subredditData.getSuggestedCommentSort().equals("null") || subredditData.getSuggestedCommentSort().equals("")) { + mRespectSubredditRecommendedSortType = false; + ViewPostDetailFragment.this.sortType = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, SortType.Type.BEST.value.toUpperCase()); + if (ViewPostDetailFragment.this.sortType != null) { + activity.setTitle(new SortType(SortType.Type.valueOf(ViewPostDetailFragment.this.sortType)).getType().fullName); + ViewPostDetailFragment.this.sortType = ViewPostDetailFragment.this.sortType.toLowerCase(); + } + fetchComments(changeRefreshState, checkSortState, ViewPostDetailFragment.this.sortType); + } else { + ViewPostDetailFragment.this.sortType = subredditData.getSuggestedCommentSort(); + String sortTypeTemp = ViewPostDetailFragment.this.sortType.toLowerCase().substring(0, 1).toUpperCase() + ViewPostDetailFragment.this.sortType.substring(1); + activity.setTitle(sortTypeTemp); + fetchComments(changeRefreshState, checkSortState, subredditData.getSuggestedCommentSort()); + } + } + + @Override + public void onFetchSubredditDataFail() { + mRespectSubredditRecommendedSortType = false; + ViewPostDetailFragment.this.sortType = mSortTypeSharedPreferences.getString(SharedPreferencesUtils.SORT_TYPE_POST_COMMENT, SortType.Type.BEST.value.toUpperCase()); + if (ViewPostDetailFragment.this.sortType != null) { + activity.setTitle(new SortType(SortType.Type.valueOf(ViewPostDetailFragment.this.sortType)).getType().fullName); + ViewPostDetailFragment.this.sortType = ViewPostDetailFragment.this.sortType.toLowerCase(); + } + } + }); + } else { + fetchComments(changeRefreshState, checkSortState, sortType); + } + } + + private void fetchComments(boolean changeRefreshState, boolean checkSortState, String sortType) { + isFetchingComments = true; + mAdapter.setSingleComment(mSingleCommentId, isSingleCommentThreadMode); + mAdapter.initiallyLoading(); + String commentId = null; + if (isSingleCommentThreadMode) { + commentId = mSingleCommentId; + } + + Retrofit retrofit = mAccessToken == null ? mRetrofit : mOauthRetrofit; + FetchComment.fetchComments(retrofit, mAccessToken, mPost.getId(), commentId, sortType, mExpandChildren, + mLocale, new FetchComment.FetchCommentListener() { + @Override + public void onFetchCommentSuccess(ArrayList<Comment> expandedComments, + String parentId, ArrayList<String> children) { + if (checkSortState && isSortingComments) { + if (changeRefreshState) { + isRefreshing = false; + } + + return; + } + + ViewPostDetailFragment.this.children = children; + + comments = expandedComments; + hasMoreChildren = children.size() != 0; + mAdapter.addComments(expandedComments, hasMoreChildren); + + if (children.size() > 0) { + mRecyclerView.clearOnScrollListeners(); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (!mIsSmoothScrolling && !mLockFab) { + if (!recyclerView.canScrollVertically(1)) { + activity.hideFab(); + } else { + if (dy > 0) { + if (mSwipeUpToHideFab) { + activity.showFab(); + } else { + activity.hideFab(); + } + } else { + if (mSwipeUpToHideFab) { + activity.hideFab(); + } else { + activity.showFab(); + } + } + } + } + + if (!isLoadingMoreChildren && loadMoreChildrenSuccess) { + int visibleItemCount = mLinearLayoutManager.getChildCount(); + int totalItemCount = mLinearLayoutManager.getItemCount(); + int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + + if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { + fetchMoreComments(); + } + } + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + mIsSmoothScrolling = false; + } + } + }); + } + if (changeRefreshState) { + isRefreshing = false; + } + + isFetchingComments = false; + } + + @Override + public void onFetchCommentFailed() { + isFetchingComments = false; + if (checkSortState && isSortingComments) { + if (changeRefreshState) { + isRefreshing = false; + } + + return; + } + + mAdapter.initiallyLoadCommentsFailed(); + if (changeRefreshState) { + isRefreshing = false; + } + } + }); + } + + private void fetchCommentsRespectRecommendedSort(boolean changeRefreshState) { + fetchCommentsRespectRecommendedSort(changeRefreshState, true, sortType); + } + + void fetchMoreComments() { + if (isFetchingComments || isLoadingMoreChildren || !loadMoreChildrenSuccess) { + return; + } + + isLoadingMoreChildren = true; + + Retrofit retrofit = mAccessToken == null ? mRetrofit : mOauthRetrofit; + FetchComment.fetchMoreComment(retrofit, mAccessToken, children, mChildrenStartingIndex, + 0, mExpandChildren, mLocale, new FetchComment.FetchMoreCommentListener() { + @Override + public void onFetchMoreCommentSuccess(ArrayList<Comment> expandedComments, int childrenStartingIndex) { + hasMoreChildren = childrenStartingIndex < children.size(); + mAdapter.addComments(expandedComments, hasMoreChildren); + mChildrenStartingIndex = childrenStartingIndex; + isLoadingMoreChildren = false; + loadMoreChildrenSuccess = true; + } + + @Override + public void onFetchMoreCommentFailed() { + isLoadingMoreChildren = false; + loadMoreChildrenSuccess = false; + mAdapter.loadMoreCommentsFailed(); + } + }); + } + + public void refresh(boolean fetchPost, boolean fetchComments) { + if (mAdapter != null && !isRefreshing) { + isRefreshing = true; + mChildrenStartingIndex = 0; + + mFetchPostInfoLinearLayout.setVisibility(View.GONE); + mGlide.clear(mFetchPostInfoImageView); + + if (fetchComments) { + fetchCommentsRespectRecommendedSort(!fetchPost); + } + + if (fetchPost) { + Retrofit retrofit; + if (mAccessToken == null) { + retrofit = mRetrofit; + } else { + retrofit = mOauthRetrofit; + } + FetchPost.fetchPost(retrofit, mPost.getId(), mAccessToken, mLocale, + new FetchPost.FetchPostListener() { + @Override + public void fetchPostSuccess(Post post) { + mPost = post; + mAdapter.updatePost(mPost); + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + isRefreshing = false; + setupMenu(); + mSwipeRefreshLayout.setRefreshing(false); + } + + @Override + public void fetchPostFailed() { + showMessage(R.string.refresh_post_failed); + isRefreshing = false; + } + }); + } + } + } + + private void showErrorView(String subredditId) { + mSwipeRefreshLayout.setRefreshing(false); + mFetchPostInfoLinearLayout.setVisibility(View.VISIBLE); + mFetchPostInfoLinearLayout.setOnClickListener(view -> fetchPostAndCommentsById(subredditId)); + mFetchPostInfoTextView.setText(R.string.load_post_error); + mGlide.load(R.drawable.error_image).into(mFetchPostInfoImageView); + } + + private void showMessage(int resId) { + if (showToast) { + Toast.makeText(activity, resId, Toast.LENGTH_SHORT).show(); + } else { + activity.showSnackBar(resId); + } + } + + private void markNSFW() { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_unmark_nsfw); + } + + Map<String, String> params = new HashMap<>(); + params.put(APIUtils.ID_KEY, mPost.getFullName()); + mOauthRetrofit.create(RedditAPI.class).markNSFW(APIUtils.getOAuthHeader(mAccessToken), params) + .enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + if (response.isSuccessful()) { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_unmark_nsfw); + } + + refresh(true, false); + showMessage(R.string.mark_nsfw_success); + } else { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_mark_nsfw); + } + + showMessage(R.string.mark_nsfw_failed); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_mark_nsfw); + } + + showMessage(R.string.mark_nsfw_failed); + } + }); + } + + private void unmarkNSFW() { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_mark_nsfw); + } + + Map<String, String> params = new HashMap<>(); + params.put(APIUtils.ID_KEY, mPost.getFullName()); + mOauthRetrofit.create(RedditAPI.class).unmarkNSFW(APIUtils.getOAuthHeader(mAccessToken), params) + .enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + if (response.isSuccessful()) { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_mark_nsfw); + } + + refresh(true, false); + showMessage(R.string.unmark_nsfw_success); + } else { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_unmark_nsfw); + } + + showMessage(R.string.unmark_nsfw_failed); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + if (mMenu != null) { + mMenu.findItem(R.id.action_nsfw_view_post_detail_fragment).setTitle(R.string.action_unmark_nsfw); + } + + showMessage(R.string.unmark_nsfw_failed); + } + }); + } + + private void markSpoiler() { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_unmark_spoiler); + } + + Map<String, String> params = new HashMap<>(); + params.put(APIUtils.ID_KEY, mPost.getFullName()); + mOauthRetrofit.create(RedditAPI.class).markSpoiler(APIUtils.getOAuthHeader(mAccessToken), params) + .enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + if (response.isSuccessful()) { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_unmark_spoiler); + } + + refresh(true, false); + showMessage(R.string.mark_spoiler_success); + } else { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_mark_spoiler); + } + + showMessage(R.string.mark_spoiler_failed); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_mark_spoiler); + } + + showMessage(R.string.mark_spoiler_failed); + } + }); + } + + private void unmarkSpoiler() { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_mark_spoiler); + } + + Map<String, String> params = new HashMap<>(); + params.put(APIUtils.ID_KEY, mPost.getFullName()); + mOauthRetrofit.create(RedditAPI.class).unmarkSpoiler(APIUtils.getOAuthHeader(mAccessToken), params) + .enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { + if (response.isSuccessful()) { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_mark_spoiler); + } + + refresh(true, false); + showMessage(R.string.unmark_spoiler_success); + } else { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_unmark_spoiler); + } + + showMessage(R.string.unmark_spoiler_failed); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + if (mMenu != null) { + mMenu.findItem(R.id.action_spoiler_view_post_detail_fragment).setTitle(R.string.action_unmark_spoiler); + } + + showMessage(R.string.unmark_spoiler_failed); + } + }); + } + + public void deleteComment(String fullName, int position) { + new MaterialAlertDialogBuilder(activity, R.style.MaterialAlertDialogTheme) + .setTitle(R.string.delete_this_comment) + .setMessage(R.string.are_you_sure) + .setPositiveButton(R.string.delete, (dialogInterface, i) + -> DeleteThing.delete(mOauthRetrofit, fullName, mAccessToken, new DeleteThing.DeleteThingListener() { + @Override + public void deleteSuccess() { + Toast.makeText(activity, R.string.delete_post_success, Toast.LENGTH_SHORT).show(); + mAdapter.deleteComment(position); + } + + @Override + public void deleteFailed() { + Toast.makeText(activity, R.string.delete_post_failed, Toast.LENGTH_SHORT).show(); + } + })) + .setNegativeButton(R.string.cancel, null) + .show(); + } + + public void showRemovedComment(Comment comment, int position) { + Toast.makeText(activity, R.string.fetching_removed_comment, Toast.LENGTH_SHORT).show(); + FetchRemovedComment.fetchRemovedComment( + pushshiftRetrofit, + comment, + new FetchRemovedComment.FetchRemovedCommentListener() { + @Override + public void fetchSuccess(Comment comment) { + mAdapter.editComment(comment.getAuthor(), comment.getCommentMarkdown(), position); + } + + @Override + public void fetchFailed() { + Toast.makeText(activity, R.string.show_removed_comment_failed, Toast.LENGTH_SHORT).show(); + } + }); + } + + public void changeToNomalThreadMode() { + isSingleCommentThreadMode = false; + mSingleCommentId = null; + mRespectSubredditRecommendedSortType = mSharedPreferences.getBoolean(SharedPreferencesUtils.RESPECT_SUBREDDIT_RECOMMENDED_COMMENT_SORT_TYPE, false); + refresh(false, true); + } + + public void scrollToNextParentComment() { + if (mLinearLayoutManager != null) { + int currentPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + if (mAdapter != null) { + int nextParentPosition = mAdapter.getNextParentCommentPosition(currentPosition); + if (nextParentPosition < 0) { + return; + } + mSmoothScroller.setTargetPosition(nextParentPosition); + if (mLinearLayoutManager != null) { + mIsSmoothScrolling = true; + mLinearLayoutManager.startSmoothScroll(mSmoothScroller); + } + } + } + } + + public void scrollToPreviousParentComment() { + if (mLinearLayoutManager != null) { + int currentPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + if (mAdapter != null) { + int nextParentPosition = mAdapter.getPreviousParentCommentPosition(currentPosition); + if (nextParentPosition < 0) { + return; + } + mSmoothScroller.setTargetPosition(nextParentPosition); + if (mLinearLayoutManager != null) { + mIsSmoothScrolling = true; + mLinearLayoutManager.startSmoothScroll(mSmoothScroller); + } + } + } + } + + public void delayTransition() { + TransitionManager.beginDelayedTransition(mRecyclerView, new AutoTransition()); + } + + public void showRemovedPost() { + Toast.makeText(activity, R.string.fetching_removed_post, Toast.LENGTH_SHORT).show(); + FetchRemovedPost.fetchRemovedPost( + pushshiftRetrofit, + mPost, + new FetchRemovedPost.FetchRemovedPostListener() { + @Override + public void fetchSuccess(Post post) { + mPost = post; + mAdapter.updatePost(post); + } + + @Override + public void fetchFailed() { + Toast.makeText(activity, R.string.show_removed_post_failed, Toast.LENGTH_SHORT).show(); + } + }); + } + + @Subscribe + public void onPostUpdateEvent(PostUpdateEventToDetailActivity event) { + if (mPost.getId().equals(event.post.getId())) { + mPost.setVoteType(event.post.getVoteType()); + mPost.setSaved(event.post.isSaved()); + if (mMenu != null) { + if (event.post.isSaved()) { + mMenu.findItem(R.id.action_save_view_post_detail_fragment).setIcon(mSavedIcon); + } else { + mMenu.findItem(R.id.action_save_view_post_detail_fragment).setIcon(mUnsavedIcon); + } + } + mAdapter.updatePost(mPost); + } + } + + @Subscribe + public void onChangeNSFWBlurEvent(ChangeNSFWBlurEvent event) { + mAdapter.setBlurNSFW(event.needBlurNSFW); + refreshAdapter(); + } + + @Subscribe + public void onChangeSpoilerBlurEvent(ChangeSpoilerBlurEvent event) { + mAdapter.setBlurSpoiler(event.needBlurSpoiler); + refreshAdapter(); + } + + private void refreshAdapter() { + int previousPosition = -1; + if (mLinearLayoutManager != null) { + previousPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + } + + RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); + mRecyclerView.setAdapter(null); + mRecyclerView.setLayoutManager(null); + mRecyclerView.setAdapter(mAdapter); + mRecyclerView.setLayoutManager(layoutManager); + + if (previousPosition > 0) { + mRecyclerView.scrollToPosition(previousPosition); + } + } + + @Subscribe + public void onChangeNetworkStatusEvent(ChangeNetworkStatusEvent changeNetworkStatusEvent) { + if (mAdapter != null) { + String autoplay = mSharedPreferences.getString(SharedPreferencesUtils.VIDEO_AUTOPLAY, SharedPreferencesUtils.VIDEO_AUTOPLAY_VALUE_NEVER); + String dataSavingMode = mSharedPreferences.getString(SharedPreferencesUtils.DATA_SAVING_MODE, SharedPreferencesUtils.DATA_SAVING_MODE_OFF); + boolean stateChanged = false; + if (autoplay.equals(SharedPreferencesUtils.VIDEO_AUTOPLAY_VALUE_ON_WIFI)) { + mAdapter.setAutoplay(changeNetworkStatusEvent.connectedNetwork == Utils.NETWORK_TYPE_WIFI); + stateChanged = true; + } + if (dataSavingMode.equals(SharedPreferencesUtils.DATA_SAVING_MODE_ONLY_ON_CELLULAR_DATA)) { + mAdapter.setDataSavingMode(changeNetworkStatusEvent.connectedNetwork == Utils.NETWORK_TYPE_CELLULAR); + stateChanged = true; + } + + if (stateChanged) { + refreshAdapter(); + } + } + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + activity = (ViewPostDetailActivity) context; + } + + @Override + public void applyTheme() { + mSwipeRefreshLayout.setProgressBackgroundColorSchemeColor(mCustomThemeWrapper.getCircularProgressBarBackground()); + mSwipeRefreshLayout.setColorSchemeColors(mCustomThemeWrapper.getColorAccent()); + mFetchPostInfoTextView.setTextColor(mCustomThemeWrapper.getSecondaryTextColor()); + } +}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java index 809f0806..2ba685eb 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java @@ -403,7 +403,7 @@ public class ParsePost { if (gfycatId.contains("-")) { gfycatId = gfycatId.substring(0, gfycatId.indexOf('-')); } - post.setGfycatId(gfycatId); + post.setGfycatId(gfycatId.toLowerCase()); } else if (authority != null && authority.contains("redgifs.com")) { String gfycatId = url.substring(url.lastIndexOf("/") + 1); if (gfycatId.contains("-")) { @@ -411,7 +411,7 @@ public class ParsePost { } post.setIsRedgifs(true); post.setVideoUrl(url); - post.setGfycatId(gfycatId); + post.setGfycatId(gfycatId.toLowerCase()); } } catch (IllegalArgumentException ignore) { } } else if (post.getPostType() == Post.LINK_TYPE || post.getPostType() == Post.NO_PREVIEW_LINK_TYPE) { @@ -449,16 +449,21 @@ public class ParsePost { } else if (post.getPostType() == Post.LINK_TYPE) { Uri uri = Uri.parse(url); String authority = uri.getAuthority(); + + // Gyfcat ids must be lowercase to resolve to a video through the api, we are not + // guaranteed to get an id that is all lowercase. + String gfycatId = url.substring(url.lastIndexOf("/") + 1).toLowerCase(); + if (authority != null && (authority.contains("gfycat.com"))) { post.setPostType(Post.VIDEO_TYPE); post.setIsGfycat(true); post.setVideoUrl(url); - post.setGfycatId(url.substring(url.lastIndexOf("/") + 1)); + post.setGfycatId(gfycatId); } else if (authority != null && authority.contains("redgifs.com")) { post.setPostType(Post.VIDEO_TYPE); post.setIsRedgifs(true); post.setVideoUrl(url); - post.setGfycatId(url.substring(url.lastIndexOf("/") + 1)); + post.setGfycatId(gfycatId); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/SubmitPost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/SubmitPost.java index 14216298..c31da124 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/SubmitPost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/SubmitPost.java @@ -1,9 +1,7 @@ package ml.docilealligator.infinityforreddit.post; import android.graphics.Bitmap; -import android.os.AsyncTask; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.json.JSONArray; @@ -21,15 +19,14 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -import ml.docilealligator.infinityforreddit.apis.RedditAPI; import ml.docilealligator.infinityforreddit.Flair; +import ml.docilealligator.infinityforreddit.apis.RedditAPI; import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.JSONUtils; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.Call; -import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; @@ -38,33 +35,31 @@ public class SubmitPost { Locale locale, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW, String kind, SubmitPostListener submitPostListener) { - submitPost(oauthRetrofit, accessToken, locale, subredditName, title, content, + submitPost(oauthRetrofit, accessToken, subredditName, title, content, flair, isSpoiler, isNSFW, kind, null, submitPostListener); } public static void submitImagePost(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit, - String accessToken, Locale locale, - String subredditName, String title, Bitmap image, Flair flair, - boolean isSpoiler, boolean isNSFW, SubmitPostListener submitPostListener) { - uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, image, - new UploadImageListener() { - @Override - public void uploaded(String imageUrl) { - submitPost(oauthRetrofit, accessToken, locale, - subredditName, title, imageUrl, flair, isSpoiler, isNSFW, - APIUtils.KIND_IMAGE, null, submitPostListener); - } - - @Override - public void uploadFailed(@Nullable String errorMessage) { - submitPostListener.submitFailed(errorMessage); - } - }); + String accessToken, String subredditName, String title, Bitmap image, + Flair flair, boolean isSpoiler, boolean isNSFW, SubmitPostListener submitPostListener) { + try { + String imageUrlOrError = uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, image); + if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) { + submitPost(oauthRetrofit, accessToken, + subredditName, title, imageUrlOrError, flair, isSpoiler, isNSFW, + APIUtils.KIND_IMAGE, null, submitPostListener); + } else { + submitPostListener.submitFailed(imageUrlOrError); + } + } catch (IOException | JSONException | XmlPullParserException e) { + e.printStackTrace(); + submitPostListener.submitFailed(e.getMessage()); + } } public static void submitVideoPost(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit, Retrofit uploadVideoRetrofit, String accessToken, - Locale locale, String subredditName, String title, File buffer, String mimeType, + String subredditName, String title, File buffer, String mimeType, Bitmap posterBitmap, Flair flair, boolean isSpoiler, boolean isNSFW, SubmitPostListener submitPostListener) { RedditAPI api = oauthRetrofit.create(RedditAPI.class); @@ -76,97 +71,64 @@ public class SubmitPost { uploadImageParams.put(APIUtils.MIMETYPE_KEY, mimeType); Call<String> uploadImageCall = api.uploadImage(APIUtils.getOAuthHeader(accessToken), uploadImageParams); - uploadImageCall.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - new ParseJSONResponseFromAWSAsyncTask(response.body(), new ParseJSONResponseFromAWSAsyncTask.ParseJSONResponseFromAWSListener() { - @Override - public void parseSuccessful(Map<String, RequestBody> nameValuePairsMap) { - RequestBody fileBody = RequestBody.create(buffer, MediaType.parse("application/octet-stream")); - MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_video." + fileType, fileBody); - - RedditAPI uploadVideoToAWSApi; - if (fileType.equals("gif")) { - uploadVideoToAWSApi = uploadMediaRetrofit.create(RedditAPI.class); - } else { - uploadVideoToAWSApi = uploadVideoRetrofit.create(RedditAPI.class); - } - Call<String> uploadMediaToAWS = uploadVideoToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload); - - uploadMediaToAWS.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - new ParseXMLReponseFromAWSAsyncTask(response.body(), new ParseXMLReponseFromAWSAsyncTask.ParseXMLResponseFromAWSListener() { - @Override - public void parseSuccessful(String url) { - uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, - posterBitmap, new UploadImageListener() { - @Override - public void uploaded(String imageUrl) { - if (fileType.equals("gif")) { - submitPost(oauthRetrofit, accessToken, locale, - subredditName, title, url, flair, isSpoiler, isNSFW, - APIUtils.KIND_VIDEOGIF, imageUrl, submitPostListener); - } else { - submitPost(oauthRetrofit, accessToken, locale, - subredditName, title, url, flair, isSpoiler, isNSFW, - APIUtils.KIND_VIDEO, imageUrl, submitPostListener); - } - } - - @Override - public void uploadFailed(@Nullable String errorMessage) { - submitPostListener.submitFailed(errorMessage); - } - }); - } - - @Override - public void parseFailed() { - submitPostListener.submitFailed(null); - } - }).execute(); - } else { - submitPostListener.submitFailed(response.message()); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - submitPostListener.submitFailed(t.getMessage()); - } - }); - } + try { + Response<String> uploadImageResponse = uploadImageCall.execute(); + if (uploadImageResponse.isSuccessful()) { + Map<String, RequestBody> nameValuePairsMap = parseJSONResponseFromAWS(uploadImageResponse.body()); + + RequestBody fileBody = RequestBody.create(buffer, MediaType.parse("application/octet-stream")); + MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_video." + fileType, fileBody); - @Override - public void parseFailed() { - submitPostListener.submitFailed(null); + RedditAPI uploadVideoToAWSApi; + if (fileType.equals("gif")) { + uploadVideoToAWSApi = uploadMediaRetrofit.create(RedditAPI.class); + } else { + uploadVideoToAWSApi = uploadVideoRetrofit.create(RedditAPI.class); + } + Call<String> uploadMediaToAWS = uploadVideoToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload); + Response<String> uploadMediaToAWSResponse = uploadMediaToAWS.execute(); + if (uploadMediaToAWSResponse.isSuccessful()) { + String url = parseXMLResponseFromAWS(uploadMediaToAWSResponse.body()); + if (url == null) { + submitPostListener.submitFailed(null); + return; + } + String imageUrlOrError = uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, posterBitmap); + if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) { + if (fileType.equals("gif")) { + submitPost(oauthRetrofit, accessToken, + subredditName, title, url, flair, isSpoiler, isNSFW, + APIUtils.KIND_VIDEOGIF, imageUrlOrError, submitPostListener); + } else { + submitPost(oauthRetrofit, accessToken, + subredditName, title, url, flair, isSpoiler, isNSFW, + APIUtils.KIND_VIDEO, imageUrlOrError, submitPostListener); } - }).execute(); + } else { + submitPostListener.submitFailed(imageUrlOrError); + } } else { - submitPostListener.submitFailed(response.message()); + submitPostListener.submitFailed(uploadMediaToAWSResponse.code() + " " + uploadMediaToAWSResponse.message()); } + } else { + submitPostListener.submitFailed(uploadImageResponse.code() + " " + uploadImageResponse.message()); } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - submitPostListener.submitFailed(t.getMessage()); - } - }); + } catch (IOException | XmlPullParserException | JSONException e) { + e.printStackTrace(); + submitPostListener.submitFailed(e.getMessage()); + } } public static void submitCrosspost(Retrofit oauthRetrofit, String accessToken, - Locale locale, String subredditName, String title, String crosspostFullname, + String subredditName, String title, String crosspostFullname, Flair flair, boolean isSpoiler, boolean isNSFW, String kind, SubmitPostListener submitPostListener) { - submitPost(oauthRetrofit, accessToken, locale, subredditName, title, crosspostFullname, + submitPost(oauthRetrofit, accessToken, subredditName, title, crosspostFullname, flair, isSpoiler, isNSFW, kind, null, submitPostListener); } private static void submitPost(Retrofit oauthRetrofit, String accessToken, - Locale locale, String subredditName, String title, String content, + String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW, String kind, @Nullable String posterUrl, SubmitPostListener submitPostListener) { RedditAPI api = oauthRetrofit.create(RedditAPI.class); @@ -206,32 +168,23 @@ public class SubmitPost { params.put(APIUtils.NSFW_KEY, Boolean.toString(isNSFW)); Call<String> submitPostCall = api.submit(APIUtils.getOAuthHeader(accessToken), params); - submitPostCall.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { - if (response.isSuccessful()) { - try { - getSubmittedPost(response.body(), kind, oauthRetrofit, accessToken, - locale, submitPostListener); - } catch (JSONException e) { - e.printStackTrace(); - submitPostListener.submitFailed(null); - } - } else { - submitPostListener.submitFailed(response.message()); - } - } - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - submitPostListener.submitFailed(t.getMessage()); + try { + Response<String> response = submitPostCall.execute(); + if (response.isSuccessful()) { + getSubmittedPost(response.body(), kind, oauthRetrofit, accessToken, submitPostListener); + } else { + submitPostListener.submitFailed(response.message()); } - }); + } catch (IOException | JSONException e) { + e.printStackTrace(); + submitPostListener.submitFailed(e.getMessage()); + } } - private static void uploadImage(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit, - String accessToken, Bitmap image, - UploadImageListener uploadImageListener) { + @Nullable + private static String uploadImage(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit, + String accessToken, Bitmap image) throws IOException, JSONException, XmlPullParserException { RedditAPI api = oauthRetrofit.create(RedditAPI.class); Map<String, String> uploadImageParams = new HashMap<>(); @@ -239,70 +192,32 @@ public class SubmitPost { uploadImageParams.put(APIUtils.MIMETYPE_KEY, "image/jpeg"); Call<String> uploadImageCall = api.uploadImage(APIUtils.getOAuthHeader(accessToken), uploadImageParams); - uploadImageCall.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - new ParseJSONResponseFromAWSAsyncTask(response.body(), new ParseJSONResponseFromAWSAsyncTask.ParseJSONResponseFromAWSListener() { - @Override - public void parseSuccessful(Map<String, RequestBody> nameValuePairsMap) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - image.compress(Bitmap.CompressFormat.JPEG, 100, stream); - byte[] byteArray = stream.toByteArray(); - - RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), byteArray); - MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_image.jpg", fileBody); - - RedditAPI uploadMediaToAWSApi = uploadMediaRetrofit.create(RedditAPI.class); - Call<String> uploadMediaToAWS = uploadMediaToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload); - - uploadMediaToAWS.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) { - if (response.isSuccessful()) { - new ParseXMLReponseFromAWSAsyncTask(response.body(), new ParseXMLReponseFromAWSAsyncTask.ParseXMLResponseFromAWSListener() { - @Override - public void parseSuccessful(String url) { - uploadImageListener.uploaded(url); - } - - @Override - public void parseFailed() { - uploadImageListener.uploadFailed(null); - } - }).execute(); - } else { - uploadImageListener.uploadFailed("Error: " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - uploadImageListener.uploadFailed(t.getMessage()); - } - }); - } - - @Override - public void parseFailed() { - uploadImageListener.uploadFailed(null); - } - }).execute(); - } else { - uploadImageListener.uploadFailed(response.message()); - } - } - - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - uploadImageListener.uploadFailed(t.getMessage()); + Response<String> uploadImageResponse = uploadImageCall.execute(); + if (uploadImageResponse.isSuccessful()) { + Map<String, RequestBody> nameValuePairsMap = parseJSONResponseFromAWS(uploadImageResponse.body()); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.JPEG, 100, stream); + byte[] byteArray = stream.toByteArray(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), byteArray); + MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_image.jpg", fileBody); + + RedditAPI uploadMediaToAWSApi = uploadMediaRetrofit.create(RedditAPI.class); + Call<String> uploadMediaToAWS = uploadMediaToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload); + Response<String> uploadMediaToAWSResponse = uploadMediaToAWS.execute(); + if (uploadMediaToAWSResponse.isSuccessful()) { + return parseXMLResponseFromAWS(uploadMediaToAWSResponse.body()); + } else { + return "Error: " + uploadMediaToAWSResponse.code(); } - }); + } else { + return "Error: " + uploadImageResponse.message(); + } } private static void getSubmittedPost(String response, String kind, Retrofit oauthRetrofit, - String accessToken, Locale locale, - SubmitPostListener submitPostListener) throws JSONException { + String accessToken, SubmitPostListener submitPostListener) throws JSONException, IOException { JSONObject responseObject = new JSONObject(response).getJSONObject(JSONUtils.JSON_KEY); if (responseObject.getJSONArray(JSONUtils.ERRORS_KEY).length() != 0) { JSONArray error = responseObject.getJSONArray(JSONUtils.ERRORS_KEY) @@ -328,31 +243,22 @@ public class SubmitPost { RedditAPI api = oauthRetrofit.create(RedditAPI.class); Call<String> getPostCall = api.getPostOauth(postId, APIUtils.getOAuthHeader(accessToken)); - getPostCall.enqueue(new Callback<String>() { - @Override - public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { - if (response.isSuccessful()) { - ParsePost.parsePost(response.body(), new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(Post post) { - submitPostListener.submitSuccessful(post); - } - - @Override - public void onParsePostFail() { - submitPostListener.submitFailed(null); - } - }); - } else { - submitPostListener.submitFailed(response.message()); + Response<String> getPostCallResponse = getPostCall.execute(); + if (getPostCallResponse.isSuccessful()) { + ParsePost.parsePost(getPostCallResponse.body(), new ParsePost.ParsePostListener() { + @Override + public void onParsePostSuccess(Post post) { + submitPostListener.submitSuccessful(post); } - } - @Override - public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { - submitPostListener.submitFailed(t.getMessage()); - } - }); + @Override + public void onParsePostFail() { + submitPostListener.submitFailed(null); + } + }); + } else { + submitPostListener.submitFailed(getPostCallResponse.message()); + } } else { submitPostListener.submitSuccessful(null); } @@ -364,115 +270,39 @@ public class SubmitPost { void submitFailed(@Nullable String errorMessage); } - private interface UploadImageListener { - void uploaded(String imageUrl); - - void uploadFailed(@Nullable String errorMessage); - } - - private static class ParseJSONResponseFromAWSAsyncTask extends AsyncTask<Void, Void, Void> { - private String response; - private ParseJSONResponseFromAWSListener parseJSONResponseFromAWSListener; - private Map<String, RequestBody> nameValuePairsMap; - private boolean successful; - ParseJSONResponseFromAWSAsyncTask(String response, ParseJSONResponseFromAWSListener parseJSONResponseFromAWSListener) { - this.response = response; - this.parseJSONResponseFromAWSListener = parseJSONResponseFromAWSListener; - nameValuePairsMap = new HashMap<>(); - successful = false; - } - - @Override - protected Void doInBackground(Void... voids) { - try { - JSONObject responseObject = new JSONObject(response); - JSONArray nameValuePairs = responseObject.getJSONObject(JSONUtils.ARGS_KEY).getJSONArray(JSONUtils.FIELDS_KEY); - - nameValuePairsMap = new HashMap<>(); - for (int i = 0; i < nameValuePairs.length(); i++) { - nameValuePairsMap.put(nameValuePairs.getJSONObject(i).getString(JSONUtils.NAME_KEY), - APIUtils.getRequestBody(nameValuePairs.getJSONObject(i).getString(JSONUtils.VALUE_KEY))); - } - - successful = true; - } catch (JSONException e) { - e.printStackTrace(); - successful = false; - } + private static Map<String, RequestBody> parseJSONResponseFromAWS(String response) throws JSONException { + JSONObject responseObject = new JSONObject(response); + JSONArray nameValuePairs = responseObject.getJSONObject(JSONUtils.ARGS_KEY).getJSONArray(JSONUtils.FIELDS_KEY); - return null; + Map<String, RequestBody> nameValuePairsMap = new HashMap<>(); + for (int i = 0; i < nameValuePairs.length(); i++) { + nameValuePairsMap.put(nameValuePairs.getJSONObject(i).getString(JSONUtils.NAME_KEY), + APIUtils.getRequestBody(nameValuePairs.getJSONObject(i).getString(JSONUtils.VALUE_KEY))); } - @Override - protected void onPostExecute(Void aVoid) { - if (successful) { - parseJSONResponseFromAWSListener.parseSuccessful(nameValuePairsMap); - } else { - parseJSONResponseFromAWSListener.parseFailed(); - } - } - - interface ParseJSONResponseFromAWSListener { - void parseSuccessful(Map<String, RequestBody> nameValuePairsMap); - - void parseFailed(); - } + return nameValuePairsMap; } - private static class ParseXMLReponseFromAWSAsyncTask extends AsyncTask<Void, Void, Void> { - private String response; - private ParseXMLResponseFromAWSListener parseXMLResponseFromAWSListener; - private String imageUrl; - private boolean successful; - ParseXMLReponseFromAWSAsyncTask(String response, ParseXMLResponseFromAWSListener parseXMLResponseFromAWSListener) { - this.response = response; - this.parseXMLResponseFromAWSListener = parseXMLResponseFromAWSListener; - successful = false; - } - - @Override - protected Void doInBackground(Void... voids) { - try { - XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser(); - xmlPullParser.setInput(new StringReader(response)); - - boolean isLocationTag = false; - int eventType = xmlPullParser.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - if (xmlPullParser.getName().equals("Location")) { - isLocationTag = true; - } - } else if (eventType == XmlPullParser.TEXT) { - if (isLocationTag) { - imageUrl = xmlPullParser.getText(); - successful = true; - return null; - } - } - eventType = xmlPullParser.next(); + @Nullable + private static String parseXMLResponseFromAWS(String response) throws XmlPullParserException, IOException { + XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser(); + xmlPullParser.setInput(new StringReader(response)); + + boolean isLocationTag = false; + int eventType = xmlPullParser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + if (xmlPullParser.getName().equals("Location")) { + isLocationTag = true; + } + } else if (eventType == XmlPullParser.TEXT) { + if (isLocationTag) { + return xmlPullParser.getText(); } - } catch (XmlPullParserException | IOException e) { - e.printStackTrace(); - successful = false; - } - - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - if (successful) { - parseXMLResponseFromAWSListener.parseSuccessful(imageUrl); - } else { - parseXMLResponseFromAWSListener.parseFailed(); } + eventType = xmlPullParser.next(); } - interface ParseXMLResponseFromAWSListener { - void parseSuccessful(String url); - - void parseFailed(); - } + return null; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/services/SubmitPostService.java b/app/src/main/java/ml/docilealligator/infinityforreddit/services/SubmitPostService.java index b979a07e..2f313125 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/services/SubmitPostService.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/services/SubmitPostService.java @@ -6,11 +6,15 @@ import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; import android.widget.Toast; import androidx.annotation.NonNull; @@ -19,8 +23,6 @@ import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import com.bumptech.glide.Glide; -import com.bumptech.glide.request.target.CustomTarget; -import com.bumptech.glide.request.transition.Transition; import org.greenrobot.eventbus.EventBus; @@ -29,22 +31,24 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Random; +import java.util.concurrent.ExecutionException; import javax.inject.Inject; import javax.inject.Named; +import ml.docilealligator.infinityforreddit.Flair; +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.events.SubmitCrosspostEvent; import ml.docilealligator.infinityforreddit.events.SubmitImagePostEvent; import ml.docilealligator.infinityforreddit.events.SubmitTextOrLinkPostEvent; import ml.docilealligator.infinityforreddit.events.SubmitVideoOrGifPostEvent; -import ml.docilealligator.infinityforreddit.Flair; -import ml.docilealligator.infinityforreddit.Infinity; -import ml.docilealligator.infinityforreddit.utils.NotificationUtils; import ml.docilealligator.infinityforreddit.post.Post; import ml.docilealligator.infinityforreddit.post.SubmitPost; -import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.utils.APIUtils; +import ml.docilealligator.infinityforreddit.utils.NotificationUtils; import retrofit2.Retrofit; public class SubmitPostService extends Service { @@ -61,6 +65,7 @@ public class SubmitPostService extends Service { public static final int EXTRA_POST_TYPE_IMAGE = 1; public static final int EXTRA_POST_TYPE_VIDEO = 2; public static final int EXTRA_POST_TYPE_CROSSPOST = 3; + private static final String EXTRA_MEDIA_URI = "EU"; @Inject @Named("oauth") Retrofit mOauthRetrofit; @@ -72,15 +77,7 @@ public class SubmitPostService extends Service { Retrofit mUploadVideoRetrofit; @Inject CustomThemeWrapper mCustomThemeWrapper; - private String mAccessToken; - private String subredditName; - private String title; - private Flair flair; - private boolean isSpoiler; - private boolean isNSFW; - private String content; - private String kind; - private Uri mediaUri; + private ServiceHandler serviceHandler; public SubmitPostService() { } @@ -90,17 +87,59 @@ public class SubmitPostService extends Service { return null; } + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(@NonNull Message msg) { + super.handleMessage(msg); + Bundle bundle = msg.getData(); + String accessToken = bundle.getString(EXTRA_ACCESS_TOKEN); + String subredditName = bundle.getString(EXTRA_SUBREDDIT_NAME); + String title = bundle.getString(EXTRA_TITLE); + Flair flair = bundle.getParcelable(EXTRA_FLAIR); + boolean isSpoiler = bundle.getBoolean(EXTRA_IS_SPOILER, false); + boolean isNSFW = bundle.getBoolean(EXTRA_IS_NSFW, false); + int postType = bundle.getInt(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK); + + 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, kind); + } else if (postType == EXTRA_POST_TYPE_CROSSPOST) { + String content = bundle.getString(EXTRA_CONTENT); + submitCrosspost(accessToken, subredditName, title, content, flair, isSpoiler, isNSFW); + } else if (postType == EXTRA_POST_TYPE_IMAGE) { + Uri mediaUri = Uri.parse(bundle.getString(EXTRA_MEDIA_URI)); + submitImagePost(accessToken, mediaUri, subredditName, title, flair, isSpoiler, isNSFW); + } else { + Uri mediaUri = Uri.parse(bundle.getString(EXTRA_MEDIA_URI)); + submitVideoPost(accessToken, mediaUri, subredditName, title, flair, isSpoiler, isNSFW); + } + } + } + @Override - public int onStartCommand(Intent intent, int flags, int startId) { + public void onCreate() { ((Infinity) getApplication()).getAppComponent().inject(this); + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work doesn't disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + serviceHandler = new ServiceHandler(thread.getLooper()); + } - mAccessToken = intent.getStringExtra(EXTRA_ACCESS_TOKEN); - subredditName = intent.getStringExtra(EXTRA_SUBREDDIT_NAME); - title = intent.getStringExtra(EXTRA_TITLE); - flair = intent.getParcelableExtra(EXTRA_FLAIR); - isSpoiler = intent.getBooleanExtra(EXTRA_IS_SPOILER, false); - isNSFW = intent.getBooleanExtra(EXTRA_IS_NSFW, false); - int postType = intent.getIntExtra(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK); + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + ((Infinity) getApplication()).getAppComponent().inject(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel serviceChannel = new NotificationChannel( @@ -113,25 +152,26 @@ public class SubmitPostService extends Service { manager.createNotificationChannel(serviceChannel); } + int randomNotificationIdOffset = new Random().nextInt(10000); + int postType = intent.getIntExtra(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK); + Bundle bundle = intent.getExtras(); + if (postType == EXTRA_POST_TEXT_OR_LINK) { - content = intent.getStringExtra(EXTRA_CONTENT); - kind = intent.getStringExtra(EXTRA_KIND); - startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting)); - submitTextOrLinkPost(); + startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting)); } else if (postType == EXTRA_POST_TYPE_CROSSPOST) { - content = intent.getStringExtra(EXTRA_CONTENT); - startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting)); - submitCrosspost(); + startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting)); } else if (postType == EXTRA_POST_TYPE_IMAGE) { - mediaUri = intent.getData(); - startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_image)); - submitImagePost(); + bundle.putString(EXTRA_MEDIA_URI, intent.getData().toString()); + startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting_image)); } else { - mediaUri = intent.getData(); - startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_video)); - submitVideoPost(); + bundle.putString(EXTRA_MEDIA_URI, intent.getData().toString()); + startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting_video)); } + Message msg = serviceHandler.obtainMessage(); + msg.setData(bundle); + serviceHandler.sendMessage(msg); + return START_NOT_STICKY; } @@ -144,8 +184,8 @@ public class SubmitPostService extends Service { .build(); } - private void submitTextOrLinkPost() { - SubmitPost.submitTextOrLinkPost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale, + private void submitTextOrLinkPost(String accessToken, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW, String kind) { + SubmitPost.submitTextOrLinkPost(mOauthRetrofit, accessToken, getResources().getConfiguration().locale, subredditName, title, content, flair, isSpoiler, isNSFW, kind, new SubmitPost.SubmitPostListener() { @Override public void submitSuccessful(Post post) { @@ -163,9 +203,9 @@ public class SubmitPostService extends Service { }); } - private void submitCrosspost() { - SubmitPost.submitCrosspost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale, - subredditName, title, content, flair, isSpoiler, isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() { + private void submitCrosspost(String accessToken, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW) { + SubmitPost.submitCrosspost(mOauthRetrofit, accessToken, subredditName, title, content, flair, isSpoiler, + isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() { @Override public void submitSuccessful(Post post) { EventBus.getDefault().post(new SubmitCrosspostEvent(true, post, null)); @@ -182,49 +222,35 @@ public class SubmitPostService extends Service { }); } - private void submitImagePost() { - Glide.with(this) - .asBitmap() - .load(mediaUri) - .into(new CustomTarget<Bitmap>() { - - @Override - public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { - SubmitPost.submitImagePost(mOauthRetrofit, mUploadMediaRetrofit, mAccessToken, - getResources().getConfiguration().locale, subredditName, title, resource, - flair, isSpoiler, isNSFW, new SubmitPost.SubmitPostListener() { - @Override - public void submitSuccessful(Post post) { - EventBus.getDefault().post(new SubmitImagePostEvent(true, null)); - Toast.makeText(SubmitPostService.this, R.string.image_is_processing, Toast.LENGTH_SHORT).show(); - - stopService(); - } - - @Override - public void submitFailed(@Nullable String errorMessage) { - EventBus.getDefault().post(new SubmitImagePostEvent(false, errorMessage)); - - stopService(); - } - }); - } - - @Override - public void onLoadFailed(@Nullable Drawable errorDrawable) { - EventBus.getDefault().post(new SubmitImagePostEvent(false, getString(R.string.error_processing_image))); + private void submitImagePost(String accessToken, Uri mediaUri, String subredditName, String title, Flair flair, boolean isSpoiler, boolean isNSFW) { + try { + Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get(); + SubmitPost.submitImagePost(mOauthRetrofit, mUploadMediaRetrofit, accessToken, subredditName, title, resource, + flair, isSpoiler, isNSFW, new SubmitPost.SubmitPostListener() { + @Override + public void submitSuccessful(Post post) { + EventBus.getDefault().post(new SubmitImagePostEvent(true, null)); + Toast.makeText(SubmitPostService.this, R.string.image_is_processing, Toast.LENGTH_SHORT).show(); - stopService(); - } + stopService(); + } - @Override - public void onLoadCleared(@Nullable Drawable placeholder) { + @Override + public void submitFailed(@Nullable String errorMessage) { + EventBus.getDefault().post(new SubmitImagePostEvent(false, errorMessage)); - } - }); + stopService(); + } + }); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + EventBus.getDefault().post(new SubmitImagePostEvent(false, getString(R.string.error_processing_image))); + stopService(); + } } - private void submitVideoPost() { + private void submitVideoPost(String accessToken, Uri mediaUri, String subredditName, String title, + Flair flair, boolean isSpoiler, boolean isNSFW) { try { InputStream in = getContentResolver().openInputStream(mediaUri); String type = getContentResolver().getType(mediaUri); @@ -235,67 +261,39 @@ public class SubmitPostService extends Service { cacheFilePath = getExternalCacheDir() + "/" + mediaUri.getLastPathSegment() + ".mp4"; } - new CopyFileToCacheAsyncTask(in, cacheFilePath, - new CopyFileToCacheAsyncTask.CopyFileToCacheAsyncTaskListener() { - @Override - public void success() { - Glide.with(SubmitPostService.this) - .asBitmap() - .load(mediaUri) - .into(new CustomTarget<Bitmap>() { - @Override - public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { - if (type != null) { - SubmitPost.submitVideoPost(mOauthRetrofit, mUploadMediaRetrofit, mUploadVideoRetrofit, - mAccessToken, getResources().getConfiguration().locale, subredditName, title, - new File(cacheFilePath), type, resource, flair, isSpoiler, isNSFW, - new SubmitPost.SubmitPostListener() { - @Override - public void submitSuccessful(Post post) { - EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(true, false, null)); - if (type.contains("gif")) { - Toast.makeText(SubmitPostService.this, R.string.gif_is_processing, Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(SubmitPostService.this, R.string.video_is_processing, Toast.LENGTH_SHORT).show(); - } - - stopService(); - } - - @Override - public void submitFailed(@Nullable String errorMessage) { - EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage)); - - stopService(); - } - }); - } else { - EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); - } - } - - @Override - public void onLoadFailed(@Nullable Drawable errorDrawable) { - EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); - - stopService(); - } - - @Override - public void onLoadCleared(@Nullable Drawable placeholder) { - - } - }); - } - - @Override - public void failed() { - EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); + copyFileToCache(in, cacheFilePath); + + Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get(); + + if (type != null) { + SubmitPost.submitVideoPost(mOauthRetrofit, mUploadMediaRetrofit, mUploadVideoRetrofit, + accessToken, subredditName, title, new File(cacheFilePath), type, resource, flair, + isSpoiler, isNSFW, new SubmitPost.SubmitPostListener() { + @Override + public void submitSuccessful(Post post) { + EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(true, false, null)); + if (type.contains("gif")) { + Toast.makeText(SubmitPostService.this, R.string.gif_is_processing, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(SubmitPostService.this, R.string.video_is_processing, Toast.LENGTH_SHORT).show(); + } + + stopService(); + } + + @Override + public void submitFailed(@Nullable String errorMessage) { + EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage)); + + stopService(); + } + }); + } else { + EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); - stopService(); - } - }).execute(); - } catch (IOException e) { + stopService(); + } + } catch (IOException | InterruptedException | ExecutionException e) { e.printStackTrace(); EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); @@ -303,47 +301,12 @@ public class SubmitPostService extends Service { } } - private static class CopyFileToCacheAsyncTask extends AsyncTask<Void, Void, Void> { - - private InputStream fileInputStream; - private String destinationFilePath; - private CopyFileToCacheAsyncTaskListener copyFileToCacheAsyncTaskListener; - private boolean parseFailed = false; - - interface CopyFileToCacheAsyncTaskListener { - void success(); - void failed(); - } - - public CopyFileToCacheAsyncTask(InputStream fileInputStream, String destinationFilePath, CopyFileToCacheAsyncTaskListener copyFileToCacheAsyncTaskListener) { - this.fileInputStream = fileInputStream; - this.destinationFilePath = destinationFilePath; - this.copyFileToCacheAsyncTaskListener = copyFileToCacheAsyncTaskListener; - } - - @Override - protected Void doInBackground(Void... voids) { - try (OutputStream out = new FileOutputStream(destinationFilePath)) { - byte[] buf = new byte[2048]; - int len; - while ((len = fileInputStream.read(buf)) > 0) { - out.write(buf, 0, len); - } - } catch (IOException e) { - e.printStackTrace(); - parseFailed = true; - } - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - if (parseFailed) { - copyFileToCacheAsyncTaskListener.failed(); - } else { - copyFileToCacheAsyncTaskListener.success(); - } + private static void copyFileToCache(InputStream fileInputStream, String destinationFilePath) throws IOException { + OutputStream out = new FileOutputStream(destinationFilePath); + byte[] buf = new byte[2048]; + int len; + while ((len = fileInputStream.read(buf)) > 0) { + out.write(buf, 0, len); } } diff --git a/app/src/main/res/layout/activity_view_post_detail.xml b/app/src/main/res/layout/activity_view_post_detail.xml index 2e3479d0..d16899f3 100644 --- a/app/src/main/res/layout/activity_view_post_detail.xml +++ b/app/src/main/res/layout/activity_view_post_detail.xml @@ -32,44 +32,11 @@ </com.google.android.material.appbar.AppBarLayout> - <androidx.swiperefreshlayout.widget.SwipeRefreshLayout - android:id="@+id/swipe_refresh_layout_view_post_detail_activity" + <androidx.viewpager2.widget.ViewPager2 + android:id="@+id/view_pager_2_view_post_detail_activity" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_behavior="@string/appbar_scrolling_view_behavior"> - - <ml.docilealligator.infinityforreddit.customviews.CustomToroContainer - android:id="@+id/recycler_view_view_post_detail" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingBottom="144dp" - android:clipToPadding="false" /> - - </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> - - <LinearLayout - android:id="@+id/fetch_post_info_linear_layout_view_post_detail_activity" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center" - android:orientation="vertical" - android:visibility="gone"> - - <ImageView - android:id="@+id/fetch_post_info_image_view_view_post_detail_activity" - android:layout_width="150dp" - android:layout_height="wrap_content" /> - - <TextView - android:id="@+id/fetch_post_info_text_view_view_post_detail_activity" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:gravity="center" - android:textSize="?attr/font_default" - android:fontFamily="?attr/font_family" /> - - </LinearLayout> + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab_view_post_detail_activity" diff --git a/app/src/main/res/layout/fragment_view_post_detail.xml b/app/src/main/res/layout/fragment_view_post_detail.xml new file mode 100644 index 00000000..7b2c314a --- /dev/null +++ b/app/src/main/res/layout/fragment_view_post_detail.xml @@ -0,0 +1,48 @@ +<?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=".fragments.ViewPostDetailFragment"> + + <androidx.swiperefreshlayout.widget.SwipeRefreshLayout + android:id="@+id/swipe_refresh_layout_view_post_detail_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + <ml.docilealligator.infinityforreddit.customviews.CustomToroContainer + android:id="@+id/recycler_view_view_post_detail_fragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="144dp" + android:clipToPadding="false" /> + + </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> + + <LinearLayout + android:id="@+id/fetch_post_info_linear_layout_view_post_detail_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" + android:visibility="gone"> + + <ImageView + android:id="@+id/fetch_post_info_image_view_view_post_detail_fragment" + android:layout_width="150dp" + android:layout_height="wrap_content" /> + + <TextView + android:id="@+id/fetch_post_info_text_view_view_post_detail_fragment" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:gravity="center" + android:textSize="?attr/font_default" + android:fontFamily="?attr/font_family" /> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/app/src/main/res/menu/view_post_detail_activity.xml b/app/src/main/res/menu/view_post_detail_fragment.xml index 454603aa..d9e66bd6 100644 --- a/app/src/main/res/menu/view_post_detail_activity.xml +++ b/app/src/main/res/menu/view_post_detail_fragment.xml @@ -2,7 +2,7 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/action_comment_view_post_detail_activity" + android:id="@+id/action_comment_view_post_detail_fragment" android:orderInCategory="1" android:title="@string/action_add_comment" android:icon="@drawable/ic_comment_toolbar_24dp" @@ -10,92 +10,92 @@ android:visible="false" /> <item - android:id="@+id/action_save_view_post_detail_activity" + android:id="@+id/action_save_view_post_detail_fragment" android:orderInCategory="2" android:title="@string/action_save_post" app:showAsAction="ifRoom" android:visible="false" /> <item - android:id="@+id/action_sort_view_post_detail_activity" + android:id="@+id/action_sort_view_post_detail_fragment" android:orderInCategory="3" android:title="@string/action_sort" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_refresh_view_post_detail_activity" + android:id="@+id/action_refresh_view_post_detail_fragment" android:orderInCategory="4" android:title="@string/action_refresh" app:showAsAction="never" /> <item - android:id="@+id/action_view_crosspost_parent_view_post_detail_activity" + android:id="@+id/action_view_crosspost_parent_view_post_detail_fragment" android:orderInCategory="5" android:title="@string/action_view_crosspost_parent" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_hide_view_post_detail_activity" + android:id="@+id/action_hide_view_post_detail_fragment" android:orderInCategory="6" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_edit_view_post_detail_activity" + android:id="@+id/action_edit_view_post_detail_fragment" android:orderInCategory="7" android:title="@string/action_edit_post" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_delete_view_post_detail_activity" + android:id="@+id/action_delete_view_post_detail_fragment" android:orderInCategory="8" android:title="@string/action_delete_post" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_nsfw_view_post_detail_activity" + android:id="@+id/action_nsfw_view_post_detail_fragment" android:orderInCategory="9" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_spoiler_view_post_detail_activity" + android:id="@+id/action_spoiler_view_post_detail_fragment" android:orderInCategory="10" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_edit_flair_view_post_detail_activity" + android:id="@+id/action_edit_flair_view_post_detail_fragment" android:orderInCategory="11" android:title="@string/action_edit_flair" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_give_award_view_post_detail_activity" + android:id="@+id/action_give_award_view_post_detail_fragment" android:orderInCategory="12" android:title="@string/action_give_award" app:showAsAction="never" /> <item - android:id="@+id/action_report_view_post_detail_activity" + android:id="@+id/action_report_view_post_detail_fragment" android:orderInCategory="13" android:title="@string/action_report" app:showAsAction="never" /> <item - android:id="@+id/action_see_removed_view_post_detail_activity" + android:id="@+id/action_see_removed_view_post_detail_fragment" android:orderInCategory="14" android:title="@string/action_see_removed" app:showAsAction="never" android:visible="false" /> <item - android:id="@+id/action_crosspost_view_post_detail_activity" + android:id="@+id/action_crosspost_view_post_detail_fragment" android:orderInCategory="15" android:title="@string/action_crosspost" app:showAsAction="never" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 50eab52f..b06b9b52 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1016,7 +1016,5 @@ <string name="add_subreddit_or_user_to_multireddit_failed">Unable to add %1$s to multireddit %2$s</string> <string name="choose_a_user">Choose a user</string> - <!-- TODO: Remove or change this placeholder text --> - <string name="hello_blank_fragment">Hello blank fragment</string> </resources> |