about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/composer/Composer.tsx2
-rw-r--r--src/view/com/composer/useExternalLinkFetch.e2e.ts45
-rw-r--r--src/view/com/feeds/FeedPage.tsx9
-rw-r--r--src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx27
-rw-r--r--src/view/com/lightbox/Lightbox.web.tsx54
-rw-r--r--src/view/com/modals/SwitchAccount.tsx6
-rw-r--r--src/view/com/post-thread/PostThread.tsx3
-rw-r--r--src/view/com/posts/Feed.tsx8
-rw-r--r--src/view/com/posts/FeedErrorMessage.tsx8
-rw-r--r--src/view/com/testing/TestCtrls.e2e.tsx28
-rw-r--r--src/view/com/util/UserAvatar.tsx5
-rw-r--r--src/view/com/util/UserBanner.tsx5
-rw-r--r--src/view/com/util/forms/NativeDropdown.web.tsx2
-rw-r--r--src/view/com/util/text/Text.tsx15
14 files changed, 169 insertions, 48 deletions
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index ab7551b60..ddb01a8fa 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -447,7 +447,7 @@ export const ComposePost = observer(function ComposePost({
             />
           )}
           {quote ? (
-            <View style={[s.mt5, isWeb && s.mb10]}>
+            <View style={[s.mt5, isWeb && s.mb10, {pointerEvents: 'none'}]}>
               <QuoteEmbed quote={quote} />
             </View>
           ) : undefined}
diff --git a/src/view/com/composer/useExternalLinkFetch.e2e.ts b/src/view/com/composer/useExternalLinkFetch.e2e.ts
new file mode 100644
index 000000000..ccf619db3
--- /dev/null
+++ b/src/view/com/composer/useExternalLinkFetch.e2e.ts
@@ -0,0 +1,45 @@
+import {useState, useEffect} from 'react'
+import * as apilib from 'lib/api/index'
+import {getLinkMeta} from 'lib/link-meta/link-meta'
+import {ComposerOpts} from 'state/shell/composer'
+import {getAgent} from '#/state/session'
+
+export function useExternalLinkFetch({}: {
+  setQuote: (opts: ComposerOpts['quote']) => void
+}) {
+  const [extLink, setExtLink] = useState<apilib.ExternalEmbedDraft | undefined>(
+    undefined,
+  )
+
+  useEffect(() => {
+    let aborted = false
+    const cleanup = () => {
+      aborted = true
+    }
+    if (!extLink) {
+      return cleanup
+    }
+    if (!extLink.meta) {
+      getLinkMeta(getAgent(), extLink.uri).then(meta => {
+        if (aborted) {
+          return
+        }
+        setExtLink({
+          uri: extLink.uri,
+          isLoading: !!meta.image,
+          meta,
+        })
+      })
+      return cleanup
+    }
+    if (extLink.isLoading) {
+      setExtLink({
+        ...extLink,
+        isLoading: false, // done
+      })
+    }
+    return cleanup
+  }, [extLink])
+
+  return {extLink, setExtLink}
+}
diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx
index e6b5d1fb6..2d0736b09 100644
--- a/src/view/com/feeds/FeedPage.tsx
+++ b/src/view/com/feeds/FeedPage.tsx
@@ -22,6 +22,7 @@ import {listenSoftReset} from '#/state/events'
 import {truncateAndInvalidate} from '#/state/queries/util'
 import {TabState, getTabState, getRootNavigation} from '#/lib/routes/helpers'
 import {isNative} from '#/platform/detection'
+import {logEvent} from '#/lib/statsig/statsig'
 
 const POLL_FREQ = 60e3 // 60sec
 
@@ -68,6 +69,10 @@ export function FeedPage({
       scrollToTop()
       truncateAndInvalidate(queryClient, FEED_RQKEY(feed))
       setHasNew(false)
+      logEvent('feed:refresh', {
+        feedType: feed.split('|')[0],
+        reason: 'soft-reset',
+      })
     }
   }, [navigation, isPageFocused, scrollToTop, queryClient, feed, setHasNew])
 
@@ -89,6 +94,10 @@ export function FeedPage({
     scrollToTop()
     truncateAndInvalidate(queryClient, FEED_RQKEY(feed))
     setHasNew(false)
+    logEvent('feed:refresh', {
+      feedType: feed.split('|')[0],
+      reason: 'load-latest',
+    })
   }, [scrollToTop, feed, queryClient, setHasNew])
 
   return (
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx b/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
index 3872919de..88476c8e1 100644
--- a/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
+++ b/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
@@ -6,7 +6,13 @@
  *
  */
 import React from 'react'
-import {SafeAreaView, Text, TouchableOpacity, StyleSheet} from 'react-native'
+import {
+  SafeAreaView,
+  TouchableOpacity,
+  StyleSheet,
+  ViewStyle,
+} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -23,14 +29,14 @@ const ImageDefaultHeader = ({onRequestClose}: Props) => {
   return (
     <SafeAreaView style={styles.root}>
       <TouchableOpacity
-        style={styles.closeButton}
+        style={[styles.closeButton, styles.blurredBackground]}
         onPress={onRequestClose}
         hitSlop={HIT_SLOP}
         accessibilityRole="button"
         accessibilityLabel={_(msg`Close image`)}
         accessibilityHint={_(msg`Closes viewer for header image`)}
         onAccessibilityEscape={onRequestClose}>
-        <Text style={styles.closeText}>✕</Text>
+        <FontAwesomeIcon icon="close" color={'#fff'} size={22} />
       </TouchableOpacity>
     </SafeAreaView>
   )
@@ -42,8 +48,8 @@ const styles = StyleSheet.create({
     pointerEvents: 'box-none',
   },
   closeButton: {
-    marginRight: 8,
-    marginTop: 8,
+    marginRight: 10,
+    marginTop: 10,
     width: 44,
     height: 44,
     alignItems: 'center',
@@ -51,13 +57,10 @@ const styles = StyleSheet.create({
     borderRadius: 22,
     backgroundColor: '#00000077',
   },
-  closeText: {
-    lineHeight: 22,
-    fontSize: 19,
-    textAlign: 'center',
-    color: '#FFF',
-    includeFontPadding: false,
-  },
+  blurredBackground: {
+    backdropFilter: 'blur(10px)',
+    WebkitBackdropFilter: 'blur(10px)',
+  } as ViewStyle,
 })
 
 export default ImageDefaultHeader
diff --git a/src/view/com/lightbox/Lightbox.web.tsx b/src/view/com/lightbox/Lightbox.web.tsx
index fb97c30a4..942c9a686 100644
--- a/src/view/com/lightbox/Lightbox.web.tsx
+++ b/src/view/com/lightbox/Lightbox.web.tsx
@@ -7,6 +7,7 @@ import {
   StyleSheet,
   View,
   Pressable,
+  ViewStyle,
 } from 'react-native'
 import {
   FontAwesomeIcon,
@@ -24,6 +25,7 @@ import {
   ProfileImageLightbox,
 } from '#/state/lightbox'
 import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
+import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 
 interface Img {
   uri: string
@@ -111,6 +113,14 @@ function LightboxInner({
     return () => window.removeEventListener('keydown', onKeyDown)
   }, [onKeyDown])
 
+  const {isTabletOrDesktop} = useWebMediaQueries()
+  const btnStyle = React.useMemo(() => {
+    return isTabletOrDesktop ? styles.btnTablet : styles.btnMobile
+  }, [isTabletOrDesktop])
+  const iconSize = React.useMemo(() => {
+    return isTabletOrDesktop ? 32 : 24
+  }, [isTabletOrDesktop])
+
   return (
     <View style={styles.mask}>
       <TouchableWithoutFeedback
@@ -130,28 +140,38 @@ function LightboxInner({
           {canGoLeft && (
             <TouchableOpacity
               onPress={onPressLeft}
-              style={[styles.btn, styles.leftBtn]}
+              style={[
+                styles.btn,
+                btnStyle,
+                styles.leftBtn,
+                styles.blurredBackground,
+              ]}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Previous image`)}
               accessibilityHint="">
               <FontAwesomeIcon
                 icon="angle-left"
                 style={styles.icon as FontAwesomeIconStyle}
-                size={40}
+                size={iconSize}
               />
             </TouchableOpacity>
           )}
           {canGoRight && (
             <TouchableOpacity
               onPress={onPressRight}
-              style={[styles.btn, styles.rightBtn]}
+              style={[
+                styles.btn,
+                btnStyle,
+                styles.rightBtn,
+                styles.blurredBackground,
+              ]}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Next image`)}
               accessibilityHint="">
               <FontAwesomeIcon
                 icon="angle-right"
                 style={styles.icon as FontAwesomeIconStyle}
-                size={40}
+                size={iconSize}
               />
             </TouchableOpacity>
           )}
@@ -213,20 +233,30 @@ const styles = StyleSheet.create({
   },
   btn: {
     position: 'absolute',
-    backgroundColor: '#000',
-    width: 50,
-    height: 50,
+    backgroundColor: '#00000077',
     justifyContent: 'center',
     alignItems: 'center',
+  },
+  btnTablet: {
+    width: 50,
+    height: 50,
     borderRadius: 25,
+    left: 30,
+    right: 30,
+  },
+  btnMobile: {
+    width: 44,
+    height: 44,
+    borderRadius: 22,
+    left: 20,
+    right: 20,
   },
   leftBtn: {
-    left: 30,
+    right: 'auto',
     top: '50%',
   },
   rightBtn: {
-    position: 'absolute',
-    right: 30,
+    left: 'auto',
     top: '50%',
   },
   footer: {
@@ -234,4 +264,8 @@ const styles = StyleSheet.create({
     paddingVertical: 24,
     backgroundColor: colors.black,
   },
+  blurredBackground: {
+    backdropFilter: 'blur(10px)',
+    WebkitBackdropFilter: 'blur(10px)',
+  } as ViewStyle,
 })
diff --git a/src/view/com/modals/SwitchAccount.tsx b/src/view/com/modals/SwitchAccount.tsx
index 0658805bd..892b07c9a 100644
--- a/src/view/com/modals/SwitchAccount.tsx
+++ b/src/view/com/modals/SwitchAccount.tsx
@@ -39,7 +39,7 @@ function SwitchAccountCard({account}: {account: SessionAccount}) {
     track('Settings:SignOutButtonClicked')
     closeAllActiveElements()
     // needs to be in timeout or the modal re-opens
-    setTimeout(() => logout(), 0)
+    setTimeout(() => logout('SwitchAccount'), 0)
   }, [track, logout, closeAllActiveElements])
 
   const contents = (
@@ -95,7 +95,9 @@ function SwitchAccountCard({account}: {account: SessionAccount}) {
       key={account.did}
       style={[isSwitchingAccounts && styles.dimmed]}
       onPress={
-        isSwitchingAccounts ? undefined : () => onPressSwitchAccount(account)
+        isSwitchingAccounts
+          ? undefined
+          : () => onPressSwitchAccount(account, 'SwitchAccount')
       }
       accessibilityRole="button"
       accessibilityLabel={_(msg`Switch to ${account.handle}`)}
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 8042e7bd5..ba74ba6d8 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -108,7 +108,8 @@ export function PostThread({
       ?.ui('contentList')
       .blurs.find(
         cause =>
-          cause.type === 'label' && cause.labelDef.id === '!no-unauthenticated',
+          cause.type === 'label' &&
+          cause.labelDef.identifier === '!no-unauthenticated',
       )
   }, [rootPost, moderationOpts])
 
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index b86646a4d..8afcce94f 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -90,6 +90,7 @@ let Feed = ({
   const [isPTRing, setIsPTRing] = React.useState(false)
   const checkForNewRef = React.useRef<(() => void) | null>(null)
   const lastFetchRef = React.useRef<number>(Date.now())
+  const feedType = feed.split('|')[0]
 
   const opts = React.useMemo(
     () => ({enabled, ignoreFilterFor}),
@@ -214,6 +215,10 @@ let Feed = ({
 
   const onRefresh = React.useCallback(async () => {
     track('Feed:onRefresh')
+    logEvent('feed:refresh', {
+      feedType: feedType,
+      reason: 'pull-to-refresh',
+    })
     setIsPTRing(true)
     try {
       await refetch()
@@ -222,9 +227,8 @@ let Feed = ({
       logger.error('Failed to refresh posts feed', {message: err})
     }
     setIsPTRing(false)
-  }, [refetch, track, setIsPTRing, onHasNew])
+  }, [refetch, track, setIsPTRing, onHasNew, feedType])
 
-  const feedType = feed.split('|')[0]
   const onEndReached = React.useCallback(async () => {
     if (isFetching || !hasNextPage || isError) return
 
diff --git a/src/view/com/posts/FeedErrorMessage.tsx b/src/view/com/posts/FeedErrorMessage.tsx
index c52090f97..d4ca38d07 100644
--- a/src/view/com/posts/FeedErrorMessage.tsx
+++ b/src/view/com/posts/FeedErrorMessage.tsx
@@ -46,7 +46,7 @@ export function FeedErrorMessage({
   if (
     typeof knownError !== 'undefined' &&
     knownError !== KnownError.Unknown &&
-    feedDesc.startsWith('feedgen')
+    (feedDesc.startsWith('feedgen') || knownError === KnownError.FeedNSFPublic)
   ) {
     return (
       <FeedgenErrorMessage
@@ -240,6 +240,9 @@ function detectKnownError(
   if (typeof error !== 'string') {
     error = error.toString()
   }
+  if (error.includes(KnownError.FeedNSFPublic)) {
+    return KnownError.FeedNSFPublic
+  }
   if (!feedDesc.startsWith('feedgen')) {
     return KnownError.Unknown
   }
@@ -263,8 +266,5 @@ function detectKnownError(
   if (error.includes('feed provided an invalid response')) {
     return KnownError.FeedgenBadResponse
   }
-  if (error.includes(KnownError.FeedNSFPublic)) {
-    return KnownError.FeedNSFPublic
-  }
   return KnownError.FeedgenUnknown
 }
diff --git a/src/view/com/testing/TestCtrls.e2e.tsx b/src/view/com/testing/TestCtrls.e2e.tsx
index e1e899488..1eb99c4f5 100644
--- a/src/view/com/testing/TestCtrls.e2e.tsx
+++ b/src/view/com/testing/TestCtrls.e2e.tsx
@@ -22,18 +22,24 @@ export function TestCtrls() {
   const {mutate: setFeedViewPref} = useSetFeedViewPreferencesMutation()
   const {setShowLoggedOut} = useLoggedOutViewControls()
   const onPressSignInAlice = async () => {
-    await login({
-      service: 'http://localhost:3000',
-      identifier: 'alice.test',
-      password: 'hunter2',
-    })
+    await login(
+      {
+        service: 'http://localhost:3000',
+        identifier: 'alice.test',
+        password: 'hunter2',
+      },
+      'LoginForm',
+    )
   }
   const onPressSignInBob = async () => {
-    await login({
-      service: 'http://localhost:3000',
-      identifier: 'bob.test',
-      password: 'hunter2',
-    })
+    await login(
+      {
+        service: 'http://localhost:3000',
+        identifier: 'bob.test',
+        password: 'hunter2',
+      },
+      'LoginForm',
+    )
   }
   return (
     <View style={{position: 'absolute', top: 100, right: 0, zIndex: 100}}>
@@ -51,7 +57,7 @@ export function TestCtrls() {
       />
       <Pressable
         testID="e2eSignOut"
-        onPress={() => logout()}
+        onPress={() => logout('Settings')}
         accessibilityRole="button"
         style={BTN}
       />
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
index 8656c3f51..4beedbd5b 100644
--- a/src/view/com/util/UserAvatar.tsx
+++ b/src/view/com/util/UserAvatar.tsx
@@ -298,7 +298,10 @@ let EditableUserAvatar = ({
     <Menu.Root>
       <Menu.Trigger label={_(msg`Edit avatar`)}>
         {({props}) => (
-          <TouchableOpacity {...props} activeOpacity={0.8}>
+          <TouchableOpacity
+            {...props}
+            activeOpacity={0.8}
+            testID="changeAvatarBtn">
             {avatar ? (
               <HighPriorityImage
                 testID="userAvatarImage"
diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx
index 4fb3726cd..4d73b853b 100644
--- a/src/view/com/util/UserBanner.tsx
+++ b/src/view/com/util/UserBanner.tsx
@@ -84,7 +84,10 @@ export function UserBanner({
       <Menu.Root>
         <Menu.Trigger label={_(msg`Edit avatar`)}>
           {({props}) => (
-            <TouchableOpacity {...props} activeOpacity={0.8}>
+            <TouchableOpacity
+              {...props}
+              activeOpacity={0.8}
+              testID="changeBannerBtn">
               {banner ? (
                 <Image
                   testID="userBannerImage"
diff --git a/src/view/com/util/forms/NativeDropdown.web.tsx b/src/view/com/util/forms/NativeDropdown.web.tsx
index 6abeb16cc..94591d393 100644
--- a/src/view/com/util/forms/NativeDropdown.web.tsx
+++ b/src/view/com/util/forms/NativeDropdown.web.tsx
@@ -237,7 +237,7 @@ const styles = StyleSheet.create({
     paddingRight: 12,
     borderRadius: 8,
     fontFamily:
-      '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
+      '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif',
     outline: 0,
     border: 0,
   },
diff --git a/src/view/com/util/text/Text.tsx b/src/view/com/util/text/Text.tsx
index ccb51bfca..37d665581 100644
--- a/src/view/com/util/text/Text.tsx
+++ b/src/view/com/util/text/Text.tsx
@@ -2,7 +2,7 @@ import React from 'react'
 import {Text as RNText, TextProps} from 'react-native'
 import {s, lh} from 'lib/styles'
 import {useTheme, TypographyVariant} from 'lib/ThemeContext'
-import {isIOS} from 'platform/detection'
+import {isIOS, isWeb} from 'platform/detection'
 import {UITextView} from 'react-native-ui-text-view'
 
 export type CustomTextProps = TextProps & {
@@ -13,6 +13,11 @@ export type CustomTextProps = TextProps & {
   selectable?: boolean
 }
 
+const fontFamilyStyle = {
+  fontFamily:
+    '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif',
+}
+
 export function Text({
   type = 'md',
   children,
@@ -39,7 +44,13 @@ export function Text({
 
   return (
     <RNText
-      style={[s.black, typography, lineHeightStyle, style]}
+      style={[
+        s.black,
+        typography,
+        isWeb && fontFamilyStyle,
+        lineHeightStyle,
+        style,
+      ]}
       // @ts-ignore web only -esb
       dataSet={Object.assign({tooltip: title}, dataSet || {})}
       selectable={selectable}