From 2265fedd2ac4d006e3c55dbb81ee387b93be9830 Mon Sep 17 00:00:00 2001
From: Eric Bailey <git@esb.lol>
Date: Thu, 5 Sep 2024 13:45:13 -0500
Subject: Constrain image heights in feeds and threads (#5129)

* Limit height of images within posts

* Add some future-proofness

* Comments, improve a11y

* Adjust ALT, add crop icon

* Fix disableCrop in record-with-media posts

* Clean up aspect ratios, handle very tall images

* Handle record-with-media separately, clarify intent using enums

* Adjust spacing

* Adjust rwm embed image size on mobile

* Only do reduced layout if images embed

* Adjust gap in small embed variant

* Clean up grid layout

* Hide badge on small variant with one image

* Remove crop icon from image grid, leave on single image

* Fix sizing in Firefox

* Fix fullBleed variant
---
 src/view/com/util/images/ImageLayoutGrid.tsx | 107 +++++++++++----------------
 1 file changed, 44 insertions(+), 63 deletions(-)

(limited to 'src/view/com/util/images/ImageLayoutGrid.tsx')

diff --git a/src/view/com/util/images/ImageLayoutGrid.tsx b/src/view/com/util/images/ImageLayoutGrid.tsx
index ba6c04f50..45da7f076 100644
--- a/src/view/com/util/images/ImageLayoutGrid.tsx
+++ b/src/view/com/util/images/ImageLayoutGrid.tsx
@@ -1,8 +1,10 @@
 import React from 'react'
-import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
+import {StyleProp, View, ViewStyle} from 'react-native'
 import {AppBskyEmbedImages} from '@atproto/api'
+
+import {PostEmbedViewContext} from '#/view/com/util/post-embeds/types'
+import {atoms as a, useBreakpoints} from '#/alf'
 import {GalleryItem} from './Gallery'
-import {isWeb} from 'platform/detection'
 
 interface ImageLayoutGridProps {
   images: AppBskyEmbedImages.ViewImage[]
@@ -10,13 +12,25 @@ interface ImageLayoutGridProps {
   onLongPress?: (index: number) => void
   onPressIn?: (index: number) => void
   style?: StyleProp<ViewStyle>
+  viewContext?: PostEmbedViewContext
 }
 
 export function ImageLayoutGrid({style, ...props}: ImageLayoutGridProps) {
+  const {gtMobile} = useBreakpoints()
+  const gap =
+    props.viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia
+      ? gtMobile
+        ? a.gap_xs
+        : a.gap_2xs
+      : gtMobile
+      ? a.gap_sm
+      : a.gap_xs
+  const count = props.images.length
+  const aspectRatio = count === 2 ? 2 : count === 3 ? 1.5 : 1
   return (
     <View style={style}>
-      <View style={styles.container}>
-        <ImageLayoutGridInner {...props} />
+      <View style={[gap, {aspectRatio}]}>
+        <ImageLayoutGridInner {...props} gap={gap} />
       </View>
     </View>
   )
@@ -27,36 +41,39 @@ interface ImageLayoutGridInnerProps {
   onPress?: (index: number) => void
   onLongPress?: (index: number) => void
   onPressIn?: (index: number) => void
+  viewContext?: PostEmbedViewContext
+  gap: {gap: number}
 }
 
 function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
+  const gap = props.gap
   const count = props.images.length
 
   switch (count) {
     case 2:
       return (
-        <View style={styles.flexRow}>
-          <View style={styles.smallItem}>
-            <GalleryItem {...props} index={0} imageStyle={styles.image} />
+        <View style={[a.flex_1, a.flex_row, gap]}>
+          <View style={[a.flex_1, {aspectRatio: 1}]}>
+            <GalleryItem {...props} index={0} />
           </View>
-          <View style={styles.smallItem}>
-            <GalleryItem {...props} index={1} imageStyle={styles.image} />
+          <View style={[a.flex_1, {aspectRatio: 1}]}>
+            <GalleryItem {...props} index={1} />
           </View>
         </View>
       )
 
     case 3:
       return (
-        <View style={styles.flexRow}>
-          <View style={styles.threeSingle}>
-            <GalleryItem {...props} index={0} imageStyle={styles.image} />
+        <View style={[a.flex_1, a.flex_row, gap]}>
+          <View style={{flex: 2}}>
+            <GalleryItem {...props} index={0} />
           </View>
-          <View style={styles.threeDouble}>
-            <View style={styles.smallItem}>
-              <GalleryItem {...props} index={1} imageStyle={styles.image} />
+          <View style={[a.flex_1, gap]}>
+            <View style={[a.flex_1, {aspectRatio: 1}]}>
+              <GalleryItem {...props} index={1} />
             </View>
-            <View style={styles.smallItem}>
-              <GalleryItem {...props} index={2} imageStyle={styles.image} />
+            <View style={[a.flex_1, {aspectRatio: 1}]}>
+              <GalleryItem {...props} index={2} />
             </View>
           </View>
         </View>
@@ -65,20 +82,20 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
     case 4:
       return (
         <>
-          <View style={styles.flexRow}>
-            <View style={styles.smallItem}>
-              <GalleryItem {...props} index={0} imageStyle={styles.image} />
+          <View style={[a.flex_row, gap]}>
+            <View style={[a.flex_1, {aspectRatio: 1}]}>
+              <GalleryItem {...props} index={0} />
             </View>
-            <View style={styles.smallItem}>
-              <GalleryItem {...props} index={1} imageStyle={styles.image} />
+            <View style={[a.flex_1, {aspectRatio: 1}]}>
+              <GalleryItem {...props} index={1} />
             </View>
           </View>
-          <View style={styles.flexRow}>
-            <View style={styles.smallItem}>
-              <GalleryItem {...props} index={2} imageStyle={styles.image} />
+          <View style={[a.flex_row, gap]}>
+            <View style={[a.flex_1, {aspectRatio: 1}]}>
+              <GalleryItem {...props} index={2} />
             </View>
-            <View style={styles.smallItem}>
-              <GalleryItem {...props} index={3} imageStyle={styles.image} />
+            <View style={[a.flex_1, {aspectRatio: 1}]}>
+              <GalleryItem {...props} index={3} />
             </View>
           </View>
         </>
@@ -88,39 +105,3 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
       return null
   }
 }
-
-// On web we use margin to calculate gap, as aspectRatio does not properly size
-// all images on web. On native though we cannot rely on margin, since the
-// negative margin interferes with the swipe controls on pagers.
-// https://github.com/facebook/yoga/issues/1418
-// https://github.com/bluesky-social/social-app/issues/2601
-const IMAGE_GAP = 5
-
-const styles = StyleSheet.create({
-  container: isWeb
-    ? {
-        marginHorizontal: -IMAGE_GAP / 2,
-        marginVertical: -IMAGE_GAP / 2,
-      }
-    : {
-        gap: IMAGE_GAP,
-      },
-  flexRow: {
-    flexDirection: 'row',
-    gap: isWeb ? undefined : IMAGE_GAP,
-  },
-  smallItem: {flex: 1, aspectRatio: 1},
-  image: isWeb
-    ? {
-        margin: IMAGE_GAP / 2,
-      }
-    : {},
-  threeSingle: {
-    flex: 2,
-    aspectRatio: isWeb ? 1 : undefined,
-  },
-  threeDouble: {
-    flex: 1,
-    gap: isWeb ? undefined : IMAGE_GAP,
-  },
-})
-- 
cgit 1.4.1

