about summary refs log tree commit diff
path: root/src/view/com/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/util')
-rw-r--r--src/view/com/util/List.web.tsx5
-rw-r--r--src/view/com/util/LoadingPlaceholder.tsx45
-rw-r--r--src/view/com/util/UserInfoText.tsx6
-rw-r--r--src/view/com/util/forms/PostDropdownBtn.tsx8
-rw-r--r--src/view/com/util/images/Gallery.tsx7
-rw-r--r--src/view/com/util/images/ImageLayoutGrid.tsx39
-rw-r--r--src/view/com/util/load-latest/LoadLatestBtn.tsx10
-rw-r--r--src/view/com/util/post-ctrls/PostCtrls.tsx26
8 files changed, 98 insertions, 48 deletions
diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx
index 3e81a8c37..29bad2db8 100644
--- a/src/view/com/util/List.web.tsx
+++ b/src/view/com/util/List.web.tsx
@@ -300,6 +300,9 @@ export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
   props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
 ) => React.ReactElement
 
+// https://stackoverflow.com/questions/7944460/detect-safari-browser
+const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
+
 const styles = StyleSheet.create({
   contentContainer: {
     borderLeftWidth: 1,
@@ -313,7 +316,7 @@ const styles = StyleSheet.create({
   },
   row: {
     // @ts-ignore web only
-    contentVisibility: 'auto',
+    contentVisibility: isSafari ? '' : 'auto', // Safari support for this is buggy.
   },
   minHeightViewport: {
     // @ts-ignore web only
diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx
index 8941bfb9c..6dfe12598 100644
--- a/src/view/com/util/LoadingPlaceholder.tsx
+++ b/src/view/com/util/LoadingPlaceholder.tsx
@@ -67,28 +67,36 @@ export function PostLoadingPlaceholder({
         <LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
         <LoadingPlaceholder width="80%" height={6} style={{marginBottom: 11}} />
         <View style={styles.postCtrls}>
-          <View style={[styles.postCtrl, {paddingLeft: 0}]}>
-            <CommentBottomArrow
-              style={[{color: theme.palette.default.icon, marginTop: 1}]}
-              strokeWidth={3}
-              size={15}
-            />
+          <View style={styles.postCtrl}>
+            <View style={[styles.postBtn, {paddingLeft: 0}]}>
+              <CommentBottomArrow
+                style={[{color: theme.palette.default.icon, marginTop: 1}]}
+                strokeWidth={3}
+                size={15}
+              />
+            </View>
+          </View>
+          <View style={styles.postCtrl}>
+            <View style={styles.postBtn}>
+              <RepostIcon
+                style={{color: theme.palette.default.icon}}
+                strokeWidth={3}
+                size={20}
+              />
+            </View>
           </View>
           <View style={styles.postCtrl}>
-            <RepostIcon
-              style={{color: theme.palette.default.icon}}
-              strokeWidth={3}
-              size={20}
-            />
+            <View style={styles.postBtn}>
+              <HeartIcon
+                style={{color: theme.palette.default.icon} as ViewStyle}
+                size={16}
+                strokeWidth={3}
+              />
+            </View>
           </View>
           <View style={styles.postCtrl}>
-            <HeartIcon
-              style={{color: theme.palette.default.icon} as ViewStyle}
-              size={16}
-              strokeWidth={3}
-            />
+            <View style={styles.postBtn} />
           </View>
-          <View style={{width: 30, height: 30}} />
         </View>
       </View>
     </View>
@@ -279,6 +287,9 @@ const styles = StyleSheet.create({
     justifyContent: 'space-between',
   },
   postCtrl: {
+    flex: 1,
+  },
+  postBtn: {
     padding: 5,
     flex: 1,
     flexDirection: 'row',
diff --git a/src/view/com/util/UserInfoText.tsx b/src/view/com/util/UserInfoText.tsx
index e5d2ceb03..9cb9997f6 100644
--- a/src/view/com/util/UserInfoText.tsx
+++ b/src/view/com/util/UserInfoText.tsx
@@ -9,6 +9,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names'
 import {sanitizeHandle} from 'lib/strings/handles'
 import {makeProfileLink} from 'lib/routes/links'
 import {useProfileQuery} from '#/state/queries/profile'
+import {STALE} from '#/state/queries'
 
 export function UserInfoText({
   type = 'md',
@@ -29,7 +30,10 @@ export function UserInfoText({
   attr = attr || 'handle'
   failed = failed || 'user'
 
-  const {data: profile, isError} = useProfileQuery({did})
+  const {data: profile, isError} = useProfileQuery({
+    did,
+    staleTime: STALE.INFINITY,
+  })
 
   let inner
   if (isError) {
diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx
index 940f39057..e56c88d2c 100644
--- a/src/view/com/util/forms/PostDropdownBtn.tsx
+++ b/src/view/com/util/forms/PostDropdownBtn.tsx
@@ -1,5 +1,5 @@
 import React, {memo} from 'react'
-import {Linking, StyleProp, View, ViewStyle} from 'react-native'
+import {StyleProp, View, ViewStyle} from 'react-native'
 import Clipboard from '@react-native-clipboard/clipboard'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {
@@ -24,6 +24,7 @@ import {usePostDeleteMutation} from '#/state/queries/post'
 import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
 import {useLanguagePrefs} from '#/state/preferences'
 import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences'
+import {useOpenLink} from '#/state/preferences/in-app-browser'
 import {logger} from '#/logger'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
@@ -61,6 +62,7 @@ let PostDropdownBtn = ({
   const postDeleteMutation = usePostDeleteMutation()
   const hiddenPosts = useHiddenPosts()
   const {hidePost} = useHiddenPostsApi()
+  const openLink = useOpenLink()
 
   const rootUri = record.reply?.root?.uri || postUri
   const isThreadMuted = mutedThreads.includes(rootUri)
@@ -111,8 +113,8 @@ let PostDropdownBtn = ({
   }, [_, richText])
 
   const onOpenTranslate = React.useCallback(() => {
-    Linking.openURL(translatorUrl)
-  }, [translatorUrl])
+    openLink(translatorUrl)
+  }, [openLink, translatorUrl])
 
   const onHidePost = React.useCallback(() => {
     hidePost({uri: postUri})
diff --git a/src/view/com/util/images/Gallery.tsx b/src/view/com/util/images/Gallery.tsx
index e7110372c..7de3b093a 100644
--- a/src/view/com/util/images/Gallery.tsx
+++ b/src/view/com/util/images/Gallery.tsx
@@ -4,6 +4,7 @@ import {StyleSheet, Text, Pressable, View} from 'react-native'
 import {Image} from 'expo-image'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
+import {isWeb} from 'platform/detection'
 
 type EventFunction = (index: number) => void
 
@@ -70,8 +71,10 @@ const styles = StyleSheet.create({
     paddingHorizontal: 6,
     paddingVertical: 3,
     position: 'absolute',
-    left: 8,
-    bottom: 8,
+    // Related to margin/gap hack. This keeps the alt label in the same position
+    // on all platforms
+    left: isWeb ? 8 : 5,
+    bottom: isWeb ? 8 : 5,
   },
   alt: {
     color: 'white',
diff --git a/src/view/com/util/images/ImageLayoutGrid.tsx b/src/view/com/util/images/ImageLayoutGrid.tsx
index 23e807b6a..ba6c04f50 100644
--- a/src/view/com/util/images/ImageLayoutGrid.tsx
+++ b/src/view/com/util/images/ImageLayoutGrid.tsx
@@ -2,6 +2,7 @@ import React from 'react'
 import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
 import {AppBskyEmbedImages} from '@atproto/api'
 import {GalleryItem} from './Gallery'
+import {isWeb} from 'platform/detection'
 
 interface ImageLayoutGridProps {
   images: AppBskyEmbedImages.ViewImage[]
@@ -47,10 +48,10 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
     case 3:
       return (
         <View style={styles.flexRow}>
-          <View style={{flex: 2, aspectRatio: 1}}>
+          <View style={styles.threeSingle}>
             <GalleryItem {...props} index={0} imageStyle={styles.image} />
           </View>
-          <View style={{flex: 1}}>
+          <View style={styles.threeDouble}>
             <View style={styles.smallItem}>
               <GalleryItem {...props} index={1} imageStyle={styles.image} />
             </View>
@@ -88,18 +89,38 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
   }
 }
 
-// This is used to compute margins (rather than flexbox gap) due to Yoga bugs:
+// 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: {
-    marginHorizontal: -IMAGE_GAP / 2,
-    marginVertical: -IMAGE_GAP / 2,
+  container: isWeb
+    ? {
+        marginHorizontal: -IMAGE_GAP / 2,
+        marginVertical: -IMAGE_GAP / 2,
+      }
+    : {
+        gap: IMAGE_GAP,
+      },
+  flexRow: {
+    flexDirection: 'row',
+    gap: isWeb ? undefined : IMAGE_GAP,
   },
-  flexRow: {flexDirection: 'row'},
   smallItem: {flex: 1, aspectRatio: 1},
-  image: {
-    margin: IMAGE_GAP / 2,
+  image: isWeb
+    ? {
+        margin: IMAGE_GAP / 2,
+      }
+    : {},
+  threeSingle: {
+    flex: 2,
+    aspectRatio: isWeb ? 1 : undefined,
+  },
+  threeDouble: {
+    flex: 1,
+    gap: isWeb ? undefined : IMAGE_GAP,
   },
 })
diff --git a/src/view/com/util/load-latest/LoadLatestBtn.tsx b/src/view/com/util/load-latest/LoadLatestBtn.tsx
index 970d3a73a..5fad11760 100644
--- a/src/view/com/util/load-latest/LoadLatestBtn.tsx
+++ b/src/view/com/util/load-latest/LoadLatestBtn.tsx
@@ -10,6 +10,7 @@ import Animated from 'react-native-reanimated'
 const AnimatedTouchableOpacity =
   Animated.createAnimatedComponent(TouchableOpacity)
 import {isWeb} from 'platform/detection'
+import {useSession} from 'state/session'
 
 export function LoadLatestBtn({
   onPress,
@@ -21,9 +22,14 @@ export function LoadLatestBtn({
   showIndicator: boolean
 }) {
   const pal = usePalette('default')
-  const {isDesktop, isTablet, isMobile} = useWebMediaQueries()
+  const {hasSession} = useSession()
+  const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
   const {fabMinimalShellTransform} = useMinimalShellMode()
 
+  // Adjust height of the fab if we have a session only on mobile web. If we don't have a session, we want to adjust
+  // it on both tablet and mobile since we are showing the bottom bar (see createNativeStackNavigatorWithAuth)
+  const showBottomBar = hasSession ? isMobile : isTabletOrMobile
+
   return (
     <AnimatedTouchableOpacity
       style={[
@@ -32,7 +38,7 @@ export function LoadLatestBtn({
         isTablet && styles.loadLatestTablet,
         pal.borderDark,
         pal.view,
-        isMobile && fabMinimalShellTransform,
+        showBottomBar && fabMinimalShellTransform,
       ]}
       onPress={onPress}
       hitSlop={HITSLOP_20}
diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx
index a6d7e38c3..249111a04 100644
--- a/src/view/com/util/post-ctrls/PostCtrls.tsx
+++ b/src/view/com/util/post-ctrls/PostCtrls.tsx
@@ -149,7 +149,7 @@ let PostCtrls = ({
           ) : undefined}
         </TouchableOpacity>
       </View>
-      <View style={[styles.ctrl]}>
+      <View style={styles.ctrl}>
         <RepostButton
           big={big}
           isReposted={!!post.viewer?.repost}
@@ -194,19 +194,19 @@ let PostCtrls = ({
         </TouchableOpacity>
       </View>
       {big ? undefined : (
-        <PostDropdownBtn
-          testID="postDropdownBtn"
-          postAuthor={post.author}
-          postCid={post.cid}
-          postUri={post.uri}
-          record={record}
-          richText={richText}
-          showAppealLabelItem={showAppealLabelItem}
-          style={styles.btnPad}
-        />
+        <View style={styles.ctrl}>
+          <PostDropdownBtn
+            testID="postDropdownBtn"
+            postAuthor={post.author}
+            postCid={post.cid}
+            postUri={post.uri}
+            record={record}
+            richText={richText}
+            showAppealLabelItem={showAppealLabelItem}
+            style={styles.btnPad}
+          />
+        </View>
       )}
-      {/* used for adding pad to the right side */}
-      <View />
     </View>
   )
 }