diff options
author | Alex Ning <chineseperson5@gmail.com> | 2020-07-16 14:02:06 +0000 |
---|---|---|
committer | Alex Ning <chineseperson5@gmail.com> | 2020-07-16 14:02:06 +0000 |
commit | ca9c90711c6d795d687983430f224fd8deaa5684 (patch) | |
tree | 6389d046dfff06a0c9ef2bf118bac0f54968d1a5 /app/src/main/java/ml | |
parent | 2d002b42d9727d3a6bb185e760b3c3450ca51319 (diff) | |
download | infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.tar infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.tar.gz infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.tar.bz2 infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.tar.lz infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.tar.xz infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.tar.zst infinity-for-reddit-ca9c90711c6d795d687983430f224fd8deaa5684.zip |
Support viewing Reddit Gallery in app. Fix gif not autoplayable in CommentAndPostRecyclerViewAdapter.
Diffstat (limited to 'app/src/main/java/ml')
11 files changed, 1254 insertions, 26 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewRedditGalleryActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewRedditGalleryActivity.java new file mode 100644 index 00000000..f46d66b7 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Activity/ViewRedditGalleryActivity.java @@ -0,0 +1,237 @@ +package ml.docilealligator.infinityforreddit.Activity; + +import android.content.SharedPreferences; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import com.thefuntasty.hauler.DragDirection; +import com.thefuntasty.hauler.HaulerView; + +import java.util.ArrayList; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import ml.docilealligator.infinityforreddit.Font.ContentFontFamily; +import ml.docilealligator.infinityforreddit.Font.ContentFontStyle; +import ml.docilealligator.infinityforreddit.Font.FontFamily; +import ml.docilealligator.infinityforreddit.Font.FontStyle; +import ml.docilealligator.infinityforreddit.Font.TitleFontFamily; +import ml.docilealligator.infinityforreddit.Font.TitleFontStyle; +import ml.docilealligator.infinityforreddit.Fragment.ViewRedditGalleryImageOrGifFragment; +import ml.docilealligator.infinityforreddit.Fragment.ViewRedditGalleryVideoFragment; +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.Post.Post; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.SetAsWallpaperCallback; +import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; +import ml.docilealligator.infinityforreddit.WallpaperSetter; + +public class ViewRedditGalleryActivity extends AppCompatActivity implements SetAsWallpaperCallback { + + public static final String EXTRA_REDDIT_GALLERY = "ERG"; + + @BindView(R.id.hauler_view_view_reddit_gallery_activity) + HaulerView haulerView; + @BindView(R.id.view_pager_view_reddit_gallery_activity) + ViewPager viewPager; + private SectionsPagerAdapter sectionsPagerAdapter; + private ArrayList<Post.Gallery> gallery; + @Inject + @Named("default") + SharedPreferences sharedPreferences; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ((Infinity) getApplication()).getAppComponent().inject(this); + + getTheme().applyStyle(R.style.Theme_Normal, true); + + getTheme().applyStyle(FontStyle.valueOf(sharedPreferences + .getString(SharedPreferencesUtils.FONT_SIZE_KEY, FontStyle.Normal.name())).getResId(), true); + + getTheme().applyStyle(TitleFontStyle.valueOf(sharedPreferences + .getString(SharedPreferencesUtils.TITLE_FONT_SIZE_KEY, TitleFontStyle.Normal.name())).getResId(), true); + + getTheme().applyStyle(ContentFontStyle.valueOf(sharedPreferences + .getString(SharedPreferencesUtils.CONTENT_FONT_SIZE_KEY, ContentFontStyle.Normal.name())).getResId(), true); + + getTheme().applyStyle(FontFamily.valueOf(sharedPreferences + .getString(SharedPreferencesUtils.FONT_FAMILY_KEY, FontFamily.Default.name())).getResId(), true); + + getTheme().applyStyle(TitleFontFamily.valueOf(sharedPreferences + .getString(SharedPreferencesUtils.TITLE_FONT_FAMILY_KEY, TitleFontFamily.Default.name())).getResId(), true); + + getTheme().applyStyle(ContentFontFamily.valueOf(sharedPreferences + .getString(SharedPreferencesUtils.CONTENT_FONT_FAMILY_KEY, ContentFontFamily.Default.name())).getResId(), true); + + setContentView(R.layout.activity_view_reddit_gallery); + + ButterKnife.bind(this); + + ActionBar actionBar = getSupportActionBar(); + Drawable upArrow = getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp); + actionBar.setHomeAsUpIndicator(upArrow); + actionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.transparentActionBarAndExoPlayerControllerColor))); + + setTitle(" "); + + gallery = getIntent().getParcelableArrayListExtra(EXTRA_REDDIT_GALLERY); + if (gallery == null || gallery.isEmpty()) { + finish(); + return; + } + + haulerView.setOnDragDismissedListener(dragDirection -> { + int slide = dragDirection == DragDirection.UP ? R.anim.slide_out_up : R.anim.slide_out_down; + finish(); + overridePendingTransition(0, slide); + }); + + setupViewPager(); + } + + private void setupViewPager() { + setToolbarTitle(0); + sectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); + viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + setToolbarTitle(position); + } + }); + viewPager.setAdapter(sectionsPagerAdapter); + } + + private void setToolbarTitle(int position) { + if (gallery != null && position >= 0 && position < gallery.size()) { + if (gallery.get(position).mediaType == Post.Gallery.TYPE_IMAGE) { + setTitle(getString(R.string.view_reddit_gallery_activity_image_label, position + 1, gallery.size())); + } else if (gallery.get(position).mediaType == Post.Gallery.TYPE_GIF) { + setTitle(getString(R.string.view_reddit_gallery_activity_gif_label, position + 1, gallery.size())); + } else { + setTitle(getString(R.string.view_reddit_gallery_activity_video_label, position + 1, gallery.size())); + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + + return false; + } + + @Override + public void setToHomeScreen(int viewPagerPosition) { + if (gallery != null && viewPagerPosition >= 0 && viewPagerPosition < gallery.size()) { + WallpaperSetter.set(gallery.get(viewPagerPosition).url, WallpaperSetter.HOME_SCREEN, this, + new WallpaperSetter.SetWallpaperListener() { + @Override + public void success() { + Toast.makeText(ViewRedditGalleryActivity.this, R.string.wallpaper_set, Toast.LENGTH_SHORT).show(); + } + + @Override + public void failed() { + Toast.makeText(ViewRedditGalleryActivity.this, R.string.error_set_wallpaper, Toast.LENGTH_SHORT).show(); + } + }); + } + } + + @Override + public void setToLockScreen(int viewPagerPosition) { + if (gallery != null && viewPagerPosition >= 0 && viewPagerPosition < gallery.size()) { + WallpaperSetter.set(gallery.get(viewPagerPosition).url, WallpaperSetter.LOCK_SCREEN, this, + new WallpaperSetter.SetWallpaperListener() { + @Override + public void success() { + Toast.makeText(ViewRedditGalleryActivity.this, R.string.wallpaper_set, Toast.LENGTH_SHORT).show(); + } + + @Override + public void failed() { + Toast.makeText(ViewRedditGalleryActivity.this, R.string.error_set_wallpaper, Toast.LENGTH_SHORT).show(); + } + }); + } + } + + @Override + public void setToBoth(int viewPagerPosition) { + if (gallery != null && viewPagerPosition >= 0 && viewPagerPosition < gallery.size()) { + WallpaperSetter.set(gallery.get(viewPagerPosition).url, WallpaperSetter.BOTH_SCREENS, this, + new WallpaperSetter.SetWallpaperListener() { + @Override + public void success() { + Toast.makeText(ViewRedditGalleryActivity.this, R.string.wallpaper_set, Toast.LENGTH_SHORT).show(); + } + + @Override + public void failed() { + Toast.makeText(ViewRedditGalleryActivity.this, R.string.error_set_wallpaper, Toast.LENGTH_SHORT).show(); + } + }); + } + } + + public int getCurrentPagePosition() { + return viewPager.getCurrentItem(); + } + + private class SectionsPagerAdapter extends FragmentStatePagerAdapter { + + SectionsPagerAdapter(@NonNull FragmentManager fm) { + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + } + + @NonNull + @Override + public Fragment getItem(int position) { + Post.Gallery media = gallery.get(position); + if (media.mediaType == Post.Gallery.TYPE_VIDEO) { + ViewRedditGalleryVideoFragment fragment = new ViewRedditGalleryVideoFragment(); + Bundle bundle = new Bundle(); + bundle.putParcelable(ViewRedditGalleryVideoFragment.EXTRA_REDDIT_GALLERY_VIDEO, media); + fragment.setArguments(bundle); + return fragment; + } else { + ViewRedditGalleryImageOrGifFragment fragment = new ViewRedditGalleryImageOrGifFragment(); + Bundle bundle = new Bundle(); + bundle.putParcelable(ViewRedditGalleryImageOrGifFragment.EXTRA_REDDIT_GALLERY_MEDIA, media); + fragment.setArguments(bundle); + return fragment; + } + } + + @Override + public int getCount() { + return gallery.size(); + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java index bbf36110..fb69a601 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/CommentAndPostRecyclerViewAdapter.java @@ -85,6 +85,7 @@ import ml.docilealligator.infinityforreddit.Activity.FilteredThingActivity; import ml.docilealligator.infinityforreddit.Activity.LinkResolverActivity; import ml.docilealligator.infinityforreddit.Activity.ViewImageOrGifActivity; import ml.docilealligator.infinityforreddit.Activity.ViewPostDetailActivity; +import ml.docilealligator.infinityforreddit.Activity.ViewRedditGalleryActivity; import ml.docilealligator.infinityforreddit.Activity.ViewSubredditDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewUserDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewVideoActivity; @@ -119,16 +120,17 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy private static final int VIEW_TYPE_POST_DETAIL_IMAGE_AND_GIF_AUTOPLAY = 3; private static final int VIEW_TYPE_POST_DETAIL_LINK = 4; private static final int VIEW_TYPE_POST_DETAIL_NO_PREVIEW_LINK = 5; - private static final int VIEW_TYPE_POST_DETAIL_TEXT_TYPE = 6; - private static final int VIEW_TYPE_FIRST_LOADING = 7; - private static final int VIEW_TYPE_FIRST_LOADING_FAILED = 8; - private static final int VIEW_TYPE_NO_COMMENT_PLACEHOLDER = 9; - private static final int VIEW_TYPE_COMMENT = 10; - private static final int VIEW_TYPE_COMMENT_FULLY_COLLAPSED = 11; - private static final int VIEW_TYPE_LOAD_MORE_CHILD_COMMENTS = 12; - private static final int VIEW_TYPE_IS_LOADING_MORE_COMMENTS = 13; - private static final int VIEW_TYPE_LOAD_MORE_COMMENTS_FAILED = 14; - private static final int VIEW_TYPE_VIEW_ALL_COMMENTS = 15; + private static final int VIEW_TYPE_POST_DETAIL_GALLERY = 6; + private static final int VIEW_TYPE_POST_DETAIL_TEXT_TYPE = 7; + private static final int VIEW_TYPE_FIRST_LOADING = 8; + private static final int VIEW_TYPE_FIRST_LOADING_FAILED = 9; + private static final int VIEW_TYPE_NO_COMMENT_PLACEHOLDER = 10; + private static final int VIEW_TYPE_COMMENT = 11; + private static final int VIEW_TYPE_COMMENT_FULLY_COLLAPSED = 12; + private static final int VIEW_TYPE_LOAD_MORE_CHILD_COMMENTS = 13; + private static final int VIEW_TYPE_IS_LOADING_MORE_COMMENTS = 14; + private static final int VIEW_TYPE_LOAD_MORE_COMMENTS_FAILED = 15; + private static final int VIEW_TYPE_VIEW_ALL_COMMENTS = 16; private AppCompatActivity mActivity; private Retrofit mRetrofit; @@ -444,6 +446,8 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy return VIEW_TYPE_POST_DETAIL_LINK; case Post.NO_PREVIEW_LINK_TYPE: return VIEW_TYPE_POST_DETAIL_NO_PREVIEW_LINK; + case Post.GALLERY_TYPE: + return VIEW_TYPE_POST_DETAIL_GALLERY; default: return VIEW_TYPE_POST_DETAIL_TEXT_TYPE; @@ -519,6 +523,8 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy return new PostDetailLinkViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail_link, parent, false)); case VIEW_TYPE_POST_DETAIL_NO_PREVIEW_LINK: return new PostDetailNoPreviewLinkViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail_no_preview_link, parent, false)); + case VIEW_TYPE_POST_DETAIL_GALLERY: + return new PostDetailGalleryViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail_gallery, parent, false)); case VIEW_TYPE_POST_DETAIL_TEXT_TYPE: return new PostDetailTextViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail_text, parent, false)); case VIEW_TYPE_FIRST_LOADING: @@ -761,6 +767,16 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy mMarkwonAdapter.setMarkdown(mPostDetailMarkwon, mPost.getSelfText()); mMarkwonAdapter.notifyDataSetChanged(); } + } else if (holder instanceof PostDetailGalleryViewHolder) { + if (mPost.getPreviewUrl() != null && !mPost.getPreviewUrl().equals("")) { + ((PostDetailGalleryViewHolder) holder).mRelativeLayout.setVisibility(View.VISIBLE); + ((PostDetailGalleryViewHolder) holder).mImageView + .setRatio((float) mPost.getPreviewHeight() / mPost.getPreviewWidth()); + + loadImage((PostDetailGalleryViewHolder) holder); + } else { + ((PostDetailGalleryViewHolder) holder).mNoPreviewLinkImageView.setVisibility(View.VISIBLE); + } } else if (holder instanceof PostDetailTextViewHolder) { if (mPost.getSelfText() != null && !mPost.getSelfText().equals("")) { ((PostDetailTextViewHolder) holder).mContentMarkdownView.setVisibility(View.VISIBLE); @@ -1224,7 +1240,8 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy private void loadImage(PostDetailBaseViewHolder holder) { if (holder instanceof PostDetailImageAndGifAutoplayViewHolder) { - RequestBuilder<Drawable> imageRequestBuilder = mGlide.load(mPost.getPreviewUrl()) + String url = mPost.getPostType() == Post.IMAGE_TYPE ? mPost.getPreviewUrl() : mPost.getUrl(); + RequestBuilder<Drawable> imageRequestBuilder = mGlide.load(url) .listener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { @@ -1318,6 +1335,37 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy imageRequestBuilder.into(((PostDetailLinkViewHolder) holder).mImageView); } } + } else if (holder instanceof PostDetailGalleryViewHolder) { + RequestBuilder<Drawable> imageRequestBuilder = mGlide.load(mPost.getPreviewUrl()) + .listener(new RequestListener<Drawable>() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { + ((PostDetailGalleryViewHolder) holder).mLoadImageProgressBar.setVisibility(View.GONE); + ((PostDetailGalleryViewHolder) holder).mLoadImageErrorTextView.setVisibility(View.VISIBLE); + ((PostDetailGalleryViewHolder) holder).mLoadImageErrorTextView.setOnClickListener(view -> { + ((PostDetailGalleryViewHolder) holder).mLoadImageProgressBar.setVisibility(View.VISIBLE); + ((PostDetailGalleryViewHolder) holder).mLoadImageErrorTextView.setVisibility(View.GONE); + loadImage(holder); + }); + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { + ((PostDetailGalleryViewHolder) holder).mLoadWrapper.setVisibility(View.GONE); + return false; + } + }); + + if ((mPost.isNSFW() && mNeedBlurNsfw && !(mPost.getPostType() == Post.GIF_TYPE && mAutoplayNsfwVideos)) || (mPost.isSpoiler() && mNeedBlurSpoiler)) { + imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 10))).into(((PostDetailGalleryViewHolder) holder).mImageView); + } else { + if (mImageViewWidth > mPost.getPreviewWidth()) { + imageRequestBuilder.override(Target.SIZE_ORIGINAL).into(((PostDetailGalleryViewHolder) holder).mImageView); + } else { + imageRequestBuilder.into(((PostDetailGalleryViewHolder) holder).mImageView); + } + } } } @@ -2706,6 +2754,103 @@ public class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<Recy } } + class PostDetailGalleryViewHolder extends PostDetailBaseViewHolder { + @BindView(R.id.icon_gif_image_view_item_post_detail_gallery) + AspectRatioGifImageView mIconGifImageView; + @BindView(R.id.subreddit_text_view_item_post_detail_gallery) + TextView mSubredditTextView; + @BindView(R.id.user_text_view_item_post_detail_gallery) + TextView mUserTextView; + @BindView(R.id.author_flair_text_view_item_post_detail_gallery) + TextView mAuthorFlairTextView; + @BindView(R.id.post_time_text_view_item_post_detail_gallery) + TextView mPostTimeTextView; + @BindView(R.id.title_text_view_item_post_detail_gallery) + TextView mTitleTextView; + @BindView(R.id.type_text_view_item_post_detail_gallery) + CustomTextView mTypeTextView; + @BindView(R.id.crosspost_image_view_item_post_detail_gallery) + ImageView mCrosspostImageView; + @BindView(R.id.archived_image_view_item_post_detail_gallery) + ImageView mArchivedImageView; + @BindView(R.id.locked_image_view_item_post_detail_gallery) + ImageView mLockedImageView; + @BindView(R.id.nsfw_text_view_item_post_detail_gallery) + CustomTextView mNSFWTextView; + @BindView(R.id.spoiler_custom_text_view_item_post_detail_gallery) + CustomTextView mSpoilerTextView; + @BindView(R.id.flair_custom_text_view_item_post_detail_gallery) + CustomTextView mFlairTextView; + @BindView(R.id.awards_text_view_item_post_detail_gallery) + TextView mAwardsTextView; + @BindView(R.id.image_view_wrapper_item_post_detail_gallery) + RelativeLayout mRelativeLayout; + @BindView(R.id.load_wrapper_item_post_detail_gallery) + RelativeLayout mLoadWrapper; + @BindView(R.id.progress_bar_item_post_detail_gallery) + ProgressBar mLoadImageProgressBar; + @BindView(R.id.load_image_error_text_view_item_post_detail_gallery) + TextView mLoadImageErrorTextView; + @BindView(R.id.image_view_item_post_detail_gallery) + AspectRatioGifImageView mImageView; + @BindView(R.id.image_view_no_preview_link_item_post_detail_gallery) + ImageView mNoPreviewLinkImageView; + @BindView(R.id.bottom_constraint_layout_item_post_detail_gallery) + ConstraintLayout mBottomConstraintLayout; + @BindView(R.id.plus_button_item_post_detail_gallery) + ImageView mUpvoteButton; + @BindView(R.id.score_text_view_item_post_detail_gallery) + TextView mScoreTextView; + @BindView(R.id.minus_button_item_post_detail_gallery) + ImageView mDownvoteButton; + @BindView(R.id.comments_count_item_post_detail_gallery) + TextView commentsCountTextView; + @BindView(R.id.save_button_item_post_detail_gallery) + ImageView mSaveButton; + @BindView(R.id.share_button_item_post_detail_gallery) + ImageView mShareButton; + + PostDetailGalleryViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + setBaseView(mIconGifImageView, + mSubredditTextView, + mUserTextView, + mAuthorFlairTextView, + mPostTimeTextView, + mTitleTextView, + mTypeTextView, + mCrosspostImageView, + mArchivedImageView, + mLockedImageView, + mNSFWTextView, + mSpoilerTextView, + mFlairTextView, + mAwardsTextView, + mBottomConstraintLayout, + mUpvoteButton, + mScoreTextView, + mDownvoteButton, + commentsCountTextView, + mSaveButton, + mShareButton); + + mLoadImageProgressBar.setIndeterminateTintList(ColorStateList.valueOf(mColorAccent)); + mLoadImageErrorTextView.setTextColor(mPrimaryTextColor); + mNoPreviewLinkImageView.setBackgroundColor(mNoPreviewLinkBackgroundColor); + + mImageView.setOnClickListener(view -> { + Intent intent = new Intent(mActivity, ViewRedditGalleryActivity.class); + intent.putParcelableArrayListExtra(ViewRedditGalleryActivity.EXTRA_REDDIT_GALLERY, mPost.getGallery()); + mActivity.startActivity(intent); + }); + + mNoPreviewLinkImageView.setOnClickListener(view -> { + mImageView.performClick(); + }); + } + } + class PostDetailTextViewHolder extends PostDetailBaseViewHolder { @BindView(R.id.icon_gif_image_view_item_post_detail_text) AspectRatioGifImageView mIconGifImageView; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java index 835d8af1..95434ca0 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/PostRecyclerViewAdapter.java @@ -70,6 +70,7 @@ import ml.docilealligator.infinityforreddit.Activity.FilteredThingActivity; import ml.docilealligator.infinityforreddit.Activity.LinkResolverActivity; import ml.docilealligator.infinityforreddit.Activity.ViewImageOrGifActivity; import ml.docilealligator.infinityforreddit.Activity.ViewPostDetailActivity; +import ml.docilealligator.infinityforreddit.Activity.ViewRedditGalleryActivity; import ml.docilealligator.infinityforreddit.Activity.ViewSubredditDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewUserDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewVideoActivity; @@ -104,9 +105,10 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView private static final int VIEW_TYPE_POST_CARD_LINK_TYPE = 4; private static final int VIEW_TYPE_POST_CARD_NO_PREVIEW_LINK_TYPE = 5; private static final int VIEW_TYPE_POST_CARD_TEXT_TYPE = 6; - private static final int VIEW_TYPE_POST_COMPACT = 7; - private static final int VIEW_TYPE_ERROR = 8; - private static final int VIEW_TYPE_LOADING = 9; + private static final int VIEW_TYPE_POST_CARD_GALLERY_TYPE = 7; + private static final int VIEW_TYPE_POST_COMPACT = 8; + private static final int VIEW_TYPE_ERROR = 9; + private static final int VIEW_TYPE_LOADING = 10; private static final DiffUtil.ItemCallback<Post> DIFF_CALLBACK = new DiffUtil.ItemCallback<Post>() { @Override public boolean areItemsTheSame(@NonNull Post post, @NonNull Post t1) { @@ -309,6 +311,8 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView return VIEW_TYPE_POST_CARD_LINK_TYPE; case Post.NO_PREVIEW_LINK_TYPE: return VIEW_TYPE_POST_CARD_NO_PREVIEW_LINK_TYPE; + case Post.GALLERY_TYPE: + return VIEW_TYPE_POST_CARD_GALLERY_TYPE; default: return VIEW_TYPE_POST_CARD_TEXT_TYPE; } @@ -333,6 +337,8 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView return new PostLinkTypeViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_link, parent, false)); } else if (viewType == VIEW_TYPE_POST_CARD_NO_PREVIEW_LINK_TYPE) { return new PostNoPreviewLinkTypeViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_no_preview_link, parent, false)); + } else if (viewType == VIEW_TYPE_POST_CARD_GALLERY_TYPE) { + return new PostGalleryTypeViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_gallery, parent, false)); } else if (viewType == VIEW_TYPE_POST_CARD_TEXT_TYPE) { return new PostTextTypeViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_text, parent, false)); } else if (viewType == VIEW_TYPE_POST_COMPACT) { @@ -586,12 +592,20 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView loadImage(holder, post); String domain = Uri.parse(post.getUrl()).getHost(); - ((PostLinkTypeViewHolder) holder).linkTextView.setVisibility(View.VISIBLE); ((PostLinkTypeViewHolder) holder).linkTextView.setText(domain); } else if (holder instanceof PostNoPreviewLinkTypeViewHolder) { - String noPreviewLinkDomain = Uri.parse(post.getUrl()).getHost(); - ((PostNoPreviewLinkTypeViewHolder) holder).linkTextView.setVisibility(View.VISIBLE); - ((PostNoPreviewLinkTypeViewHolder) holder).linkTextView.setText(noPreviewLinkDomain); + ((PostNoPreviewLinkTypeViewHolder) holder).linkTextView.setText(Uri.parse(post.getUrl()).getHost()); + } else if (holder instanceof PostGalleryTypeViewHolder) { + if (post.getPreviewUrl() != null && !post.getPreviewUrl().equals("")) { + ((PostGalleryTypeViewHolder) holder).imageWrapperRelativeLayout.setVisibility(View.VISIBLE); + ((PostGalleryTypeViewHolder) holder).progressBar.setVisibility(View.VISIBLE); + ((PostGalleryTypeViewHolder) holder).imageView + .setRatio((float) post.getPreviewHeight() / post.getPreviewWidth()); + + loadImage(holder, post); + } else { + ((PostGalleryTypeViewHolder) holder).noPreviewLinkImageView.setVisibility(View.VISIBLE); + } } else if (holder instanceof PostTextTypeViewHolder) { if (post.getSelfTextPlainTrimmed() != null && !post.getSelfTextPlainTrimmed().equals("")) { ((PostTextTypeViewHolder) holder).contentTextView.setVisibility(View.VISIBLE); @@ -945,6 +959,38 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView imageRequestBuilder.into(((PostLinkTypeViewHolder) holder).imageView); } } + } else if (holder instanceof PostGalleryTypeViewHolder) { + RequestBuilder<Drawable> imageRequestBuilder = mGlide.load(post.getPreviewUrl()).listener(new RequestListener<Drawable>() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { + ((PostGalleryTypeViewHolder) holder).progressBar.setVisibility(View.GONE); + ((PostGalleryTypeViewHolder) holder).errorRelativeLayout.setVisibility(View.VISIBLE); + ((PostGalleryTypeViewHolder) holder).errorRelativeLayout.setOnClickListener(view -> { + ((PostGalleryTypeViewHolder) holder).progressBar.setVisibility(View.VISIBLE); + ((PostGalleryTypeViewHolder) holder).errorRelativeLayout.setVisibility(View.GONE); + loadImage(holder, post); + }); + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { + ((PostGalleryTypeViewHolder) holder).errorRelativeLayout.setVisibility(View.GONE); + ((PostGalleryTypeViewHolder) holder).progressBar.setVisibility(View.GONE); + return false; + } + }); + + if ((post.isNSFW() && mNeedBlurNSFW && !(post.getPostType() == Post.GIF_TYPE && mAutoplayNsfwVideos)) || post.isSpoiler() && mNeedBlurSpoiler) { + imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 10))) + .into(((PostGalleryTypeViewHolder) holder).imageView); + } else { + if (mImageViewWidth > post.getPreviewWidth()) { + imageRequestBuilder.override(Target.SIZE_ORIGINAL).into(((PostGalleryTypeViewHolder) holder).imageView); + } else { + imageRequestBuilder.into(((PostGalleryTypeViewHolder) holder).imageView); + } + } } else if (holder instanceof PostCompactBaseViewHolder) { String previewUrl = post.getThumbnailPreviewUrl().equals("") ? post.getPreviewUrl() : post.getThumbnailPreviewUrl(); RequestBuilder<Drawable> imageRequestBuilder = mGlide.load(previewUrl) @@ -1107,6 +1153,11 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView mGlide.clear(((PostLinkTypeViewHolder) holder).imageView); ((PostLinkTypeViewHolder) holder).imageView.getLayoutParams().height = FrameLayout.LayoutParams.WRAP_CONTENT; ((PostLinkTypeViewHolder) holder).errorRelativeLayout.setVisibility(View.GONE); + } else if (holder instanceof PostGalleryTypeViewHolder) { + mGlide.clear(((PostGalleryTypeViewHolder) holder).imageView); + ((PostGalleryTypeViewHolder) holder).imageWrapperRelativeLayout.setVisibility(View.GONE); + ((PostGalleryTypeViewHolder) holder).errorRelativeLayout.setVisibility(View.GONE); + ((PostGalleryTypeViewHolder) holder).noPreviewLinkImageView.setVisibility(View.GONE); } else if (holder instanceof PostTextTypeViewHolder) { ((PostTextTypeViewHolder) holder).contentTextView.setVisibility(View.GONE); } @@ -2233,6 +2284,109 @@ public class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView } } + class PostGalleryTypeViewHolder extends PostBaseViewHolder { + @BindView(R.id.card_view_item_post_gallery_type) + MaterialCardView cardView; + @BindView(R.id.icon_gif_image_view_item_post_gallery_type) + AspectRatioGifImageView iconGifImageView; + @BindView(R.id.subreddit_name_text_view_item_post_gallery_type) + TextView subredditTextView; + @BindView(R.id.user_text_view_item_post_gallery_type) + TextView userTextView; + @BindView(R.id.stickied_post_image_view_item_post_gallery_type) + ImageView stickiedPostImageView; + @BindView(R.id.post_time_text_view_item_post_gallery_type) + TextView postTimeTextView; + @BindView(R.id.title_text_view_item_post_gallery_type) + TextView titleTextView; + @BindView(R.id.type_text_view_item_post_gallery_type) + CustomTextView typeTextView; + @BindView(R.id.archived_image_view_item_post_gallery_type) + ImageView archivedImageView; + @BindView(R.id.locked_image_view_item_post_gallery_type) + ImageView lockedImageView; + @BindView(R.id.crosspost_image_view_item_post_gallery_type) + ImageView crosspostImageView; + @BindView(R.id.nsfw_text_view_item_post_gallery_type) + CustomTextView nsfwTextView; + @BindView(R.id.spoiler_custom_text_view_item_post_gallery_type) + CustomTextView spoilerTextView; + @BindView(R.id.flair_custom_text_view_item_post_gallery_type) + CustomTextView flairTextView; + @BindView(R.id.awards_text_view_item_post_gallery_type) + CustomTextView awardsTextView; + @BindView(R.id.image_wrapper_relative_layout_item_post_gallery) + RelativeLayout imageWrapperRelativeLayout; + @BindView(R.id.progress_bar_item_post_gallery_type) + ProgressBar progressBar; + @BindView(R.id.image_view_item_post_gallery_type) + AspectRatioGifImageView imageView; + @BindView(R.id.load_image_error_relative_layout_item_post_gallery_type) + RelativeLayout errorRelativeLayout; + @BindView(R.id.load_image_error_text_view_item_post_gallery_type) + TextView errorTextView; + @BindView(R.id.image_view_no_preview_gallery_item_post_gallery_type) + ImageView noPreviewLinkImageView; + @BindView(R.id.bottom_constraint_layout_item_post_gallery_type) + ConstraintLayout bottomConstraintLayout; + @BindView(R.id.plus_button_item_post_gallery_type) + ImageView upvoteButton; + @BindView(R.id.score_text_view_item_post_gallery_type) + TextView scoreTextView; + @BindView(R.id.minus_button_item_post_gallery_type) + ImageView downvoteButton; + @BindView(R.id.comments_count_item_post_gallery_type) + TextView commentsCountTextView; + @BindView(R.id.save_button_item_post_gallery_type) + ImageView saveButton; + @BindView(R.id.share_button_item_post_gallery_type) + ImageView shareButton; + + PostGalleryTypeViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + setBaseView(cardView, + iconGifImageView, + subredditTextView, + userTextView, + stickiedPostImageView, + postTimeTextView, + titleTextView, + typeTextView, + archivedImageView, + lockedImageView, + crosspostImageView, + nsfwTextView, + spoilerTextView, + flairTextView, + awardsTextView, + bottomConstraintLayout, + upvoteButton, + scoreTextView, + downvoteButton, + commentsCountTextView, + saveButton, + shareButton); + + noPreviewLinkImageView.setBackgroundColor(mNoPreviewLinkBackgroundColor); + progressBar.setIndeterminateTintList(ColorStateList.valueOf(mColorAccent)); + errorTextView.setTextColor(mPrimaryTextColor); + + imageView.setOnClickListener(view -> { + Post post = getItem(getAdapterPosition()); + if (post != null) { + Intent intent = new Intent(mActivity, ViewRedditGalleryActivity.class); + intent.putParcelableArrayListExtra(ViewRedditGalleryActivity.EXTRA_REDDIT_GALLERY, post.getGallery()); + mActivity.startActivity(intent); + } + }); + + noPreviewLinkImageView.setOnClickListener(view -> { + imageView.performClick(); + }); + } + } + class PostTextTypeViewHolder extends PostBaseViewHolder { @BindView(R.id.card_view_item_post_text_type) MaterialCardView cardView; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java index cd75c469..3542c686 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java @@ -38,6 +38,7 @@ import ml.docilealligator.infinityforreddit.Activity.InboxActivity; import ml.docilealligator.infinityforreddit.Activity.ViewMultiRedditDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewPostDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewPrivateMessagesActivity; +import ml.docilealligator.infinityforreddit.Activity.ViewRedditGalleryActivity; import ml.docilealligator.infinityforreddit.Activity.ViewSubredditDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewUserDetailActivity; import ml.docilealligator.infinityforreddit.Activity.ViewVideoActivity; @@ -52,6 +53,7 @@ import ml.docilealligator.infinityforreddit.Fragment.SubredditListingFragment; import ml.docilealligator.infinityforreddit.Fragment.SubscribedSubredditsListingFragment; import ml.docilealligator.infinityforreddit.Fragment.UserListingFragment; import ml.docilealligator.infinityforreddit.Fragment.ViewImgurVideoFragment; +import ml.docilealligator.infinityforreddit.Fragment.ViewRedditGalleryVideoFragment; import ml.docilealligator.infinityforreddit.Service.DownloadRedditVideoService; import ml.docilealligator.infinityforreddit.Service.SubmitPostService; import ml.docilealligator.infinityforreddit.Settings.AdvancedPreferenceFragment; @@ -182,4 +184,8 @@ public interface AppComponent { void inject(SendPrivateMessageActivity sendPrivateMessageActivity); void inject(VideoPreferenceFragment videoPreferenceFragment); + + void inject(ViewRedditGalleryActivity viewRedditGalleryActivity); + + void inject(ViewRedditGalleryVideoFragment viewRedditGalleryVideoFragment); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java index 83411416..d6651066 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurImageFragment.java @@ -139,14 +139,14 @@ public class ViewImgurImageFragment extends Fragment { @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.view_imgur_image_fragments, menu); + inflater.inflate(R.menu.view_imgur_image_fragment, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { - case R.id.action_download_view_imgur_image_fragments: + case R.id.action_download_view_imgur_image_fragment: if (isDownloading) { return false; } @@ -172,7 +172,7 @@ public class ViewImgurImageFragment extends Fragment { } return true; - case R.id.action_share_view_imgur_image_fragments: + case R.id.action_share_view_imgur_image_fragment: glide.asBitmap().load(imgurMedia.getLink()).into(new CustomTarget<Bitmap>() { @Override @@ -212,7 +212,7 @@ public class ViewImgurImageFragment extends Fragment { } }); return true; - case R.id.action_set_wallpaper_view_imgur_image_fragments: + case R.id.action_set_wallpaper_view_imgur_image_fragment: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { SetAsWallpaperBottomSheetFragment setAsWallpaperBottomSheetFragment = new SetAsWallpaperBottomSheetFragment(); Bundle bundle = new Bundle(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java index e64ad295..30a00c21 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewImgurVideoFragment.java @@ -52,9 +52,6 @@ import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; -/** - * A simple {@link Fragment} subclass. - */ public class ViewImgurVideoFragment extends Fragment { public static final String EXTRA_IMGUR_VIDEO = "EIV"; @@ -154,7 +151,7 @@ public class ViewImgurVideoFragment extends Fragment { @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.action_download_view_imgur_image_fragments) { + if (item.getItemId() == R.id.action_download_view_imgur_video_fragment) { isDownloading = true; if (Build.VERSION.SDK_INT >= 23) { if (ContextCompat.checkSelfPermission(activity, diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java new file mode 100644 index 00000000..2d456910 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryImageOrGifFragment.java @@ -0,0 +1,297 @@ +package ml.docilealligator.infinityforreddit.Fragment; + +import android.Manifest; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +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.LinearLayout; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.fragment.app.Fragment; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.resource.gif.GifDrawable; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.target.Target; +import com.bumptech.glide.request.transition.Transition; +import com.davemorrissey.labs.subscaleview.ImageSource; +import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; + +import java.io.File; + +import butterknife.BindView; +import butterknife.ButterKnife; +import ml.docilealligator.infinityforreddit.Activity.ViewRedditGalleryActivity; +import ml.docilealligator.infinityforreddit.AsyncTask.SaveGIFToFileAsyncTask; +import ml.docilealligator.infinityforreddit.AsyncTask.SaveImageToFileAsyncTask; +import ml.docilealligator.infinityforreddit.BottomSheetFragment.SetAsWallpaperBottomSheetFragment; +import ml.docilealligator.infinityforreddit.BuildConfig; +import ml.docilealligator.infinityforreddit.MediaDownloader; +import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; +import ml.docilealligator.infinityforreddit.Post.Post; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.SetAsWallpaperCallback; + +public class ViewRedditGalleryImageOrGifFragment extends Fragment { + + public static final String EXTRA_REDDIT_GALLERY_MEDIA = "ERGM"; + private static final int PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 0; + + @BindView(R.id.progress_bar_view_reddit_gallery_image_or_gif_fragment) + ProgressBar progressBar; + @BindView(R.id.image_view_view_reddit_gallery_image_or_gif_fragment) + SubsamplingScaleImageView imageView; + @BindView(R.id.load_image_error_linear_layout_view_reddit_gallery_image_or_gif_fragment) + LinearLayout errorLinearLayout; + + private ViewRedditGalleryActivity activity; + private RequestManager glide; + private MediaDownloader mediaDownloader; + private Post.Gallery media; + private boolean isDownloading = false; + private boolean isActionBarHidden = false; + + public ViewRedditGalleryImageOrGifFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_view_reddit_gallery_image_or_gif, container, false); + + ButterKnife.bind(this, rootView); + + setHasOptionsMenu(true); + + media = getArguments().getParcelable(EXTRA_REDDIT_GALLERY_MEDIA); + glide = Glide.with(activity); + mediaDownloader = new MediaDownloaderImpl(); + loadImage(); + + imageView.setOnClickListener(view -> { + if (isActionBarHidden) { + activity.getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + isActionBarHidden = false; + } else { + activity.getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE); + isActionBarHidden = true; + } + }); + + return rootView; + } + + private void loadImage() { + glide.asBitmap().load(media.url).listener(new RequestListener<Bitmap>() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) { + progressBar.setVisibility(View.GONE); + errorLinearLayout.setVisibility(View.VISIBLE); + return false; + } + + @Override + public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) { + progressBar.setVisibility(View.GONE); + return false; + } + }).into(new CustomTarget<Bitmap>() { + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { + imageView.setImage(ImageSource.bitmap(resource)); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + inflater.inflate(R.menu.view_reddit_gallery_image_or_gif_fragment, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.action_download_view_reddit_gallery_image_or_gif_fragment: + if (isDownloading) { + return false; + } + + isDownloading = true; + + if (Build.VERSION.SDK_INT >= 23) { + if (ContextCompat.checkSelfPermission(activity, + Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + + // Permission is not granted + // No explanation needed; request the permission + ActivityCompat.requestPermissions(activity, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); + } else { + // Permission has already been granted + mediaDownloader.download(media.url, media.fileName, getContext()); + } + } else { + mediaDownloader.download(media.url, media.fileName, getContext()); + } + + return true; + case R.id.action_share_view_reddit_gallery_image_or_gif_fragment: + if (media.mediaType == Post.Gallery.TYPE_GIF) { + shareGif(); + } else { + shareImage(); + } + return true; + case R.id.action_set_wallpaper_view_reddit_gallery_image_or_gif_fragment: + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + SetAsWallpaperBottomSheetFragment setAsWallpaperBottomSheetFragment = new SetAsWallpaperBottomSheetFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(SetAsWallpaperBottomSheetFragment.EXTRA_VIEW_PAGER_POSITION, activity.getCurrentPagePosition()); + setAsWallpaperBottomSheetFragment.setArguments(bundle); + setAsWallpaperBottomSheetFragment.show(activity.getSupportFragmentManager(), setAsWallpaperBottomSheetFragment.getTag()); + } else { + ((SetAsWallpaperCallback) activity).setToBoth(activity.getCurrentPagePosition()); + } + return true; + } + + return false; + } + + private void shareImage() { + glide.asBitmap().load(media.url).into(new CustomTarget<Bitmap>() { + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { + if (activity.getExternalCacheDir() != null) { + Toast.makeText(activity, R.string.save_image_first, Toast.LENGTH_SHORT).show(); + new SaveImageToFileAsyncTask(resource, activity.getExternalCacheDir().getPath(), + media.fileName, + new SaveImageToFileAsyncTask.SaveImageToFileAsyncTaskListener() { + @Override + public void saveSuccess(File imageFile) { + Uri uri = FileProvider.getUriForFile(activity, + BuildConfig.APPLICATION_ID + ".provider", imageFile); + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_STREAM, uri); + shareIntent.setType("image/*"); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + startActivity(Intent.createChooser(shareIntent, getString(R.string.share))); + } + + @Override + public void saveFailed() { + Toast.makeText(activity, + R.string.cannot_save_image, Toast.LENGTH_SHORT).show(); + } + }).execute(); + } else { + Toast.makeText(activity, + R.string.cannot_get_storage, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } + + private void shareGif() { + Toast.makeText(activity, R.string.save_gif_first, Toast.LENGTH_SHORT).show(); + glide.asGif().load(media.url).listener(new RequestListener<GifDrawable>() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) { + if (activity.getExternalCacheDir() != null) { + new SaveGIFToFileAsyncTask(resource, activity.getExternalCacheDir().getPath(), media.fileName, + new SaveGIFToFileAsyncTask.SaveGIFToFileAsyncTaskListener() { + @Override + public void saveSuccess(File imageFile) { + Uri uri = FileProvider.getUriForFile(activity, + BuildConfig.APPLICATION_ID + ".provider", imageFile); + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_STREAM, uri); + shareIntent.setType("image/*"); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + startActivity(Intent.createChooser(shareIntent, getString(R.string.share))); + } + + @Override + public void saveFailed() { + Toast.makeText(activity, + R.string.cannot_save_gif, Toast.LENGTH_SHORT).show(); + } + }).execute(); + } else { + Toast.makeText(activity, + R.string.cannot_get_storage, Toast.LENGTH_SHORT).show(); + } + return false; + } + }).submit(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { + if (grantResults[0] == PackageManager.PERMISSION_DENIED) { + Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { + mediaDownloader.download(media.url, media.fileName, getContext()); + } + isDownloading = false; + } + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + activity = (ViewRedditGalleryActivity) context; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java new file mode 100644 index 00000000..2a0ec80f --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewRedditGalleryVideoFragment.java @@ -0,0 +1,285 @@ +package ml.docilealligator.infinityforreddit.Fragment; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +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.ImageButton; +import android.widget.LinearLayout; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + +import com.google.android.exoplayer2.ExoPlayerFactory; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.source.ProgressiveMediaSource; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.ui.PlayerView; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; +import com.google.android.exoplayer2.util.Util; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import ml.docilealligator.infinityforreddit.Infinity; +import ml.docilealligator.infinityforreddit.MediaDownloader; +import ml.docilealligator.infinityforreddit.MediaDownloaderImpl; +import ml.docilealligator.infinityforreddit.Post.Post; +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.Utils.SharedPreferencesUtils; + +public class ViewRedditGalleryVideoFragment extends Fragment { + + public static final String EXTRA_REDDIT_GALLERY_VIDEO = "EIV"; + private static final String IS_MUTE_STATE = "IMS"; + private static final String POSITION_STATE = "PS"; + private static final int PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 0; + @BindView(R.id.player_view_view_reddit_gallery_video_fragment) + PlayerView videoPlayerView; + @BindView(R.id.mute_exo_playback_control_view) + ImageButton muteButton; + private Activity activity; + private Post.Gallery galleryVideo; + private SimpleExoPlayer player; + private DataSource.Factory dataSourceFactory; + private MediaDownloader mediaDownloader; + private boolean wasPlaying = false; + private boolean isMute = false; + private boolean isDownloading = false; + @Inject + @Named("default") + SharedPreferences mSharedPreferences; + + public ViewRedditGalleryVideoFragment() { + // Required empty public constructor + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_view_reddit_gallery_video, container, false); + + ((Infinity) activity.getApplication()).getAppComponent().inject(this); + + ButterKnife.bind(this, rootView); + + setHasOptionsMenu(true); + + activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); + + galleryVideo = getArguments().getParcelable(EXTRA_REDDIT_GALLERY_VIDEO); + + if (!mSharedPreferences.getBoolean(SharedPreferencesUtils.VIDEO_PLAYER_IGNORE_NAV_BAR, false)) { + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT || getResources().getBoolean(R.bool.isTablet)) { + //Set player controller bottom margin in order to display it above the navbar + int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android"); + LinearLayout controllerLinearLayout = rootView.findViewById(R.id.linear_layout_exo_playback_control_view); + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) controllerLinearLayout.getLayoutParams(); + params.bottomMargin = getResources().getDimensionPixelSize(resourceId); + } else { + //Set player controller right margin in order to display it above the navbar + int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android"); + LinearLayout controllerLinearLayout = rootView.findViewById(R.id.linear_layout_exo_playback_control_view); + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) controllerLinearLayout.getLayoutParams(); + params.rightMargin = getResources().getDimensionPixelSize(resourceId); + } + } + + videoPlayerView.setControllerVisibilityListener(visibility -> { + switch (visibility) { + case View.GONE: + activity.getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE); + break; + case View.VISIBLE: + activity.getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } + }); + + mediaDownloader = new MediaDownloaderImpl(); + + TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(); + TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); + player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector); + videoPlayerView.setPlayer(player); + dataSourceFactory = new DefaultDataSourceFactory(activity, + Util.getUserAgent(activity, "Infinity")); + player.prepare(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(galleryVideo.url))); + preparePlayer(savedInstanceState); + + return rootView; + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + inflater.inflate(R.menu.view_reddit_gallery_video_fragment, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == R.id.action_download_view_reddit_gallery_video_fragment) { + isDownloading = true; + if (Build.VERSION.SDK_INT >= 23) { + if (ContextCompat.checkSelfPermission(activity, + Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + + // Permission is not granted + // No explanation needed; request the permission + ActivityCompat.requestPermissions(activity, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); + } else { + // Permission has already been granted + download(); + } + } else { + download(); + } + return true; + } + return false; + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) { + if (grantResults[0] == PackageManager.PERMISSION_DENIED) { + Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && isDownloading) { + download(); + } + isDownloading = false; + } + } + + private void download() { + isDownloading = false; + + mediaDownloader.download(galleryVideo.url, galleryVideo.fileName, getContext()); + } + + private void preparePlayer(Bundle savedInstanceState) { + player.setRepeatMode(Player.REPEAT_MODE_ALL); + wasPlaying = true; + + boolean muteVideo = mSharedPreferences.getBoolean(SharedPreferencesUtils.MUTE_VIDEO, false); + + if (savedInstanceState != null) { + long position = savedInstanceState.getLong(POSITION_STATE); + if (position > 0) { + player.seekTo(position); + } + isMute = savedInstanceState.getBoolean(IS_MUTE_STATE); + if (isMute) { + player.setVolume(0f); + muteButton.setImageResource(R.drawable.ic_mute_24dp); + } else { + player.setVolume(1f); + muteButton.setImageResource(R.drawable.ic_unmute_24dp); + } + } else if (muteVideo) { + isMute = true; + player.setVolume(0f); + muteButton.setImageResource(R.drawable.ic_mute_24dp); + } else { + muteButton.setImageResource(R.drawable.ic_unmute_24dp); + } + + player.addListener(new Player.EventListener() { + @Override + public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + if (!trackGroups.isEmpty()) { + for (int i = 0; i < trackGroups.length; i++) { + String mimeType = trackGroups.get(i).getFormat(0).sampleMimeType; + if (mimeType != null && mimeType.contains("audio")) { + muteButton.setVisibility(View.VISIBLE); + muteButton.setOnClickListener(view -> { + if (isMute) { + isMute = false; + player.setVolume(1f); + muteButton.setImageResource(R.drawable.ic_unmute_24dp); + } else { + isMute = true; + player.setVolume(0f); + muteButton.setImageResource(R.drawable.ic_mute_24dp); + } + }); + break; + } + } + } else { + muteButton.setVisibility(View.GONE); + } + } + }); + } + + @Override + public void onResume() { + super.onResume(); + if (wasPlaying) { + player.setPlayWhenReady(true); + } + } + + @Override + public void onPause() { + super.onPause(); + wasPlaying = player.getPlayWhenReady(); + player.setPlayWhenReady(false); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(IS_MUTE_STATE, isMute); + outState.putLong(POSITION_STATE, player.getCurrentPosition()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + player.release(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + activity = (Activity) context; + } +}
\ 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 fd54a613..17bb9bba 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/ParsePost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/ParsePost.java @@ -8,6 +8,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.Locale; @@ -388,6 +389,30 @@ public class ParsePost { post.setUrl(url); } } catch (IllegalArgumentException ignore) { } + } else if (post.getPostType() == Post.LINK_TYPE || post.getPostType() == Post.NO_PREVIEW_LINK_TYPE) { + if (data.has(JSONUtils.GALLERY_DATA_KEY)) { + JSONArray galleryIdsArray = data.getJSONObject(JSONUtils.GALLERY_DATA_KEY).getJSONArray(JSONUtils.ITEMS_KEY); + JSONObject galleryObject = data.getJSONObject(JSONUtils.MEDIA_METADATA_KEY); + ArrayList<Post.Gallery> gallery = new ArrayList<>(); + for (int i = 0; i < galleryIdsArray.length(); i++) { + String galleryId = galleryIdsArray.getJSONObject(i).getString(JSONUtils.MEDIA_ID_KEY); + JSONObject singleGalleryObject = galleryObject.getJSONObject(galleryId); + String mimeType = singleGalleryObject.getString(JSONUtils.M_KEY); + String galleryItemUrl = singleGalleryObject.getJSONObject(JSONUtils.S_KEY).getString(JSONUtils.U_KEY); + if ((previewUrl.equals("")) && mimeType.contains("jpg") || mimeType.contains("png")) { + previewUrl = galleryItemUrl; + post.setPreviewUrl(previewUrl); + post.setPreviewWidth(singleGalleryObject.getJSONObject(JSONUtils.S_KEY).getInt(JSONUtils.X_KEY)); + post.setPreviewHeight(singleGalleryObject.getJSONObject(JSONUtils.S_KEY).getInt(JSONUtils.Y_KEY)); + } + gallery.add(new Post.Gallery(mimeType, galleryItemUrl, subredditName + "-" + galleryId + "." + mimeType.substring(mimeType.lastIndexOf("/") + 1))); + } + + if (!gallery.isEmpty()) { + post.setPostType(Post.GALLERY_TYPE); + post.setGallery(gallery); + } + } } return post; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/Post.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/Post.java index 9cea2b6a..a1a8c9c7 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Post/Post.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Post/Post.java @@ -5,6 +5,8 @@ import android.os.Parcelable; import androidx.annotation.Nullable; +import java.util.ArrayList; + import ml.docilealligator.infinityforreddit.Utils.APIUtils; /** @@ -19,6 +21,7 @@ public class Post implements Parcelable { public static final int VIDEO_TYPE = 3; public static final int GIF_TYPE = 4; public static final int NO_PREVIEW_LINK_TYPE = 5; + public static final int GALLERY_TYPE = 6; public static final Creator<Post> CREATOR = new Creator<Post>() { @Override public Post createFromParcel(Parcel in) { @@ -69,6 +72,7 @@ public class Post implements Parcelable { private boolean saved; private boolean isCrosspost; private String crosspostParentId; + private ArrayList<Gallery> gallery = new ArrayList<>(); public Post(String id, String fullName, String subredditName, String subredditNamePrefixed, String author, String authorFlair, String authorFlairHTML, @@ -217,6 +221,7 @@ public class Post implements Parcelable { saved = in.readByte() != 0; isCrosspost = in.readByte() != 0; crosspostParentId = in.readString(); + in.readTypedList(gallery, Gallery.CREATOR); } public String getId() { @@ -312,6 +317,10 @@ public class Post implements Parcelable { return previewUrl; } + public void setPreviewUrl(String previewUrl) { + this.previewUrl = previewUrl; + } + public String getThumbnailPreviewUrl() { return thumbnailPreviewUrl; } @@ -473,6 +482,14 @@ public class Post implements Parcelable { this.crosspostParentId = crosspostParentId; } + public ArrayList<Gallery> getGallery() { + return gallery; + } + + public void setGallery(ArrayList<Gallery> gallery) { + this.gallery = gallery; + } + @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(id); @@ -514,6 +531,7 @@ public class Post implements Parcelable { parcel.writeByte((byte) (saved ? 1 : 0)); parcel.writeByte((byte) (isCrosspost ? 1 : 0)); parcel.writeString(crosspostParentId); + parcel.writeTypedList(gallery); } @Override @@ -528,4 +546,60 @@ public class Post implements Parcelable { public int hashCode() { return id.hashCode(); } + + public static class Gallery implements Parcelable{ + public static final int TYPE_IMAGE = 0; + public static final int TYPE_GIF = 1; + public static final int TYPE_VIDEO = 2; + + public String mimeType; + public String url; + public String fileName; + public int mediaType; + + public Gallery(String mimeType, String url, String fileName) { + this.mimeType = mimeType; + this.url = url; + this.fileName = fileName; + if (mimeType.contains("gif")) { + mediaType = TYPE_GIF; + } else if (mimeType.contains("jpg") || mimeType.contains("png")) { + mediaType = TYPE_IMAGE; + } else { + mediaType = TYPE_VIDEO; + } + } + + protected Gallery(Parcel in) { + mimeType = in.readString(); + url = in.readString(); + fileName = in.readString(); + mediaType = in.readInt(); + } + + public static final Creator<Gallery> CREATOR = new Creator<Gallery>() { + @Override + public Gallery createFromParcel(Parcel in) { + return new Gallery(in); + } + + @Override + public Gallery[] newArray(int size) { + return new Gallery[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(mimeType); + parcel.writeString(url); + parcel.writeString(fileName); + parcel.writeInt(mediaType); + } + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/JSONUtils.java index 5e83152d..28c6ddfe 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/JSONUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Utils/JSONUtils.java @@ -113,4 +113,12 @@ public class JSONUtils { public static final String TYPE_KEY = "type"; public static final String MP4_KEY = "mp4"; public static final String THINGS_KEY = "things"; + public static final String MEDIA_METADATA_KEY = "media_metadata"; + public static final String GALLERY_DATA_KEY = "gallery_data"; + public static final String ITEMS_KEY = "items"; + public static final String M_KEY = "m"; + public static final String MEDIA_ID_KEY = "media_id"; + public static final String S_KEY = "s"; + public static final String X_KEY = "x"; + public static final String Y_KEY = "y"; } |