diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/App.native.tsx | 11 | ||||
-rw-r--r-- | src/Navigation.tsx | 93 | ||||
-rw-r--r-- | src/lib/analytics/analytics.tsx | 6 | ||||
-rw-r--r-- | src/lib/analytics/analytics.web.tsx | 6 | ||||
-rw-r--r-- | src/lib/strings/headings.ts | 2 | ||||
-rw-r--r-- | src/state/models/feeds/post.ts | 14 | ||||
-rw-r--r-- | src/view/com/auth/create/Step2.tsx | 14 | ||||
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 6 | ||||
-rw-r--r-- | src/view/com/profile/ProfileHeader.tsx | 17 | ||||
-rw-r--r-- | src/view/com/util/Link.tsx | 13 | ||||
-rw-r--r-- | src/view/com/util/PostMeta.tsx | 6 | ||||
-rw-r--r-- | src/view/com/util/UserInfoText.tsx | 4 | ||||
-rw-r--r-- | src/view/com/util/images/AutoSizedImage.tsx | 12 | ||||
-rw-r--r-- | src/view/shell/desktop/LeftNav.tsx | 12 | ||||
-rw-r--r-- | src/view/shell/index.tsx | 7 |
15 files changed, 119 insertions, 104 deletions
diff --git a/src/App.native.tsx b/src/App.native.tsx index f99e976ce..f4298c461 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -2,7 +2,6 @@ import 'react-native-url-polyfill/auto' import React, {useState, useEffect} from 'react' import 'lib/sentry' // must be relatively on top import {withSentry} from 'lib/sentry' -import {Linking} from 'react-native' import {RootSiblingParent} from 'react-native-root-siblings' import * as SplashScreen from 'expo-splash-screen' import {GestureHandlerRootView} from 'react-native-gesture-handler' @@ -15,7 +14,6 @@ import {Shell} from './view/shell' import * as notifications from 'lib/notifications/notifications' import * as analytics from 'lib/analytics/analytics' import * as Toast from './view/com/util/Toast' -import {handleLink} from './Navigation' import {QueryClientProvider} from '@tanstack/react-query' import {queryClient} from 'lib/react-query' import {TestCtrls} from 'view/com/testing/TestCtrls' @@ -34,15 +32,6 @@ const App = observer(function AppImpl() { setRootStore(store) analytics.init(store) notifications.init(store) - SplashScreen.hideAsync() - Linking.getInitialURL().then((url: string | null) => { - if (url) { - handleLink(url) - } - }) - Linking.addEventListener('url', ({url}) => { - handleLink(url) - }) store.onSessionDropped(() => { Toast.show('Sorry! Your session expired. Please log in again.') }) diff --git a/src/Navigation.tsx b/src/Navigation.tsx index e1d5e76aa..a75651987 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -1,5 +1,6 @@ import * as React from 'react' import {StyleSheet} from 'react-native' +import * as SplashScreen from 'expo-splash-screen' import {observer} from 'mobx-react-lite' import { NavigationContainer, @@ -91,42 +92,42 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) { <> <Stack.Screen name="NotFound" - component={NotFoundScreen} + getComponent={() => NotFoundScreen} options={{title: title('Not Found')}} /> <Stack.Screen name="Moderation" - component={ModerationScreen} + getComponent={() => ModerationScreen} options={{title: title('Moderation')}} /> <Stack.Screen name="ModerationMuteLists" - component={ModerationMuteListsScreen} + getComponent={() => ModerationMuteListsScreen} options={{title: title('Mute Lists')}} /> <Stack.Screen name="ModerationMutedAccounts" - component={ModerationMutedAccounts} + getComponent={() => ModerationMutedAccounts} options={{title: title('Muted Accounts')}} /> <Stack.Screen name="ModerationBlockedAccounts" - component={ModerationBlockedAccounts} + getComponent={() => ModerationBlockedAccounts} options={{title: title('Blocked Accounts')}} /> <Stack.Screen name="Settings" - component={SettingsScreen} + getComponent={() => SettingsScreen} options={{title: title('Settings')}} /> <Stack.Screen name="LanguageSettings" - component={LanguageSettingsScreen} + getComponent={() => LanguageSettingsScreen} options={{title: title('Language Settings')}} /> <Stack.Screen name="Profile" - component={ProfileScreen} + getComponent={() => ProfileScreen} options={({route}) => ({ title: title(`@${route.params.name}`), animation: 'none', @@ -134,101 +135,101 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) { /> <Stack.Screen name="ProfileFollowers" - component={ProfileFollowersScreen} + getComponent={() => ProfileFollowersScreen} options={({route}) => ({ title: title(`People following @${route.params.name}`), })} /> <Stack.Screen name="ProfileFollows" - component={ProfileFollowsScreen} + getComponent={() => ProfileFollowsScreen} options={({route}) => ({ title: title(`People followed by @${route.params.name}`), })} /> <Stack.Screen name="ProfileList" - component={ProfileListScreen} + getComponent={() => ProfileListScreen} options={{title: title('Mute List')}} /> <Stack.Screen name="PostThread" - component={PostThreadScreen} + getComponent={() => PostThreadScreen} options={({route}) => ({title: title(`Post by @${route.params.name}`)})} /> <Stack.Screen name="PostLikedBy" - component={PostLikedByScreen} + getComponent={() => PostLikedByScreen} options={({route}) => ({title: title(`Post by @${route.params.name}`)})} /> <Stack.Screen name="PostRepostedBy" - component={PostRepostedByScreen} + getComponent={() => PostRepostedByScreen} options={({route}) => ({title: title(`Post by @${route.params.name}`)})} /> <Stack.Screen name="CustomFeed" - component={CustomFeedScreen} + getComponent={() => CustomFeedScreen} options={{title: title('Feed')}} /> <Stack.Screen name="CustomFeedLikedBy" - component={CustomFeedLikedByScreen} + getComponent={() => CustomFeedLikedByScreen} options={{title: title('Liked by')}} /> <Stack.Screen name="Debug" - component={DebugScreen} + getComponent={() => DebugScreen} options={{title: title('Debug')}} /> <Stack.Screen name="Log" - component={LogScreen} + getComponent={() => LogScreen} options={{title: title('Log')}} /> <Stack.Screen name="Support" - component={SupportScreen} + getComponent={() => SupportScreen} options={{title: title('Support')}} /> <Stack.Screen name="PrivacyPolicy" - component={PrivacyPolicyScreen} + getComponent={() => PrivacyPolicyScreen} options={{title: title('Privacy Policy')}} /> <Stack.Screen name="TermsOfService" - component={TermsOfServiceScreen} + getComponent={() => TermsOfServiceScreen} options={{title: title('Terms of Service')}} /> <Stack.Screen name="CommunityGuidelines" - component={CommunityGuidelinesScreen} + getComponent={() => CommunityGuidelinesScreen} options={{title: title('Community Guidelines')}} /> <Stack.Screen name="CopyrightPolicy" - component={CopyrightPolicyScreen} + getComponent={() => CopyrightPolicyScreen} options={{title: title('Copyright Policy')}} /> <Stack.Screen name="AppPasswords" - component={AppPasswords} + getComponent={() => AppPasswords} options={{title: title('App Passwords')}} /> <Stack.Screen name="SavedFeeds" - component={SavedFeeds} + getComponent={() => SavedFeeds} options={{title: title('Edit My Feeds')}} /> <Stack.Screen name="PreferencesHomeFeed" - component={PreferencesHomeFeed} + getComponent={() => PreferencesHomeFeed} options={{title: title('Home Feed Preferences')}} /> <Stack.Screen name="PreferencesThreads" - component={PreferencesThreads} + getComponent={() => PreferencesThreads} options={{title: title('Threads Preferences')}} /> </> @@ -253,14 +254,17 @@ function TabsNavigator() { backBehavior="initialRoute" screenOptions={{headerShown: false, lazy: true}} tabBar={tabBar}> - <Tab.Screen name="HomeTab" component={HomeTabNavigator} /> - <Tab.Screen name="SearchTab" component={SearchTabNavigator} /> - <Tab.Screen name="FeedsTab" component={FeedsTabNavigator} /> + <Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} /> + <Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} /> + <Tab.Screen name="FeedsTab" getComponent={() => FeedsTabNavigator} /> <Tab.Screen name="NotificationsTab" - component={NotificationsTabNavigator} + getComponent={() => NotificationsTabNavigator} + /> + <Tab.Screen + name="MyProfileTab" + getComponent={() => MyProfileTabNavigator} /> - <Tab.Screen name="MyProfileTab" component={MyProfileTabNavigator} /> </Tab.Navigator> ) } @@ -277,7 +281,7 @@ function HomeTabNavigator() { animationDuration: 250, contentStyle, }}> - <HomeTab.Screen name="Home" component={HomeScreen} /> + <HomeTab.Screen name="Home" getComponent={() => HomeScreen} /> {commonScreens(HomeTab)} </HomeTab.Navigator> ) @@ -294,7 +298,7 @@ function SearchTabNavigator() { animationDuration: 250, contentStyle, }}> - <SearchTab.Screen name="Search" component={SearchScreen} /> + <SearchTab.Screen name="Search" getComponent={() => SearchScreen} /> {commonScreens(SearchTab as typeof HomeTab)} </SearchTab.Navigator> ) @@ -311,7 +315,7 @@ function FeedsTabNavigator() { animationDuration: 250, contentStyle, }}> - <FeedsTab.Screen name="Feeds" component={FeedsScreen} /> + <FeedsTab.Screen name="Feeds" getComponent={() => FeedsScreen} /> {commonScreens(FeedsTab as typeof HomeTab)} </FeedsTab.Navigator> ) @@ -330,7 +334,7 @@ function NotificationsTabNavigator() { }}> <NotificationsTab.Screen name="Notifications" - component={NotificationsScreen} + getComponent={() => NotificationsScreen} /> {commonScreens(NotificationsTab as typeof HomeTab)} </NotificationsTab.Navigator> @@ -352,7 +356,7 @@ const MyProfileTabNavigator = observer(function MyProfileTabNavigatorImpl() { <MyProfileTab.Screen name="MyProfile" // @ts-ignore // TODO: fix this broken type in ProfileScreen - component={ProfileScreen} + getComponent={() => ProfileScreen} initialParams={{ name: store.me.did, }} @@ -383,22 +387,22 @@ const FlatNavigator = observer(function FlatNavigatorImpl() { }}> <Flat.Screen name="Home" - component={HomeScreen} + getComponent={() => HomeScreen} options={{title: title('Home')}} /> <Flat.Screen name="Search" - component={SearchScreen} + getComponent={() => SearchScreen} options={{title: title('Search')}} /> <Flat.Screen name="Feeds" - component={FeedsScreen} + getComponent={() => FeedsScreen} options={{title: title('Feeds')}} /> <Flat.Screen name="Notifications" - component={NotificationsScreen} + getComponent={() => NotificationsScreen} options={{title: title('Notifications')}} /> {commonScreens(Flat as typeof HomeTab, unreadCountLabel)} @@ -462,6 +466,13 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { linking={LINKING} theme={theme} onReady={() => { + SplashScreen.hideAsync() + const initMs = Math.round( + // @ts-ignore Emitted by Metro in the bundle prelude + performance.now() - global.__BUNDLE_START_TIME__, + ) + console.log(`Time to first paint: ${initMs} ms`) + // Register the navigation container with the Sentry instrumentation (only works on native) if (isNative) { const routingInstrumentation = getRoutingInstrumentation() diff --git a/src/lib/analytics/analytics.tsx b/src/lib/analytics/analytics.tsx index d1eb50f8a..b3db9149c 100644 --- a/src/lib/analytics/analytics.tsx +++ b/src/lib/analytics/analytics.tsx @@ -51,10 +51,10 @@ export function init(store: RootStoreModel) { store.onSessionLoaded(() => { const sess = store.session.currentSession if (sess) { - if (sess.email) { + if (sess.did) { + const did_hashed = sha256(sess.did) + segmentClient.identify(did_hashed, {did_hashed}) store.log.debug('Ping w/hash') - const email_hashed = sha256(sess.email) - segmentClient.identify(email_hashed, {email_hashed}) } else { store.log.debug('Ping w/o hash') segmentClient.identify() diff --git a/src/lib/analytics/analytics.web.tsx b/src/lib/analytics/analytics.web.tsx index db9d86e3c..78bd9b42b 100644 --- a/src/lib/analytics/analytics.web.tsx +++ b/src/lib/analytics/analytics.web.tsx @@ -46,10 +46,10 @@ export function init(store: RootStoreModel) { store.onSessionLoaded(() => { const sess = store.session.currentSession if (sess) { - if (sess.email) { + if (sess.did) { + const did_hashed = sha256(sess.did) + segmentClient.identify(did_hashed, {did_hashed}) store.log.debug('Ping w/hash') - const email_hashed = sha256(sess.email) - segmentClient.identify(email_hashed, {email_hashed}) } else { store.log.debug('Ping w/o hash') segmentClient.identify() diff --git a/src/lib/strings/headings.ts b/src/lib/strings/headings.ts index a88a69645..f9a062492 100644 --- a/src/lib/strings/headings.ts +++ b/src/lib/strings/headings.ts @@ -1,4 +1,4 @@ export function bskyTitle(page: string, unreadCountLabel?: string) { const unreadPrefix = unreadCountLabel ? `(${unreadCountLabel}) ` : '' - return `${unreadPrefix}${page} - Bluesky` + return `${unreadPrefix}${page} — Bluesky` } diff --git a/src/state/models/feeds/post.ts b/src/state/models/feeds/post.ts index ae4f29105..d46cced75 100644 --- a/src/state/models/feeds/post.ts +++ b/src/state/models/feeds/post.ts @@ -116,6 +116,7 @@ export class PostsFeedItemModel { }, () => this.rootStore.agent.deleteLike(url), ) + track('Post:Unlike') } else { // like await updateDataOptimistically( @@ -129,11 +130,10 @@ export class PostsFeedItemModel { this.post.viewer!.like = res.uri }, ) + track('Post:Like') } } catch (error) { this.rootStore.log.error('Failed to toggle like', error) - } finally { - track(this.post.viewer.like ? 'Post:Unlike' : 'Post:Like') } } @@ -141,6 +141,7 @@ export class PostsFeedItemModel { this.post.viewer = this.post.viewer || {} try { if (this.post.viewer?.repost) { + // unrepost const url = this.post.viewer.repost await updateDataOptimistically( this.post, @@ -150,7 +151,9 @@ export class PostsFeedItemModel { }, () => this.rootStore.agent.deleteRepost(url), ) + track('Post:Unrepost') } else { + // repost await updateDataOptimistically( this.post, () => { @@ -162,11 +165,10 @@ export class PostsFeedItemModel { this.post.viewer!.repost = res.uri }, ) + track('Post:Repost') } } catch (error) { this.rootStore.log.error('Failed to toggle repost', error) - } finally { - track(this.post.viewer.repost ? 'Post:Unrepost' : 'Post:Repost') } } @@ -174,13 +176,13 @@ export class PostsFeedItemModel { try { if (this.isThreadMuted) { this.rootStore.mutedThreads.uris.delete(this.rootUri) + track('Post:ThreadUnmute') } else { this.rootStore.mutedThreads.uris.add(this.rootUri) + track('Post:ThreadMute') } } catch (error) { this.rootStore.log.error('Failed to toggle thread mute', error) - } finally { - track(this.isThreadMuted ? 'Post:ThreadUnmute' : 'Post:ThreadMute') } } diff --git a/src/view/com/auth/create/Step2.tsx b/src/view/com/auth/create/Step2.tsx index 83b0aee40..60e197564 100644 --- a/src/view/com/auth/create/Step2.tsx +++ b/src/view/com/auth/create/Step2.tsx @@ -11,6 +11,7 @@ import {TextInput} from '../util/TextInput' import {Policies} from './Policies' import {ErrorMessage} from 'view/com/util/error/ErrorMessage' import {useStores} from 'state/index' +import {isWeb} from 'platform/detection' /** STEP 2: Your account * @field Invite code or waitlist @@ -60,10 +61,11 @@ export const Step2 = observer(function Step2Impl({ Don't have an invite code?{' '} <TouchableWithoutFeedback onPress={onPressWaitlist} - accessibilityRole="button" - accessibilityLabel="Waitlist" - accessibilityHint="Opens Bluesky waitlist form"> - <Text style={pal.link}>Join the waitlist.</Text> + accessibilityLabel="Join the waitlist." + accessibilityHint=""> + <View style={styles.touchable}> + <Text style={pal.link}>Join the waitlist.</Text> + </View> </TouchableWithoutFeedback> </Text> ) : ( @@ -151,4 +153,8 @@ const styles = StyleSheet.create({ borderRadius: 6, paddingVertical: 14, }, + // @ts-expect-error: Suppressing error due to incomplete `ViewStyle` type definition in react-native-web, missing `cursor` prop as discussed in https://github.com/necolas/react-native-web/issues/832. + touchable: { + ...(isWeb && {cursor: 'pointer'}), + }, }) diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index 77c71f26d..441621638 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -9,7 +9,7 @@ import { } from '@fortawesome/react-native-fontawesome' import {PostsFeedItemModel} from 'state/models/feeds/post' import {FeedSourceInfo} from 'lib/api/feed/types' -import {Link, DesktopWebTextLink, TextLink} from '../util/Link' +import {Link, TextLinkOnWebOnly, TextLink} from '../util/Link' import {Text} from '../util/text/Text' import {UserInfoText} from '../util/UserInfoText' import {PostMeta} from '../util/PostMeta' @@ -198,7 +198,7 @@ export const FeedItem = observer(function FeedItemImpl({ lineHeight={1.2} numberOfLines={1}> From{' '} - <DesktopWebTextLink + <TextLinkOnWebOnly type="sm-bold" style={pal.textLight} lineHeight={1.2} @@ -229,7 +229,7 @@ export const FeedItem = observer(function FeedItemImpl({ lineHeight={1.2} numberOfLines={1}> Reposted by{' '} - <DesktopWebTextLink + <TextLinkOnWebOnly type="sm-bold" style={pal.textLight} lineHeight={1.2} diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index df19ecad5..6bb3bc5f6 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -119,7 +119,11 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ const [showSuggestedFollows, setShowSuggestedFollows] = React.useState(false) const onPressBack = React.useCallback(() => { - navigation.goBack() + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } }, [navigation]) const onPressAvi = React.useCallback(() => { @@ -132,20 +136,19 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ }, [store, view]) const onPressToggleFollow = React.useCallback(() => { - track( - view.viewer.following - ? 'ProfileHeader:FollowButtonClicked' - : 'ProfileHeader:UnfollowButtonClicked', - ) view?.toggleFollowing().then( () => { setShowSuggestedFollows(Boolean(view.viewer.following)) - Toast.show( `${ view.viewer.following ? 'Following' : 'No longer following' } ${sanitizeDisplayName(view.displayName || view.handle)}`, ) + track( + view.viewer.following + ? 'ProfileHeader:FollowButtonClicked' + : 'ProfileHeader:UnfollowButtonClicked', + ) }, err => store.log.error('Failed to toggle follow', err), ) diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index 35524bcc6..1777f6659 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -27,11 +27,10 @@ import { isExternalUrl, linkRequiresWarning, } from 'lib/strings/url-helpers' -import {isAndroid} from 'platform/detection' +import {isAndroid, isWeb} from 'platform/detection' import {sanitizeUrl} from '@braintree/sanitize-url' import {PressableWithHover} from './PressableWithHover' import FixedTouchableHighlight from '../pager/FixedTouchableHighlight' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' type Event = | React.MouseEvent<HTMLAnchorElement, MouseEvent> @@ -222,7 +221,7 @@ export const TextLink = memo(function TextLink({ /** * Only acts as a link on desktop web */ -interface DesktopWebTextLinkProps extends TextProps { +interface TextLinkOnWebOnlyProps extends TextProps { testID?: string type?: TypographyVariant style?: StyleProp<TextStyle> @@ -235,7 +234,7 @@ interface DesktopWebTextLinkProps extends TextProps { accessibilityHint?: string title?: string } -export const DesktopWebTextLink = memo(function DesktopWebTextLink({ +export const TextLinkOnWebOnly = memo(function DesktopWebTextLink({ testID, type = 'md', style, @@ -244,10 +243,8 @@ export const DesktopWebTextLink = memo(function DesktopWebTextLink({ numberOfLines, lineHeight, ...props -}: DesktopWebTextLinkProps) { - const {isDesktop} = useWebMediaQueries() - - if (isDesktop) { +}: TextLinkOnWebOnlyProps) { + if (isWeb) { return ( <TextLink testID={testID} diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index b5c47dea5..c5e438f8d 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -1,7 +1,7 @@ import React from 'react' import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native' import {Text} from './text/Text' -import {DesktopWebTextLink} from './Link' +import {TextLinkOnWebOnly} from './Link' import {niceDate} from 'lib/strings/time' import {usePalette} from 'lib/hooks/usePalette' import {TypographyVariant} from 'lib/ThemeContext' @@ -47,7 +47,7 @@ export const PostMeta = observer(function PostMetaImpl(opts: PostMetaOpts) { </View> )} <View style={styles.maxWidth}> - <DesktopWebTextLink + <TextLinkOnWebOnly type={opts.displayNameType || 'lg-bold'} style={[pal.text, opts.displayNameStyle]} numberOfLines={1} @@ -78,7 +78,7 @@ export const PostMeta = observer(function PostMetaImpl(opts: PostMetaOpts) { )} <TimeElapsed timestamp={opts.timestamp}> {({timeElapsed}) => ( - <DesktopWebTextLink + <TextLinkOnWebOnly type="md" style={pal.textLight} lineHeight={1.2} diff --git a/src/view/com/util/UserInfoText.tsx b/src/view/com/util/UserInfoText.tsx index 695711b2a..e4ca981d9 100644 --- a/src/view/com/util/UserInfoText.tsx +++ b/src/view/com/util/UserInfoText.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect} from 'react' import {AppBskyActorGetProfile as GetProfile} from '@atproto/api' import {StyleProp, StyleSheet, TextStyle} from 'react-native' -import {DesktopWebTextLink} from './Link' +import {TextLinkOnWebOnly} from './Link' import {Text} from './text/Text' import {LoadingPlaceholder} from './LoadingPlaceholder' import {useStores} from 'state/index' @@ -65,7 +65,7 @@ export function UserInfoText({ ) } else if (profile) { inner = ( - <DesktopWebTextLink + <TextLinkOnWebOnly type={type} style={style} lineHeight={1.2} diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx index 035e29c25..6cbcddc32 100644 --- a/src/view/com/util/images/AutoSizedImage.tsx +++ b/src/view/com/util/images/AutoSizedImage.tsx @@ -52,20 +52,20 @@ export function AutoSizedImage({ if (onPress || onLongPress || onPressIn) { return ( + // disable a11y rule because in this case we want the tags on the image (#1640) + // eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors <Pressable onPress={onPress} onLongPress={onLongPress} onPressIn={onPressIn} - style={[styles.container, style]} - accessible={true} - accessibilityRole="button" - accessibilityLabel={alt || 'Image'} - accessibilityHint="Tap to view fully"> + style={[styles.container, style]}> <Image style={[styles.image, {aspectRatio}]} source={uri} - accessible={false} // Must set for `accessibilityLabel` to work + accessible={true} // Must set for `accessibilityLabel` to work accessibilityIgnoresInvertColors + accessibilityLabel={alt} + accessibilityHint="Tap to view fully" /> {children} </Pressable> diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index cbff3a1c4..2679a6648 100644 --- a/src/view/shell/desktop/LeftNav.tsx +++ b/src/view/shell/desktop/LeftNav.tsx @@ -460,18 +460,22 @@ const styles = StyleSheet.create({ justifyContent: 'center', width: 140, borderRadius: 24, - paddingVertical: 10, - paddingHorizontal: 16, + paddingTop: 10, + paddingBottom: 12, // visually aligns the text vertically inside the button + paddingLeft: 16, + paddingRight: 18, // looks nicer like this backgroundColor: colors.blue3, marginLeft: 12, marginTop: 20, marginBottom: 10, gap: 8, }, - newPostBtnIconWrapper: {}, + newPostBtnIconWrapper: { + marginTop: 2, // aligns the icon visually with the text + }, newPostBtnLabel: { color: colors.white, fontSize: 16, - fontWeight: 'bold', + fontWeight: '600', }, }) diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx index 3119715e9..b564f99f8 100644 --- a/src/view/shell/index.tsx +++ b/src/view/shell/index.tsx @@ -21,7 +21,10 @@ import {usePalette} from 'lib/hooks/usePalette' import * as backHandler from 'lib/routes/back-handler' import {RoutesContainer, TabsNavigator} from '../../Navigation' import {isStateAtTabRoot} from 'lib/routes/helpers' -import {SafeAreaProvider} from 'react-native-safe-area-context' +import { + SafeAreaProvider, + initialWindowMetrics, +} from 'react-native-safe-area-context' import {useOTAUpdate} from 'lib/hooks/useOTAUpdate' const ShellInner = observer(function ShellInnerImpl() { @@ -87,7 +90,7 @@ export const Shell: React.FC = observer(function ShellImpl() { const pal = usePalette('default') const theme = useTheme() return ( - <SafeAreaProvider style={pal.view}> + <SafeAreaProvider initialMetrics={initialWindowMetrics} style={pal.view}> <View testID="mobileShellView" style={[styles.outerContainer, pal.view]}> <StatusBar style={theme.colorScheme === 'dark' ? 'light' : 'dark'} /> <RoutesContainer> |