Skip to content
This repository has been archived by the owner on Jun 9, 2023. It is now read-only.

Full height images style #207

Merged
merged 5 commits into from
Aug 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]

### Added
- Full height images style ([#207](https://github.com/Tunous/Dawn/pull/207))

### Changed
- Add support for alternate Redgifs domain ([#281](https://github.com/Tunous/Dawn/pull/281))
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/me/saket/dank/cache/CachePreFiller.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ private Completable preFillImageOrAlbum(Submission submission, MediaLink mediaLi
Single<Drawable> firstImageLoad = submissionImageLoader.get().load(appContext, firstImage, imageLoadOptions);

ImageWithMultipleVariants redditSuppliedImages = ImageWithMultipleVariants.Companion.of(submission.getPreview());
String optimizedCoverImageUrl = redditSuppliedImages.findNearestFor(submissionAlbumLinkThumbnailWidth, albumLink.coverImageUrl());
String optimizedCoverImageUrl = redditSuppliedImages.findNearestUrlFor(submissionAlbumLinkThumbnailWidth, albumLink.coverImageUrl());
Single<Drawable> coverImageLoad = submissionImageLoader.get().loadImage(appContext, optimizedCoverImageUrl, imageLoadOptions);

return coverImageLoad
Expand Down Expand Up @@ -268,7 +268,7 @@ private Completable preFillLinkMetadata(Submission submission, Link contentLink,
if (linkMetadata.hasImage() && !UrlParser.isGifUrl(linkMetadata.getImageUrl())) {
ImageWithMultipleVariants redditSuppliedImages = ImageWithMultipleVariants.Companion.of(submission.getPreview());
//noinspection ConstantConditions
String thumbnailImageUrl = redditSuppliedImages.findNearestFor(submissionAlbumLinkThumbnailWidth, linkMetadata.getImageUrl());
String thumbnailImageUrl = redditSuppliedImages.findNearestUrlFor(submissionAlbumLinkThumbnailWidth, linkMetadata.getImageUrl());
imagesToDownload.add(thumbnailImageUrl);
}
return imagesToDownload;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) {
optimizedQualityUrl = activeMediaItem.mediaLink().lowQualityUrl();
} else {
ImageWithMultipleVariants imageVariants = ImageWithMultipleVariants.Companion.of(redditSuppliedImages);
optimizedQualityUrl = imageVariants.findNearestFor(
optimizedQualityUrl = imageVariants.findNearestUrlFor(
getResources().getDisplayMetrics().widthPixels,
ImageWithMultipleVariants.DEFAULT_VIEWER_MIN_WIDTH,
activeMediaItem.mediaLink().lowQualityUrl() /* defaultValue */
Expand Down Expand Up @@ -649,7 +649,7 @@ private Single<File> findHighestResImageFileFromCache(MediaAlbumItem albumItem)
Observable<File> optimizedResImageFileStream = getRedditSuppliedImages()
.flatMapObservable(redditImages -> Observable.create(emitter -> {
ImageWithMultipleVariants imageVariants = ImageWithMultipleVariants.Companion.of(redditImages);
String optimizedQualityImageForDevice = imageVariants.findNearestFor(
String optimizedQualityImageForDevice = imageVariants.findNearestUrlFor(
getDeviceDisplayWidth(),
ImageWithMultipleVariants.DEFAULT_VIEWER_MIN_WIDTH,
albumItem.mediaLink().lowQualityUrl()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ private void calculateUrlAndLoadImage(MediaAlbumItem mediaAlbumItemToShow, boole
int deviceDisplayWidth = ((MediaFragmentCallbacks) requireActivity()).getDeviceDisplayWidth();
ImageWithMultipleVariants imageWithMultipleVariants = ImageWithMultipleVariants.Companion.of(redditImages);
imageUrl = imageWithMultipleVariants
.findNearestFor(deviceDisplayWidth, ImageWithMultipleVariants.DEFAULT_VIEWER_MIN_WIDTH, lowQualityUrl);
.findNearestUrlFor(deviceDisplayWidth, ImageWithMultipleVariants.DEFAULT_VIEWER_MIN_WIDTH, lowQualityUrl);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class LookAndFeelPreferencesConstructor @Inject constructor(
builder.addOption(SubredditSubmissionImageStyle.NONE, R.string.image_style_disabled, R.drawable.ic_block_20dp)
builder.addOption(SubredditSubmissionImageStyle.THUMBNAIL, R.string.image_style_thumbnail, R.drawable.ic_image_style_thumbnail_20dp)
builder.addOption(SubredditSubmissionImageStyle.LARGE, R.string.image_style_large, R.drawable.ic_image_style_large_20dp)
builder.addOption(SubredditSubmissionImageStyle.FULL_HEIGHT, R.string.image_style_full_height, R.drawable.ic_image_style_full_height_20dp)
clickHandler.show(builder, event.itemViewHolder())
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private String imageUrlSuitableForNetwork(MediaLink mediaLink, Optional<Submissi
// Images supplied by Reddit are static, so cannot optimize for GIFs.
String defaultImageUrl = mediaLink.lowQualityUrl();
return mediaLink.isGif() ? defaultImageUrl :
ImageWithMultipleVariants.Companion.of(redditPreviews).findNearestFor(
ImageWithMultipleVariants.Companion.of(redditPreviews).findNearestUrlFor(
deviceDisplaySize.getWidth(),
ImageWithMultipleVariants.DEFAULT_VIEWER_MIN_WIDTH,
defaultImageUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,7 @@ private void loadSubmissionContent(Submission submission) {
if (resolvedLink instanceof ImgurAlbumLink) {
ImageWithMultipleVariants redditSuppliedImages = ImageWithMultipleVariants.Companion.of(submission.getPreview());
int albumContentLinkThumbnailWidth = SubmissionCommentsHeader.getWidthForAlbumContentLinkThumbnail(getContext());
String albumCoverImageUrl = redditSuppliedImages.findNearestFor(
String albumCoverImageUrl = redditSuppliedImages.findNearestUrlFor(
albumContentLinkThumbnailWidth,
((ImgurAlbumLink) resolvedLink).coverImageUrl()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class ImageWithMultipleVariants private constructor(private val optionalRedditPr
* @param minWidth Minimum preview width.
* Specify -1 to find any preview. minWidth is ignored if it larger than preferredWidth
*/
@Suppress("DEPRECATION")
fun findNearestFor(preferredWidth: Int, minWidth: Int): String? {
fun findNearestFor(preferredWidth: Int, minWidth: Int): SubmissionPreview.Variation? {
if (optionalRedditPreviews.isEmpty) {
return null
}
Expand All @@ -34,34 +33,45 @@ class ImageWithMultipleVariants private constructor(private val optionalRedditPr
for (variation in redditPreviews.resolutions) {
val differenceAbs = abs(preferredWidth - variation.width)
if (differenceAbs < abs(closestDifference)
// If another image is found with the same difference, choose the higher-res image.
|| differenceAbs == closestDifference && variation.width > closestImage.width) {
// If another image is found with the same difference, choose the higher-res image.
|| differenceAbs == closestDifference && variation.width > closestImage.width
) {
closestDifference = preferredWidth - variation.width
closestImage = variation
}
}

return if (closestImage.width < minWidthChecked) null else {
closestImage
}
}

@Suppress("DEPRECATION")
fun findNearestUrlFor(preferredWidth: Int, minWidth: Int): String? {
val url = findNearestFor(preferredWidth, minWidth)?.url
return if (url != null) {
// Reddit sends HTML-escaped URLs.
Html.fromHtml(closestImage.url).toString()
Html.fromHtml(url).toString()
} else {
null
}
}

fun findNearestFor(preferredWidth: Int): String {
return this.findNearestFor(preferredWidth, -1) ?:
fun findNearestUrlFor(preferredWidth: Int): String {
return findNearestUrlFor(preferredWidth, -1) ?:
throw NoSuchElementException("No reddit supplied images present")
}

fun findNearestFor(preferredWidth: Int, minWidth: Int, defaultValue: String): String {
fun findNearestUrlFor(preferredWidth: Int, minWidth: Int, defaultValue: String): String {
if (UrlParser.isGifUrl(defaultValue)) {
throw AssertionError("Optimizing GIFs is an error: $defaultValue")
}

return this.findNearestFor(preferredWidth, minWidth) ?: defaultValue
return findNearestUrlFor(preferredWidth, minWidth) ?: defaultValue
}

fun findNearestFor(preferredWidth: Int, defaultValue: String): String {
return findNearestFor(preferredWidth, -1, defaultValue)
fun findNearestUrlFor(preferredWidth: Int, defaultValue: String): String {
return findNearestUrlFor(preferredWidth, -1, defaultValue)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ private Observable<Optional<Drawable>> fetchThumbnail(
.flatMap(hasRedditSuppliedImages -> {
if (hasRedditSuppliedImages) {
int thumbnailWidth = SubmissionCommentsHeader.getWidthForAlbumContentLinkThumbnail(context);
return Observable.just(redditSuppliedThumbnails.findNearestFor(thumbnailWidth));
return Observable.just(redditSuppliedThumbnails.findNearestUrlFor(thumbnailWidth));
} else {
return fallbackThumbnailUrlStream
.flatMap(optionalUrl -> optionalUrl.isPresent() ? Observable.just(optionalUrl.get()) : Observable.empty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.signature.ObjectKey;
import com.google.auto.value.AutoValue;
import com.jakewharton.rxrelay2.PublishRelay;

Expand Down Expand Up @@ -132,6 +133,8 @@ public abstract static class Thumbnail {

public abstract String contentDescription();

public abstract Optional<Integer> height();

public static Builder builder() {
return new AutoValue_SubredditSubmission_UiModel_Thumbnail.Builder();
}
Expand All @@ -150,6 +153,8 @@ public abstract static class Builder {

public abstract Builder contentDescription(String description);

public abstract Builder height(Optional<Integer> height);

public abstract Thumbnail build();
}
}
Expand All @@ -164,6 +169,7 @@ class ViewHolder extends RecyclerView.ViewHolder implements ViewHolderWithSwipeA
private UiModel uiModel;
private final ConstraintSet originalConstraintSet = new ConstraintSet();
private final ConstraintSet leftAlignedThumbnailConstraintSet = new ConstraintSet();
private final int largeImageHeight;

protected ViewHolder(View itemView) {
super(itemView);
Expand All @@ -180,6 +186,8 @@ protected ViewHolder(View itemView) {
int thumbnailGoneMargin = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.subreddit_submission_padding);
leftAlignedThumbnailConstraintSet.setGoneMargin(R.id.submission_item_title, ConstraintSet.START, thumbnailGoneMargin);
originalConstraintSet.setGoneMargin(R.id.submission_item_title, ConstraintSet.END, thumbnailGoneMargin);

largeImageHeight = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.subreddit_submission_large_image);
}

public void setUiModel(UiModel uiModel) {
Expand Down Expand Up @@ -273,25 +281,36 @@ private void setThumbnail(Optional<UiModel.Thumbnail> optionalThumbnail) {
break;
case THUMBNAIL:
imageView.setVisibility(View.GONE);
Glide.with(itemView)
.load(thumb.remoteUrl().get())
.apply(RequestOptions.circleCropTransform())
.transition(DrawableTransitionOptions.withCrossFade())
.into(thumbnailView);
loadThumbnail(thumb, RequestOptions.circleCropTransform(), thumbnailView, -1);
break;
case LARGE:
thumbnailView.setVisibility(View.GONE);
Glide.with(itemView)
.load(thumb.remoteUrl().get())
.apply(RequestOptions.centerCropTransform())
.transition(DrawableTransitionOptions.withCrossFade())
.into(imageView);
setLargeImage(thumb, largeImageHeight);
break;
case FULL_HEIGHT:
setLargeImage(thumb, thumb.height().orElse(ViewGroup.LayoutParams.WRAP_CONTENT));
break;
}
}
});
}

private void setLargeImage(UiModel.Thumbnail thumb, int height) {
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.height = height;
imageView.setLayoutParams(layoutParams);
thumbnailView.setVisibility(View.GONE);
loadThumbnail(thumb, RequestOptions.centerCropTransform(), imageView, height);
}

private void loadThumbnail(UiModel.Thumbnail thumb, RequestOptions requestOptions, ImageView imageView, int height) {
Glide.with(itemView)
.load(thumb.remoteUrl().get())
.signature(new ObjectKey(height))
.apply(requestOptions)
.transition(DrawableTransitionOptions.withCrossFade())
.into(imageView);
}

@Override
public SwipeableLayout getSwipeableLayout() {
return (SwipeableLayout) itemView;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import me.saket.dank.R
enum class SubredditSubmissionImageStyle {
NONE,
THUMBNAIL,
LARGE;
LARGE,
FULL_HEIGHT;

val userVisibleName: Int
@StringRes get() {
return when (this) {
NONE -> R.string.image_style_disabled
THUMBNAIL -> R.string.image_style_thumbnail
LARGE -> R.string.image_style_large
FULL_HEIGHT -> R.string.image_style_full_height
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -397,33 +397,43 @@ public SubredditSubmission.UiModel submissionUiModel(
}

private SubredditSubmission.UiModel.Thumbnail.Builder thumbnailForStaticImage(Context c) {
//noinspection ConstantConditions
return SubredditSubmission.UiModel.Thumbnail.builder()
.remoteUrl(Optional.empty())
.scaleType(ImageView.ScaleType.CENTER_INSIDE)
.tintColor(Optional.of(ContextCompat.getColor(c, R.color.gray_100)))
.backgroundRes(Optional.of(R.drawable.background_submission_self_thumbnail));
.backgroundRes(Optional.of(R.drawable.background_submission_self_thumbnail))
.height(Optional.empty());
}

private SubredditSubmission.UiModel.Thumbnail thumbnailForRemoteImage(Context c, SubmissionPreview preview) {
ImageWithMultipleVariants redditThumbnails = ImageWithMultipleVariants.Companion.of(preview);
int preferredWidth = getPreferredWidthForThumbnail(c);
String optimizedThumbnailUrl = redditThumbnails.findNearestFor(preferredWidth);
Optional<SubmissionPreview.Variation> optimizedThumbnail = Optional.ofNullable(redditThumbnails.findNearestFor(preferredWidth, -1));
Optional<String> optimizedThumbnailUrl = optimizedThumbnail.map(thumbnail -> Html.fromHtml(thumbnail.getUrl()).toString());
Optional<Integer> thumbnailFullHeight = optimizedThumbnail.map(thumbnail -> getFullHeightForThumbnail(preferredWidth, thumbnail));

return SubredditSubmission.UiModel.Thumbnail.builder()
.staticRes(Optional.empty())
.remoteUrl(Optional.of(optimizedThumbnailUrl))
.remoteUrl(optimizedThumbnailUrl)
.contentDescription(c.getString(R.string.subreddit_submission_item_cd_external_url))
.scaleType(ImageView.ScaleType.CENTER_CROP)
.tintColor(Optional.empty())
.backgroundRes(Optional.empty())
.height(thumbnailFullHeight)
.build();
}

private int getFullHeightForThumbnail(int preferredWidth, SubmissionPreview.Variation optimizedThumbnail) {
int widthDifference = preferredWidth - optimizedThumbnail.getWidth();
float aspectRatio = optimizedThumbnail.getWidth() / ((float) optimizedThumbnail.getHeight());
int heightDifference = aspectRatio != 0 ? Math.round(widthDifference / aspectRatio) : 0;
return optimizedThumbnail.getHeight() + heightDifference;
}

private int getPreferredWidthForThumbnail(Context c) {
if (subredditSubmissionImageStyle.get().equals(SubredditSubmissionImageStyle.LARGE)) {
return c.getResources().getDisplayMetrics().widthPixels;
if (subredditSubmissionImageStyle.get().equals(SubredditSubmissionImageStyle.THUMBNAIL)) {
return c.getResources().getDimensionPixelSize(R.dimen.subreddit_submission_thumbnail);
}
return c.getResources().getDimensionPixelSize(R.dimen.subreddit_submission_thumbnail);
return c.getResources().getDisplayMetrics().widthPixels;
}
}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_image_style_full_height_20dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFF"
android:pathData="M12.01,5.5L10,8h4l-1.99,-2.5zM18,10v4l2.5,-1.99L18,10zM6,10l-2.5,2.01L6,14v-4zM14,16h-4l2.01,2.5L14,16zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.99h18v14.02z" />
</vector>
5 changes: 2 additions & 3 deletions app/src/main/res/layout/list_item_submission_content.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
<me.saket.dank.ImageViewWithStackTraceName
android:id="@+id/submission_item_image"
android:layout_width="0dp"
android:layout_height="160dp"
android:layout_marginTop="@dimen/spacing16"
android:layout_height="@dimen/subreddit_submission_large_image"
android:foreground="@drawable/touchindicator_submission_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand All @@ -24,7 +23,7 @@
android:id="@+id/submission_item_separator"
style="@style/DankSeparator.VerticalContent"
android:layout_width="0dp"
app:layout_constraintBottom_toTopOf="@+id/submission_item_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

Expand Down
5 changes: 2 additions & 3 deletions app/src/main/res/layout/list_item_submission_content_left.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
<me.saket.dank.ImageViewWithStackTraceName
android:id="@+id/submission_item_image"
android:layout_width="0dp"
android:layout_height="160dp"
android:layout_marginTop="@dimen/spacing16"
android:layout_height="@dimen/subreddit_submission_large_image"
android:foreground="@drawable/touchindicator_submission_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand All @@ -24,7 +23,7 @@
android:id="@+id/submission_item_separator"
style="@style/DankSeparator.VerticalContent"
android:layout_width="0dp"
app:layout_constraintBottom_toTopOf="@+id/submission_item_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<dimen name="subreddit_submission_padding">@dimen/spacing16</dimen>
<dimen name="subreddit_submission_thumbnail_padding">@dimen/spacing24</dimen>
<dimen name="subreddit_submission_thumbnail">52dp</dimen>
<dimen name="subreddit_submission_large_image">160dp</dimen>

<dimen name="popup_menu_horizontal_offset_for_button">4dp</dimen> <!-- Adjustments required to align with a button -->
<dimen name="popup_menu_vertical_offset_for_button">6dp</dimen> <!-- that includes padding to make space for shadow. -->
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,5 @@
<string name="image_style_disabled">Disabled</string>
<string name="image_style_thumbnail">Thumbnail</string>
<string name="image_style_large">Large</string>
<string name="image_style_full_height">Full height</string>
</resources>