diff --git a/src/main/java/org/quantumbadger/redreader/common/ImagePreviewUtils.java b/src/main/java/org/quantumbadger/redreader/common/ImagePreviewUtils.java
new file mode 100644
index 000000000..104dc19c8
--- /dev/null
+++ b/src/main/java/org/quantumbadger/redreader/common/ImagePreviewUtils.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * This file is part of RedReader.
+ *
+ * RedReader is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RedReader is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RedReader. If not, see .
+ ******************************************************************************/
+
+package org.quantumbadger.redreader.common;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.quantumbadger.redreader.R;
+import org.quantumbadger.redreader.activities.BaseActivity;
+import org.quantumbadger.redreader.account.RedditAccountManager;
+import org.quantumbadger.redreader.cache.CacheManager;
+import org.quantumbadger.redreader.cache.CacheRequest;
+import org.quantumbadger.redreader.cache.CacheRequestCallbacks;
+import org.quantumbadger.redreader.cache.downloadstrategy.DownloadStrategyIfNotCached;
+import org.quantumbadger.redreader.common.datastream.SeekableInputStream;
+import org.quantumbadger.redreader.common.time.TimestampUTC;
+import org.quantumbadger.redreader.reddit.prepared.RedditParsedPost;
+import org.quantumbadger.redreader.reddit.prepared.RedditPreparedPost;
+import org.quantumbadger.redreader.views.RRAnimationShrinkHeight;
+import org.quantumbadger.redreader.views.liststatus.ErrorView;
+
+public class ImagePreviewUtils {
+
+ private static final String TAG = "ImagePreviewUtils";
+ private static final String PROMPT_PREF_KEY = "inline_image_prompt_accepted";
+ private static final AtomicInteger sInlinePreviewsShownThisSession = new AtomicInteger(0);
+
+ public interface ImagePreviewListener {
+ void setImageBitmap(Bitmap bitmap);
+ void setLoadingSpinnerVisible(boolean visible);
+ void setOuterViewVisible(boolean visible);
+ void setPlayOverlayVisible(boolean visible);
+ void setPreviewDimensions(String ratio);
+ LinearLayout getFooterView();
+ BaseActivity getActivity();
+ boolean isUsageIdValid(int usageId);
+ void addErrorView(ErrorView errorView);
+ void setErrorViewLayout(View errorView);
+ }
+
+ public static void showPrefPrompt(final ImagePreviewListener listener) {
+ final BaseActivity activity = listener.getActivity();
+ final SharedPrefsWrapper sharedPrefs = General.getSharedPrefs(activity);
+
+ LayoutInflater.from(activity).inflate(
+ R.layout.inline_images_question_view,
+ listener.getFooterView(),
+ true);
+
+ final FrameLayout promptView = listener.getFooterView()
+ .findViewById(R.id.inline_images_prompt_root);
+ final Button keepShowing = listener.getFooterView()
+ .findViewById(R.id.inline_preview_prompt_keep_showing_button);
+ final Button turnOff = listener.getFooterView()
+ .findViewById(R.id.inline_preview_prompt_turn_off_button);
+
+ keepShowing.setOnClickListener(v -> {
+ new RRAnimationShrinkHeight(promptView).start();
+ sharedPrefs.edit()
+ .putBoolean(PROMPT_PREF_KEY, true)
+ .apply();
+ });
+
+ turnOff.setOnClickListener(v -> {
+ final String prefPreview = activity.getApplicationContext()
+ .getString(R.string.pref_images_inline_image_previews_key);
+ sharedPrefs.edit()
+ .putBoolean(PROMPT_PREF_KEY, true)
+ .putString(prefPreview, "never")
+ .apply();
+ });
+ }
+
+ public static void downloadInlinePreview(
+ @NonNull final BaseActivity activity,
+ @NonNull final RedditPreparedPost post,
+ @NonNull final ImagePreviewListener listener,
+ final int usageId) {
+
+ final Rect windowVisibleDisplayFrame = DisplayUtils.getWindowVisibleDisplayFrame(activity);
+
+ final int screenWidth = Math.min(1080, Math.max(720, windowVisibleDisplayFrame.width()));
+ final int screenHeight = Math.min(2000, Math.max(400, windowVisibleDisplayFrame.height()));
+
+ final RedditParsedPost.ImagePreviewDetails preview = post.src.getPreview(screenWidth, 0);
+
+ if(preview == null || preview.width < 10 || preview.height < 10) {
+ listener.setOuterViewVisible(false);
+ listener.setLoadingSpinnerVisible(false);
+ return;
+ }
+
+ final int boundedImageHeight = Math.min(
+ (screenHeight * 2) / 3,
+ (int)(((long)preview.height * screenWidth) / preview.width));
+
+ listener.setPreviewDimensions(screenWidth + ":" + boundedImageHeight);
+ listener.setOuterViewVisible(true);
+ listener.setLoadingSpinnerVisible(true);
+
+ CacheManager.getInstance(activity).makeRequest(new CacheRequest(
+ preview.url,
+ RedditAccountManager.getAnon(),
+ null,
+ new Priority(Constants.Priority.INLINE_IMAGE_PREVIEW),
+ DownloadStrategyIfNotCached.INSTANCE,
+ Constants.FileType.INLINE_IMAGE_PREVIEW,
+ CacheRequest.DownloadQueueType.IMMEDIATE,
+ activity,
+ new CacheRequestCallbacks() {
+ @Override
+ public void onDataStreamComplete(
+ @NonNull final GenericFactory stream,
+ final TimestampUTC timestamp,
+ @NonNull final UUID session,
+ final boolean fromCache,
+ @Nullable final String mimetype) {
+
+ if(!listener.isUsageIdValid(usageId)) {
+ return;
+ }
+
+ try(InputStream is = stream.create()) {
+ final Bitmap data = BitmapFactory.decodeStream(is);
+
+ if(data == null) {
+ throw new IOException("Failed to decode bitmap");
+ }
+
+ // Avoid a crash on badly behaving Android ROMs (where the ImageView
+ // crashes if an image is too big)
+ // Should never happen as we limit the preview size to 3000x3000
+ if(data.getByteCount() > 50 * 1024 * 1024) {
+ throw new RuntimeException("Image was too large: "
+ + data.getByteCount()
+ + ", preview URL was "
+ + preview.url
+ + " and post was "
+ + post.src.getIdAndType());
+ }
+
+ final boolean alreadyAcceptedPrompt = General.getSharedPrefs(activity)
+ .getBoolean(PROMPT_PREF_KEY, false);
+
+ final int totalPreviewsShown
+ = sInlinePreviewsShownThisSession.incrementAndGet();
+
+ final boolean isVideoPreview = post.isVideoPreview();
+
+ AndroidCommon.runOnUiThread(() -> {
+ listener.setImageBitmap(data);
+ listener.setLoadingSpinnerVisible(false);
+
+ if(isVideoPreview) {
+ listener.setPlayOverlayVisible(true);
+ }
+
+ // Show every 8 previews, starting at the second one
+ if(totalPreviewsShown % 8 == 2 && !alreadyAcceptedPrompt) {
+ showPrefPrompt(listener);
+ }
+ });
+
+ } catch(final Throwable t) {
+ onFailure(General.getGeneralErrorForFailure(
+ activity,
+ CacheRequest.RequestFailureType.CONNECTION,
+ t,
+ null,
+ preview.url,
+ Optional.empty()));
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull final RRError error) {
+ Log.e(TAG, "Failed to download image preview: " + error, error.t);
+
+ if(!listener.isUsageIdValid(usageId)) {
+ return;
+ }
+
+ AndroidCommon.runOnUiThread(() -> {
+ listener.setLoadingSpinnerVisible(false);
+ listener.setOuterViewVisible(false);
+
+ final ErrorView errorView = new ErrorView(
+ activity,
+ error);
+
+ listener.addErrorView(errorView);
+ listener.setErrorViewLayout(errorView);
+ });
+ }
+ }
+ ));
+ }
+}
diff --git a/src/main/java/org/quantumbadger/redreader/common/PrefsUtility.java b/src/main/java/org/quantumbadger/redreader/common/PrefsUtility.java
index 1262439fb..9a2a96aa2 100644
--- a/src/main/java/org/quantumbadger/redreader/common/PrefsUtility.java
+++ b/src/main/java/org/quantumbadger/redreader/common/PrefsUtility.java
@@ -59,6 +59,10 @@ public final class PrefsUtility {
private static SharedPrefsWrapper sharedPrefs;
private static Resources mRes;
+ public static String getLayoutMode() {
+ return sharedPrefs.getString("pref_layout_mode", "thumbnails");
+ }
+
private static String getPrefKey(@StringRes final int prefKey) {
return mRes.getString(prefKey);
}
diff --git a/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditParsedPost.kt b/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditParsedPost.kt
index bd4f51a08..8979ce331 100644
--- a/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditParsedPost.kt
+++ b/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditParsedPost.kt
@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with RedReader. If not, see .
******************************************************************************/
+
package org.quantumbadger.redreader.reddit.prepared
import androidx.appcompat.app.AppCompatActivity
@@ -141,9 +142,25 @@ class RedditParsedPost(
@JvmField val height: Int
)
- fun getPreview(minWidth: Int, minHeight: Int) = src.preview?.images?.get(0)?.run {
- getPreviewInternal(this, minWidth, minHeight)
- }
+
+ val isGallery = src.gallery_data?.items?.firstOrNull()?.ok()?.media_id != null
+
+ fun getPreview(minWidth: Int, minHeight: Int): ImagePreviewDetails? {
+ if (isGallery) {
+ val firstItem = src.gallery_data?.items?.firstOrNull()?.ok()?.media_id ?: return null
+ val metadata = src.media_metadata?.get(firstItem)?.ok() ?: return null
+
+ return ImagePreviewDetails(
+ UriString(metadata.s.u?.decoded ?: return null),
+ metadata.s.x.toInt(),
+ metadata.s.y.toInt()
+ )
+ }
+
+ return src.preview?.images?.get(0)?.run {
+ getPreviewInternal(this, minWidth, minHeight)
+ }
+ }
fun getPreviewMP4(minWidth: Int, minHeight: Int)
= src.preview?.images?.get(0)?.variants?.mp4?.apply {
diff --git a/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditPreparedPost.java b/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditPreparedPost.java
index ae0c90f1a..8008c6370 100644
--- a/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditPreparedPost.java
+++ b/src/main/java/org/quantumbadger/redreader/reddit/prepared/RedditPreparedPost.java
@@ -72,6 +72,7 @@ public final class RedditPreparedPost implements RedditChangeDataManager.Listene
public final boolean canModerate;
public final boolean hasThumbnail;
public final boolean mIsProbablyAnImage;
+ public final boolean isGallery;
private final boolean mShowInlinePreviews;
@@ -109,6 +110,7 @@ public RedditPreparedPost(
isArchived = post.isArchived();
isLocked = post.isLocked();
canModerate = post.getCanModerate();
+ isGallery = post.isGallery();
mIsProbablyAnImage = LinkHandler.isProbablyAnImage(post.getUrl());
@@ -127,18 +129,27 @@ public RedditPreparedPost(
}
public boolean shouldShowInlinePreview() {
+ final String layoutMode = PrefsUtility.getLayoutMode();
+ final boolean alwaysPreviewMode = layoutMode.equals("always_preview")
+ || layoutMode.equals("card");
+
return mShowInlinePreviews && (src.isPreviewEnabled()
|| "gfycat.com".equals(src.getDomain())
|| "i.imgur.com".equals(src.getDomain())
|| "streamable.com".equals(src.getDomain())
|| "i.redd.it".equals(src.getDomain())
- || "v.redd.it".equals(src.getDomain()));
+ || "v.redd.it".equals(src.getDomain())
+ || (isGallery && alwaysPreviewMode));
}
public boolean isVideoPreview() {
return src.isVideoPreview();
}
+ public boolean isGalleryPreview() {
+ return isGallery;
+ }
+
public void performAction(final BaseActivity activity, final RedditPostActions.Action action) {
RedditPostActions.INSTANCE.onActionMenuItemSelected(this, activity, action);
}
diff --git a/src/main/java/org/quantumbadger/redreader/views/RedditPostHeaderView.java b/src/main/java/org/quantumbadger/redreader/views/RedditPostHeaderView.java
index 8b1452c95..c575cc40d 100644
--- a/src/main/java/org/quantumbadger/redreader/views/RedditPostHeaderView.java
+++ b/src/main/java/org/quantumbadger/redreader/views/RedditPostHeaderView.java
@@ -26,6 +26,13 @@
import androidx.annotation.Nullable;
import androidx.appcompat.widget.TooltipCompat;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.annotation.NonNull;
+import android.graphics.Bitmap;
+
import org.quantumbadger.redreader.R;
import org.quantumbadger.redreader.account.RedditAccount;
import org.quantumbadger.redreader.account.RedditAccountManager;
@@ -37,6 +44,8 @@
import org.quantumbadger.redreader.reddit.api.RedditPostActions;
import org.quantumbadger.redreader.reddit.prepared.RedditChangeDataManager;
import org.quantumbadger.redreader.reddit.prepared.RedditPreparedPost;
+import org.quantumbadger.redreader.common.ImagePreviewUtils;
+import org.quantumbadger.redreader.views.liststatus.ErrorView;
public class RedditPostHeaderView extends LinearLayout {
@@ -45,24 +54,55 @@ public class RedditPostHeaderView extends LinearLayout {
@Nullable private final Runnable mChangeListenerAddTask;
@Nullable private final Runnable mChangeListenerRemoveTask;
+ @NonNull private final FrameLayout mImagePreviewHolder;
+ @NonNull private final ImageView mImagePreviewImageView;
+ @NonNull private final ConstraintLayout mImagePreviewPlayOverlay;
+ @NonNull private final LinearLayout mImagePreviewOuter;
+ @NonNull private final LoadingSpinnerView mImagePreviewLoadingSpinner;
+ @NonNull private final BaseActivity mActivity;
+ @NonNull private final LinearLayout mPostErrors;
+
+ static private int mUsageId = 0;
+
public RedditPostHeaderView(
final BaseActivity activity,
final RedditPreparedPost post) {
super(activity);
- final float dpScale = activity.getResources().getDisplayMetrics().density;
+ mActivity = activity;
+
+ final String layoutMode = PrefsUtility.getLayoutMode();
+
+ boolean alwaysPreviewMode = false;
+
+ switch(layoutMode) {
+ case "always_preview":
+ alwaysPreviewMode = true;
+ break;
+ case "card":
+ alwaysPreviewMode = true;
+ break;
+ default:
+ alwaysPreviewMode = false;
+ break;
+ }
+
+ final boolean showInlinePreview = alwaysPreviewMode ||
+ post.shouldShowInlinePreview();
+
+ final float dpScale = mActivity.getResources().getDisplayMetrics().density;
setOrientation(LinearLayout.VERTICAL);
- final LinearLayout greyHeader = new LinearLayout(activity);
+ final LinearLayout greyHeader = new LinearLayout(mActivity);
RedditPostActions.INSTANCE.setupAccessibilityActions(
new AccessibilityActionManager(
greyHeader,
- activity.getResources()),
+ mActivity.getResources()),
post,
- activity,
+ mActivity,
true);
greyHeader.setOrientation(LinearLayout.VERTICAL);
@@ -74,27 +114,46 @@ public RedditPostHeaderView(
final float titleFontScale = PrefsUtility.appearance_fontscale_post_header_titles();
- final TextView title = new TextView(activity);
+ final TextView title = new TextView(mActivity);
title.setTextSize(19.0f * titleFontScale);
title.setTypeface(Fonts.getRobotoLightOrAlternative());
title.setText(post.src.getTitle());
- title.setContentDescription(post.buildAccessibilityTitle(activity, true));
+ title.setContentDescription(post.buildAccessibilityTitle(mActivity, true));
title.setTextColor(Color.WHITE);
greyHeader.addView(title);
+ final View previewView = inflate(mActivity, R.layout.post_header_preview, null);
+
+ mPostErrors = previewView.findViewById(R.id.reddit_post_errors);
+
+ mImagePreviewOuter = previewView.findViewById(R.id.reddit_post_image_preview_outer);
+ mImagePreviewHolder = previewView.findViewById(R.id.reddit_post_image_preview_holder);
+ mImagePreviewImageView = previewView.findViewById(R.id.reddit_post_image_preview_imageview);
+ mImagePreviewPlayOverlay = previewView.findViewById(
+ R.id.reddit_post_image_preview_play_overlay);
+
+ mImagePreviewLoadingSpinner = new LoadingSpinnerView(mActivity);
+ mImagePreviewHolder.addView(mImagePreviewLoadingSpinner);
+
+ greyHeader.addView(previewView, greyHeader.indexOfChild(title) + 1);
+
+ if(showInlinePreview) {
+ ImagePreviewUtils.downloadInlinePreview(activity, post, previewListener, mUsageId);
+ }
+
final float subtitleFontScale =
PrefsUtility.appearance_fontscale_post_header_subtitles();
- subtitle = new TextView(activity);
+ subtitle = new TextView(mActivity);
subtitle.setTextSize(13.0f * subtitleFontScale);
- subtitle.setText(post.buildSubtitle(activity, true));
- subtitle.setContentDescription(post.buildAccessibilitySubtitle(activity, true));
+ subtitle.setText(post.buildSubtitle(mActivity, true));
+ subtitle.setContentDescription(post.buildAccessibilitySubtitle(mActivity, true));
subtitle.setTextColor(Color.rgb(200, 200, 200));
greyHeader.addView(subtitle);
{
- final TypedArray appearance = activity.obtainStyledAttributes(new int[] {
+ final TypedArray appearance = mActivity.obtainStyledAttributes(new int[] {
R.attr.rrPostListHeaderBackgroundCol});
greyHeader.setBackgroundColor(appearance.getColor(0, General.COLOR_INVALID));
@@ -105,7 +164,7 @@ public RedditPostHeaderView(
greyHeader.setOnClickListener(v -> {
if(!post.isSelf()) {
LinkHandler.onLinkClicked(
- activity,
+ mActivity,
post.src.getUrl(),
false,
post.src.getSrc());
@@ -113,14 +172,14 @@ public RedditPostHeaderView(
});
greyHeader.setOnLongClickListener(v -> {
- RedditPostActions.INSTANCE.showActionMenu(activity, post);
+ RedditPostActions.INSTANCE.showActionMenu(mActivity, post);
return true;
});
addView(greyHeader);
final RedditAccount currentUser =
- RedditAccountManager.getInstance(activity).getDefaultAccount();
+ RedditAccountManager.getInstance(mActivity).getDefaultAccount();
if(!currentUser.isAnonymous()) {
@@ -133,7 +192,7 @@ public RedditPostHeaderView(
if(!PrefsUtility.pref_appearance_hide_headertoolbar_commentlist()) {
final LinearLayout buttons =
- inflate(activity, R.layout.post_header_toolbar, this)
+ inflate(mActivity, R.layout.post_header_toolbar, this)
.findViewById(R.id.post_toolbar_layout);
for(int i = 0; i < buttons.getChildCount(); i++) {
@@ -157,32 +216,32 @@ public RedditPostHeaderView(
buttons.findViewById(R.id.post_toolbar_botton_more);
buttonAddUpvote.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.UPVOTE));
buttonRemoveUpvote.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.UNVOTE));
buttonAddDownvote.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.DOWNVOTE));
buttonRemoveDownvote.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.UNVOTE));
buttonReply.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.REPLY));
buttonShare.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.SHARE));
buttonMore.setOnClickListener(v -> post.performAction(
- activity,
+ mActivity,
RedditPostActions.Action.ACTION_MENU));
changeListener = thingIdAndType -> {
- subtitle.setText(post.buildSubtitle(activity, true));
+ subtitle.setText(post.buildSubtitle(mActivity, true));
subtitle.setContentDescription(
- post.buildAccessibilitySubtitle(activity, true));
+ post.buildAccessibilitySubtitle(mActivity, true));
final boolean isUpvoted = changeDataManager.isUpvoted(
post.src.getIdAndType());
@@ -212,9 +271,9 @@ public RedditPostHeaderView(
} else {
changeListener = thingIdAndType -> {
- subtitle.setText(post.buildSubtitle(activity, true));
+ subtitle.setText(post.buildSubtitle(mActivity, true));
subtitle.setContentDescription(
- post.buildAccessibilitySubtitle(activity, true));
+ post.buildAccessibilitySubtitle(mActivity, true));
};
}
@@ -233,6 +292,62 @@ public RedditPostHeaderView(
}
}
+ private final ImagePreviewUtils.ImagePreviewListener previewListener =
+ new ImagePreviewUtils.ImagePreviewListener() {
+ @Override
+ public void setImageBitmap(final Bitmap bitmap) {
+ mImagePreviewImageView.setImageBitmap(bitmap);
+ }
+
+ @Override
+ public void setLoadingSpinnerVisible(final boolean visible) {
+ mImagePreviewLoadingSpinner.setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ @Override
+ public void setOuterViewVisible(final boolean visible) {
+ mImagePreviewOuter.setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ @Override
+ public void setPlayOverlayVisible(final boolean visible) {
+ mImagePreviewPlayOverlay.setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ @Override
+ public void setPreviewDimensions(final String ratio) {
+ final ConstraintLayout.LayoutParams params =
+ (ConstraintLayout.LayoutParams)mImagePreviewHolder.getLayoutParams();
+ params.dimensionRatio = ratio;
+ mImagePreviewHolder.setLayoutParams(params);
+ }
+
+ @Override
+ public LinearLayout getFooterView() {
+ return null;
+ }
+
+ @Override
+ public BaseActivity getActivity() {
+ return mActivity;
+ }
+
+ @Override
+ public void addErrorView(final ErrorView errorView) {
+ mPostErrors.addView(errorView);
+ }
+
+ @Override
+ public void setErrorViewLayout(final View errorView) {
+ General.setLayoutMatchWidthWrapHeight(errorView);
+ }
+
+ @Override
+ public boolean isUsageIdValid(final int usageId) {
+ return usageId == mUsageId;
+ }
+ };
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
diff --git a/src/main/java/org/quantumbadger/redreader/views/RedditPostView.java b/src/main/java/org/quantumbadger/redreader/views/RedditPostView.java
index 6bce3e40d..8fd625749 100644
--- a/src/main/java/org/quantumbadger/redreader/views/RedditPostView.java
+++ b/src/main/java/org/quantumbadger/redreader/views/RedditPostView.java
@@ -20,68 +20,39 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintLayout;
import org.quantumbadger.redreader.R;
-import org.quantumbadger.redreader.account.RedditAccountManager;
import org.quantumbadger.redreader.activities.BaseActivity;
-import org.quantumbadger.redreader.cache.CacheManager;
-import org.quantumbadger.redreader.cache.CacheRequest;
-import org.quantumbadger.redreader.cache.CacheRequestCallbacks;
-import org.quantumbadger.redreader.cache.downloadstrategy.DownloadStrategyIfNotCached;
import org.quantumbadger.redreader.common.AndroidCommon;
-import org.quantumbadger.redreader.common.Constants;
-import org.quantumbadger.redreader.common.DisplayUtils;
import org.quantumbadger.redreader.common.General;
-import org.quantumbadger.redreader.common.GenericFactory;
-import org.quantumbadger.redreader.common.Optional;
import org.quantumbadger.redreader.common.PrefsUtility;
-import org.quantumbadger.redreader.common.Priority;
-import org.quantumbadger.redreader.common.RRError;
-import org.quantumbadger.redreader.common.SharedPrefsWrapper;
-import org.quantumbadger.redreader.common.datastream.SeekableInputStream;
-import org.quantumbadger.redreader.common.time.TimestampUTC;
import org.quantumbadger.redreader.fragments.PostListingFragment;
import org.quantumbadger.redreader.reddit.api.RedditPostActions;
-import org.quantumbadger.redreader.reddit.prepared.RedditParsedPost;
import org.quantumbadger.redreader.reddit.prepared.RedditPreparedPost;
+import org.quantumbadger.redreader.common.ImagePreviewUtils;
import org.quantumbadger.redreader.views.liststatus.ErrorView;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.ArrayList;
import java.util.Objects;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
public final class RedditPostView extends FlingableItemView
implements RedditPreparedPost.ThumbnailLoadedCallback {
- private static final String TAG = "RedditPostView";
-
- private static final String PROMPT_PREF_KEY = "inline_image_prompt_accepted";
-
- private static final AtomicInteger sInlinePreviewsShownThisSession = new AtomicInteger(0);
-
private final AccessibilityActionManager mAccessibilityActionManager;
private RedditPreparedPost mPost = null;
@@ -209,8 +180,15 @@ public void handleMessage(@NonNull final Message msg) {
final float titleFontScale = PrefsUtility.appearance_fontscale_posts();
final float subtitleFontScale = PrefsUtility.appearance_fontscale_post_subtitles();
- final View rootView =
- LayoutInflater.from(context).inflate(R.layout.reddit_post, this, true);
+ final String layoutMode = PrefsUtility.getLayoutMode();
+
+ int layout = R.layout.reddit_post;
+
+ if (layoutMode.equals("card")) {
+ layout = R.layout.reddit_post_card;
+ }
+
+ final View rootView = LayoutInflater.from(context).inflate(layout, this, true);
mOuterView = Objects.requireNonNull(rootView.findViewById(R.id.reddit_post_layout_outer));
mInnerView = Objects.requireNonNull(rootView.findViewById(R.id.reddit_post_layout_inner));
@@ -346,9 +324,26 @@ public void handleMessage(@NonNull final Message msg) {
@UiThread
public void reset(@NonNull final RedditPreparedPost newPost) {
+ final String layoutMode = PrefsUtility.getLayoutMode();
- if(newPost != mPost) {
+ boolean alwaysPreviewMode = false;
+
+ switch(layoutMode) {
+ case "always_preview":
+ alwaysPreviewMode = true;
+ break;
+ case "card":
+ alwaysPreviewMode = true;
+ break;
+ default:
+ alwaysPreviewMode = false;
+ break;
+ }
+
+ final boolean showInlinePreview = alwaysPreviewMode ||
+ newPost.shouldShowInlinePreview();
+ if(newPost != mPost) {
mThumbnailView.setImageBitmap(null);
mImagePreviewImageView.setImageBitmap(null);
mImagePreviewPlayOverlay.setVisibility(GONE);
@@ -364,21 +359,15 @@ public void reset(@NonNull final RedditPreparedPost newPost) {
mCommentsText.setText(String.valueOf(newPost.src.getSrc().getNum_comments()));
}
- final boolean showInlinePreview = newPost.shouldShowInlinePreview();
-
final boolean showThumbnail = !showInlinePreview && newPost.hasThumbnail;
- if(showInlinePreview) {
- downloadInlinePreview(newPost, mUsageId);
-
- } else {
+ if(!showInlinePreview) {
mImagePreviewLoadingSpinner.setVisibility(GONE);
mImagePreviewOuter.setVisibility(GONE);
setBottomMargin(false);
}
if(showThumbnail) {
-
final Bitmap thumbnail = newPost.getThumbnail(this, mUsageId);
mThumbnailView.setImageBitmap(thumbnail);
@@ -386,12 +375,11 @@ public void reset(@NonNull final RedditPreparedPost newPost) {
mThumbnailView.setMinimumWidth(mThumbnailSizePrefPixels);
General.setLayoutWidthHeight(
- mThumbnailView,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
+ mThumbnailView,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
mInnerView.setMinimumHeight(mThumbnailSizePrefPixels);
-
} else {
mThumbnailView.setMinimumWidth(0);
mThumbnailView.setVisibility(GONE);
@@ -407,6 +395,10 @@ public void reset(@NonNull final RedditPreparedPost newPost) {
mPost = newPost;
+ if(showInlinePreview) {
+ ImagePreviewUtils.downloadInlinePreview(mActivity, mPost, previewListener, mUsageId);
+ }
+
updateAppearance();
}
@@ -492,179 +484,59 @@ private void setBottomMargin(final boolean enabled) {
mOuterView.setLayoutParams(layoutParams);
}
- private void downloadInlinePreview(
- @NonNull final RedditPreparedPost post,
- final int usageId) {
-
- final Rect windowVisibleDisplayFrame
- = DisplayUtils.getWindowVisibleDisplayFrame(mActivity);
-
- final int screenWidth = Math.min(1080, Math.max(720, windowVisibleDisplayFrame.width()));
- final int screenHeight = Math.min(2000, Math.max(400, windowVisibleDisplayFrame.height()));
-
- final RedditParsedPost.ImagePreviewDetails preview
- = post.src.getPreview(screenWidth, 0);
-
- if(preview == null || preview.width < 10 || preview.height < 10) {
- mImagePreviewOuter.setVisibility(GONE);
- mImagePreviewLoadingSpinner.setVisibility(GONE);
- setBottomMargin(false);
- return;
+ private final ImagePreviewUtils.ImagePreviewListener previewListener =
+ new ImagePreviewUtils.ImagePreviewListener() {
+ @Override
+ public void setImageBitmap(final Bitmap bitmap) {
+ mImagePreviewImageView.setImageBitmap(bitmap);
}
- final int boundedImageHeight = Math.min(
- (screenHeight * 2) / 3,
- (int)(((long)preview.height * screenWidth) / preview.width));
-
- final ConstraintLayout.LayoutParams imagePreviewLayoutParams
- = (ConstraintLayout.LayoutParams)mImagePreviewHolder.getLayoutParams();
-
- imagePreviewLayoutParams.dimensionRatio = screenWidth + ":" + boundedImageHeight;
- mImagePreviewHolder.setLayoutParams(imagePreviewLayoutParams);
-
- mImagePreviewOuter.setVisibility(VISIBLE);
- mImagePreviewLoadingSpinner.setVisibility(VISIBLE);
- setBottomMargin(true);
-
- CacheManager.getInstance(mActivity).makeRequest(new CacheRequest(
- preview.url,
- RedditAccountManager.getAnon(),
- null,
- new Priority(Constants.Priority.INLINE_IMAGE_PREVIEW),
- DownloadStrategyIfNotCached.INSTANCE,
- Constants.FileType.INLINE_IMAGE_PREVIEW,
- CacheRequest.DownloadQueueType.IMMEDIATE,
- mActivity,
- new CacheRequestCallbacks() {
- @Override
- public void onDataStreamComplete(
- @NonNull final GenericFactory stream,
- final TimestampUTC timestamp,
- @NonNull final UUID session,
- final boolean fromCache,
- @Nullable final String mimetype) {
-
- if(usageId != mUsageId) {
- return;
- }
-
- try(InputStream is = stream.create()) {
-
- final Bitmap data = BitmapFactory.decodeStream(is);
-
- if(data == null) {
- throw new IOException("Failed to decode bitmap");
- }
-
- // Avoid a crash on badly behaving Android ROMs (where the ImageView
- // crashes if an image is too big)
- // Should never happen as we limit the preview size to 3000x3000
- if(data.getByteCount() > 50 * 1024 * 1024) {
- throw new RuntimeException("Image was too large: "
- + data.getByteCount()
- + ", preview URL was "
- + preview.url
- + " and post was "
- + post.src.getIdAndType());
- }
-
- final boolean alreadyAcceptedPrompt = General.getSharedPrefs(mActivity)
- .getBoolean(PROMPT_PREF_KEY, false);
-
- final int totalPreviewsShown
- = sInlinePreviewsShownThisSession.incrementAndGet();
-
- final boolean isVideoPreview = post.isVideoPreview();
-
- AndroidCommon.runOnUiThread(() -> {
- mImagePreviewImageView.setImageBitmap(data);
- mImagePreviewLoadingSpinner.setVisibility(GONE);
-
- if(isVideoPreview) {
- mImagePreviewPlayOverlay.setVisibility(VISIBLE);
- }
-
- // Show every 8 previews, starting at the second one
- if(totalPreviewsShown % 8 == 2 && !alreadyAcceptedPrompt) {
- showPrefPrompt();
- }
- });
-
- } catch(final Throwable t) {
- onFailure(General.getGeneralErrorForFailure(
- mActivity,
- CacheRequest.RequestFailureType.CONNECTION,
- t,
- null,
- preview.url,
- Optional.empty()));
- }
- }
-
- @Override
- public void onFailure(@NonNull final RRError error) {
-
- Log.e(TAG, "Failed to download image preview: " + error, error.t);
-
- if(usageId != mUsageId) {
- return;
- }
-
- AndroidCommon.runOnUiThread(() -> {
-
- mImagePreviewLoadingSpinner.setVisibility(GONE);
- mImagePreviewOuter.setVisibility(GONE);
-
- final ErrorView errorView = new ErrorView(
- mActivity,
- error);
-
- mPostErrors.addView(errorView);
- General.setLayoutMatchWidthWrapHeight(errorView);
- });
- }
- }
- ));
- }
-
- private void showPrefPrompt() {
-
- final SharedPrefsWrapper sharedPrefs
- = General.getSharedPrefs(mActivity);
-
- LayoutInflater.from(mActivity).inflate(
- R.layout.inline_images_question_view,
- mFooter,
- true);
-
- final FrameLayout promptView
- = mFooter.findViewById(R.id.inline_images_prompt_root);
+ @Override
+ public void setLoadingSpinnerVisible(final boolean visible) {
+ mImagePreviewLoadingSpinner.setVisibility(visible ? VISIBLE : GONE);
+ }
- final Button keepShowing
- = mFooter.findViewById(R.id.inline_preview_prompt_keep_showing_button);
+ @Override
+ public void setOuterViewVisible(final boolean visible) {
+ mImagePreviewOuter.setVisibility(visible ? VISIBLE : GONE);
+ }
- final Button turnOff
- = mFooter.findViewById(R.id.inline_preview_prompt_turn_off_button);
+ @Override
+ public void setPlayOverlayVisible(final boolean visible) {
+ mImagePreviewPlayOverlay.setVisibility(visible ? VISIBLE : GONE);
+ }
- keepShowing.setOnClickListener(v -> {
+ @Override
+ public void setPreviewDimensions(final String ratio) {
+ final ConstraintLayout.LayoutParams params =
+ (ConstraintLayout.LayoutParams)mImagePreviewHolder.getLayoutParams();
+ params.dimensionRatio = ratio;
+ mImagePreviewHolder.setLayoutParams(params);
+ }
- new RRAnimationShrinkHeight(promptView).start();
+ @Override
+ public LinearLayout getFooterView() {
+ return mFooter;
+ }
- sharedPrefs.edit()
- .putBoolean(PROMPT_PREF_KEY, true)
- .apply();
- });
+ @Override
+ public BaseActivity getActivity() {
+ return mActivity;
+ }
- turnOff.setOnClickListener(v -> {
+ @Override
+ public void addErrorView(final ErrorView errorView) {
+ mPostErrors.addView(errorView);
+ }
- final String prefPreview = mActivity.getApplicationContext()
- .getString(
- R.string.pref_images_inline_image_previews_key);
+ @Override
+ public void setErrorViewLayout(final View errorView) {
+ General.setLayoutMatchWidthWrapHeight(errorView);
+ }
- sharedPrefs.edit()
- .putBoolean(PROMPT_PREF_KEY, true)
- .putString(prefPreview, "never")
- .apply();
- });
- }
+ @Override
+ public boolean isUsageIdValid(final int usageId) {
+ return usageId == mUsageId;
+ }
+ };
}
diff --git a/src/main/res/layout/post_header_preview.xml b/src/main/res/layout/post_header_preview.xml
new file mode 100644
index 000000000..e4d462e7a
--- /dev/null
+++ b/src/main/res/layout/post_header_preview.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/res/layout/reddit_post_card.xml b/src/main/res/layout/reddit_post_card.xml
new file mode 100644
index 000000000..96429f5d4
--- /dev/null
+++ b/src/main/res/layout/reddit_post_card.xml
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml
index f07f2a665..00683000c 100644
--- a/src/main/res/values-ar/strings.xml
+++ b/src/main/res/values-ar/strings.xml
@@ -576,4 +576,4 @@
تضمين العنوان/الوصف عند النشر
تعليقات ل%s
التعليق من قبل %s في ريديت
-
\ No newline at end of file
+
diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml
index 2c029dca3..2117e7785 100644
--- a/src/main/res/values-cs/strings.xml
+++ b/src/main/res/values-cs/strings.xml
@@ -669,6 +669,14 @@
Skrýt přečtené články
Self-text příspěvku zkopírován do schránky
+
+
+ Rozvržení
+ Režim rozvržení
+ Miniatury
+ Vždy Náhled
+ Karta
+
Oznámení
Smazat praporky v mezipaměti (přečteno, upvoted, atd.) po
@@ -962,4 +970,4 @@
Kontroverzní s hlasy.
Chyba při odesílání komentáře
Kontroverzní: Tento rok
-
\ No newline at end of file
+
diff --git a/src/main/res/values-eo/strings.xml b/src/main/res/values-eo/strings.xml
index e13a2f263..97c1431e6 100644
--- a/src/main/res/values-eo/strings.xml
+++ b/src/main/res/values-eo/strings.xml
@@ -625,6 +625,14 @@
Tio ĉi estas elŝut-ligilo. Ĉu vi volas malfermi ĝin per ekstera foliumilo?
Frapeto sur memafiŝo
+
+
+ Aranĝo
+ Aranĝa reĝimo
+ Bildetojn
+ Ĉiam Antaŭrigardu
+ Karto
+
Montri /r/popular en ĉefmenuo
Aktivigi filmet-ludadajn stirilojn
@@ -944,4 +952,4 @@
Ĉi tio estas enarkivigita kaj ne plu alrespondebla.
Indikilo de debatateco (†)
Dum spektado de aŭdvidaĵo
-
\ No newline at end of file
+
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index 4154a22c2..a26529b6a 100644
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -618,6 +618,14 @@
Comentario padre siguiente
Comentario padre anterior
Mostrar botones de navegación sobre los comentarios
+
+
+ Diseño
+ Modo de diseño
+ Miniaturas
+ Previsualizar Siempre
+ Tarjeta
+
Descargar archivo
Esto es un enlace de descarga. ¿Deseas abrir esto en un navegador externo?
@@ -942,4 +950,4 @@
Comentarios: Esta semana
Indicador de controversia (†)
Buscar en %s
-
\ No newline at end of file
+
diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml
index c04c1422c..e92fcbe50 100644
--- a/src/main/res/values-eu/strings.xml
+++ b/src/main/res/values-eu/strings.xml
@@ -550,6 +550,11 @@
Ausazko NSFW Subreddita
Erakutsi tresna-barra behean
Mututu bideoak modu lehenetsian
+
+
+ Diseinua
+ Diseinu modua
+
Irudiak/Bideoa
Sarrerako Reddit mezuak
Argitalpena testu propioa arbelera kopiatuta
diff --git a/src/main/res/values-fi/strings.xml b/src/main/res/values-fi/strings.xml
index 1f207f2d9..5a915cf3e 100644
--- a/src/main/res/values-fi/strings.xml
+++ b/src/main/res/values-fi/strings.xml
@@ -554,6 +554,14 @@
Käytä sisäänrakennettua jakonäkymää
Valitse sovellus jakamista varten
Saapuvat Reddit-viestit
+
+
+ Asettelu
+ Asettelu-tila
+ Pikkukuvat
+ Esikatsele Aina
+ Kortti
+
Kuvat/Video
Mykistä videot oletuksena
Näytä työkalupalkki alhaalla
@@ -786,4 +794,4 @@
Syöttämäsi CAPTCHA on väärä. Yritä uudelleen.
Väärä CAPTCHA
Redditin mukaan nykyisellä käyttäjällä ei ole lupaa tehdä sitä.
-
\ No newline at end of file
+
diff --git a/src/main/res/values-in/strings.xml b/src/main/res/values-in/strings.xml
index 7860f706f..4c8ec9430 100644
--- a/src/main/res/values-in/strings.xml
+++ b/src/main/res/values-in/strings.xml
@@ -667,6 +667,14 @@
Tampilkan indikator pemuatan media jika tersedia
Tampilkan bilah alat di bawah
Matikan suara video secara bawaan
+
+
+ Tata Letak
+ Mode Tata Letak
+ Gambar mini
+ Selalu Pratinjau
+ Kartu
+
Gambar/Video
Pesan Masuk Reddit
Pos teks self disalin ke papan klip
@@ -949,4 +957,4 @@
Baru: Bulang Ini
Terhangat: Sepanjang Waktu
Saat melihat media
-
\ No newline at end of file
+
diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml
index 643d60dbf..5b9097c4d 100644
--- a/src/main/res/values-it/strings.xml
+++ b/src/main/res/values-it/strings.xml
@@ -552,6 +552,14 @@
Mostra un indicatore di caricamento del contenuto, se disponibile
Mostra barra degli strumenti in basso
Muta i video in modo predefinito
+
+
+ Layout
+ Modalità layout
+ Miniature
+ Anteprima Sempre
+ Carta
+
Immagini/Video
Messaggi di Reddit in arrivo
Testo del post copiato negli appunti
diff --git a/src/main/res/values-lt/strings.xml b/src/main/res/values-lt/strings.xml
index 457ae30d2..09750b7c4 100644
--- a/src/main/res/values-lt/strings.xml
+++ b/src/main/res/values-lt/strings.xml
@@ -519,6 +519,14 @@
Nėra įdiegtos tinkamos programos, kuria būtų galima tai bendrinti.
Naudoti integruotą bendrinimo dialogo langą
Įeinančios Reddit žinutės
+
+
+ Išdėstymas
+ Išdėstymo režimas
+ Miniatiūros
+ Visada Peržiūrėti
+ Kortelė
+
Vaizdai/Vaizdo įrašai
Nutildyti vaizdo įrašus pagal automatiškai
Rodyti įrankių juostą apačioje
@@ -836,4 +844,4 @@
Aktualu: per visą laiką
Autorius: %s, administratorius.
Kol kas jokių įrašų.
-
\ No newline at end of file
+
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index 594c12441..c4ee7cd82 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -652,6 +652,14 @@
Ukryj przeczytane posty
Skróty
Losowy subreddit NSFW
+
+
+ Układ
+ Tryb układu
+ Miniatury
+ Zawsze Podgląd
+ Karta
+
Obrazy/Wideo
Post skopiowany do schowka
Wybierz aplikację do udostępnienia
@@ -879,4 +887,4 @@
Po zakończeniu logowania, powinieneś zostać przekierowany z powrotem do RedReadera. Jeśli logowanie nie powiedzie się, możesz spróbować użyć innej przeglądarki korzystając z poniższego pola wyboru.
Aby się zalogować, zostaniesz przeniesiony do Reddita w przeglądarce.
Podany obraz nie został odnaleziony. Mógł zostać usunięty.
-
\ No newline at end of file
+
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index 59edf6a9a..21ae49f66 100644
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -585,6 +585,14 @@
Копировать собственный текст
Текст сообщения скопирован в буфер обмена
Входящие сообщения Reddit
+
+
+ Макет
+ Режим макета
+ Миниатюры
+ Всегда Превью
+ Карточка
+
Изображения/Видео
Видео без звука по умолчанию
Показывать панель инструментов внизу
diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml
index c24d3463e..bfc2ce500 100644
--- a/src/main/res/values-uk/strings.xml
+++ b/src/main/res/values-uk/strings.xml
@@ -542,6 +542,14 @@
Застосунків, через які можливе поширення, не встановлено.
Оберіть застосунок для поширення
Текст допису скопійовано до буфера обміну
+
+
+ Макет
+ Режим макета
+ Мініатюри
+ Завжди Переглядати
+ картка
+
Зображення/Відео
Показувати панель інструментів знизу
Показувати індикатор співвідношення сторін
@@ -837,4 +845,4 @@
Суперечливий індикатор (†)
Пошук у %s
Пошук «%1$s» у %2$s
-
\ No newline at end of file
+
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 24f59ee2b..49fc5a392 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -552,6 +552,14 @@
在可用时显示加载中媒体的外观
在底部显示工具栏
默认将视频静音
+
+
+ 布局
+ 布局模式
+ 缩略图
+ 始终预览
+ 卡片
+
图片/视频
传入的Reddit消息
帖子self-text已复制到剪贴板
@@ -834,4 +842,4 @@
查看媒体文件时
从不
帖子已经存档,不能再回复。
-
\ No newline at end of file
+
diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml
index 9d3502316..500afbd55 100644
--- a/src/main/res/values/arrays.xml
+++ b/src/main/res/values/arrays.xml
@@ -1312,6 +1312,19 @@
- np_reddit
+
+
+ - @string/pref_layout_mode_thumbnails
+ - @string/pref_layout_mode_alwayspreview
+ - @string/pref_layout_mode_card
+
+
+
+ - thumbnails
+ - always_preview
+ - card
+
+
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 4d1f752c7..9240addf8 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -1088,6 +1088,16 @@
pref_behaviour_video_mute_default
Mute videos by default
+
+ pref_layout_mode
+ Layout
+ Layout Mode
+ Thumbnails
+ Always Preview
+ Card
+
+ Post Image
+
Images/Video
Incoming Reddit Messages
diff --git a/src/main/res/xml/prefs_images_video.xml b/src/main/res/xml/prefs_images_video.xml
index 7126cba0d..94c686a5b 100644
--- a/src/main/res/xml/prefs_images_video.xml
+++ b/src/main/res/xml/prefs_images_video.xml
@@ -19,6 +19,19 @@
+
+
+
+
+
+