From c13b1374d7ff25b913405b96cc568dce6c929be0 Mon Sep 17 00:00:00 2001 From: Ana Date: Mon, 28 Jul 2025 20:22:58 -0700 Subject: add: toasts to storybook --- src/view/screens/Storybook/Toasts.tsx | 69 +++++++++++++++++++++++++++++++++++ src/view/screens/Storybook/index.tsx | 2 + 2 files changed, 71 insertions(+) create mode 100644 src/view/screens/Storybook/Toasts.tsx (limited to 'src') diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx new file mode 100644 index 000000000..714afdfbd --- /dev/null +++ b/src/view/screens/Storybook/Toasts.tsx @@ -0,0 +1,69 @@ +import {View} from 'react-native' + +import {atoms as a} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import {H1} from '#/components/Typography' +import * as Toast from '#/view/com/util/Toast' +import * as ToastHelpers from '#/view/com/util/ToastHelpers' + +export function Toasts() { + return ( + +

Toasts

+ + + + + + + + + + + + +
+ ) +} diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx index a6c2ecdde..afcc1c4e7 100644 --- a/src/view/screens/Storybook/index.tsx +++ b/src/view/screens/Storybook/index.tsx @@ -20,6 +20,7 @@ import {Settings} from './Settings' import {Shadows} from './Shadows' import {Spacing} from './Spacing' import {Theming} from './Theming' +import {Toasts} from './Toasts' import {Typography} from './Typography' export function Storybook() { @@ -122,6 +123,7 @@ function StorybookInner() { + -- cgit 1.4.1 From e5457c946a5bf56fafde790ced9014e1cb73cd34 Mon Sep 17 00:00:00 2001 From: Caidan Williams Date: Tue, 29 Jul 2025 17:04:47 -0700 Subject: feat(ui): improve suggested follow placeholder card Now matches the same size and shape as the rendered card, which prevents content layout shift. --- src/components/FeedInterstitials.tsx | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx index aab54b7df..e4419838d 100644 --- a/src/components/FeedInterstitials.tsx +++ b/src/components/FeedInterstitials.tsx @@ -25,7 +25,7 @@ import { type ViewStyleProp, web, } from '#/alf' -import {Button} from '#/components/Button' +import {Button, ButtonText} from '#/components/Button' import * as FeedCard from '#/components/FeedCard' import {ArrowRight_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow' import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag' @@ -64,15 +64,30 @@ function CardOuter({ export function SuggestedFollowPlaceholder() { const t = useTheme() + return ( - - - - - - + + + + + + + + - + + + ) } -- cgit 1.4.1 From 7b4ec21e3e60cb25197fb277f3ba54fa627e4e1e Mon Sep 17 00:00:00 2001 From: Caidan Williams Date: Tue, 29 Jul 2025 17:05:13 -0700 Subject: refactor(ui): adjust border styles in ProfileGrid card --- src/components/FeedInterstitials.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx index e4419838d..9bdfcbc5e 100644 --- a/src/components/FeedInterstitials.tsx +++ b/src/components/FeedInterstitials.tsx @@ -308,10 +308,8 @@ export function ProfileGrid({ Date: Tue, 29 Jul 2025 17:29:22 -0700 Subject: feat(ui): add "See More Suggested Profiles" card --- src/components/FeedInterstitials.tsx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src') diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx index 9bdfcbc5e..2a3a00ba7 100644 --- a/src/components/FeedInterstitials.tsx +++ b/src/components/FeedInterstitials.tsx @@ -415,6 +415,8 @@ export function ProfileGrid({ style={[a.overflow_visible]}> {content} + + @@ -424,6 +426,32 @@ export function ProfileGrid({ ) } +function SeeMoreSuggestedProfilesCard() { + const navigation = useNavigation() + const t = useTheme() + const {_} = useLingui() + + return ( + + ) +} + export function SuggestedFeeds() { const numFeedsToDisplay = 3 const t = useTheme() -- cgit 1.4.1 From 0a00e02c701aee2151b8f708e9b53af81a41d44e Mon Sep 17 00:00:00 2001 From: pfrazee <1270099+pfrazee@users.noreply.github.com> Date: Wed, 30 Jul 2025 02:51:39 +0000 Subject: Nightly source-language update --- src/locale/locales/en/messages.po | 53 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po index 69532591c..3a5480a5c 100644 --- a/src/locale/locales/en/messages.po +++ b/src/locale/locales/en/messages.po @@ -966,8 +966,8 @@ msgstr "" #: src/components/hooks/useFollowMethods.ts:35 #: src/components/hooks/useFollowMethods.ts:50 -#: src/components/ProfileCard.tsx:457 -#: src/components/ProfileCard.tsx:478 +#: src/components/ProfileCard.tsx:484 +#: src/components/ProfileCard.tsx:505 #: src/view/com/profile/FollowButton.tsx:38 #: src/view/com/profile/FollowButton.tsx:48 msgid "An issue occurred, please try again." @@ -1262,7 +1262,7 @@ msgid "Birthday" msgstr "" #: src/components/PostControls/PostMenu/PostMenuItems.tsx:757 -#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:319 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:320 #: src/view/com/profile/ProfileMenu.tsx:473 msgid "Block" msgstr "" @@ -1423,23 +1423,20 @@ msgstr "" msgid "Books" msgstr "" -#: src/components/FeedInterstitials.tsx:379 +#: src/components/FeedInterstitials.tsx:436 msgid "Browse more accounts on the Explore page" msgstr "" -#: src/components/FeedInterstitials.tsx:517 +#: src/components/FeedInterstitials.tsx:566 msgid "Browse more feeds on the Explore page" msgstr "" -#: src/components/FeedInterstitials.tsx:359 -#: src/components/FeedInterstitials.tsx:362 -#: src/components/FeedInterstitials.tsx:498 -#: src/components/FeedInterstitials.tsx:501 +#: src/components/FeedInterstitials.tsx:547 +#: src/components/FeedInterstitials.tsx:550 msgid "Browse more suggestions" msgstr "" -#: src/components/FeedInterstitials.tsx:387 -#: src/components/FeedInterstitials.tsx:526 +#: src/components/FeedInterstitials.tsx:575 msgid "Browse more suggestions on the Explore page" msgstr "" @@ -3618,7 +3615,7 @@ msgid "Flexible" msgstr "" #. User is not following this account, click to follow -#: src/components/ProfileCard.tsx:490 +#: src/components/ProfileCard.tsx:517 #: src/components/ProfileHoverCard/index.web.tsx:494 #: src/components/ProfileHoverCard/index.web.tsx:505 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:245 @@ -3696,7 +3693,7 @@ msgid "Followers you know" msgstr "" #. User is following this account, click to unfollow -#: src/components/ProfileCard.tsx:484 +#: src/components/ProfileCard.tsx:511 #: src/components/ProfileHoverCard/index.web.tsx:493 #: src/components/ProfileHoverCard/index.web.tsx:504 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:241 @@ -3711,7 +3708,7 @@ msgctxt "feed-name" msgid "Following" msgstr "" -#: src/components/ProfileCard.tsx:447 +#: src/components/ProfileCard.tsx:474 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:89 msgid "Following {0}" msgstr "" @@ -5459,7 +5456,7 @@ msgstr "" msgid "No likes yet" msgstr "" -#: src/components/ProfileCard.tsx:469 +#: src/components/ProfileCard.tsx:496 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:110 msgid "No longer following {0}" msgstr "" @@ -7398,6 +7395,18 @@ msgstr "" msgid "See jobs at Bluesky" msgstr "" +#: src/components/FeedInterstitials.tsx:397 +msgid "See more" +msgstr "" + +#: src/components/FeedInterstitials.tsx:444 +msgid "See more accounts you might like" +msgstr "" + +#: src/components/FeedInterstitials.tsx:395 +msgid "See more suggested profiles on the Explore page" +msgstr "" + #: src/view/screens/SavedFeeds.tsx:213 msgid "See this guide" msgstr "" @@ -7975,7 +7984,7 @@ msgstr "" msgid "Signed in as @{0}" msgstr "" -#: src/components/FeedInterstitials.tsx:343 +#: src/components/FeedInterstitials.tsx:389 msgid "Similar accounts" msgstr "" @@ -8005,7 +8014,7 @@ msgstr "" msgid "Some of your verifications are invalid." msgstr "" -#: src/components/FeedInterstitials.tsx:480 +#: src/components/FeedInterstitials.tsx:529 msgid "Some other feeds you might like" msgstr "" @@ -8237,7 +8246,7 @@ msgstr "" msgid "Suggested Accounts" msgstr "" -#: src/components/FeedInterstitials.tsx:345 +#: src/components/FeedInterstitials.tsx:391 msgid "Suggested for you" msgstr "" @@ -8421,7 +8430,7 @@ msgstr "" msgid "That's everything!" msgstr "" -#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:315 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:316 #: src/view/com/profile/ProfileMenu.tsx:461 msgid "The account will be able to interact with you after unblocking." msgstr "" @@ -9046,7 +9055,7 @@ msgstr "" #: src/components/dms/MessagesListBlockedFooter.tsx:112 #: src/components/dms/MessagesListBlockedFooter.tsx:119 #: src/screens/Profile/Header/ProfileHeaderStandard.tsx:203 -#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:319 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:320 #: src/view/com/profile/ProfileMenu.tsx:473 #: src/view/screens/ProfileList.tsx:723 msgid "Unblock" @@ -9064,7 +9073,7 @@ msgstr "" msgid "Unblock account" msgstr "" -#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:313 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:314 #: src/view/com/profile/ProfileMenu.tsx:455 msgid "Unblock Account?" msgstr "" @@ -9571,7 +9580,7 @@ msgstr "" msgid "View {0}'s avatar" msgstr "" -#: src/components/ProfileCard.tsx:118 +#: src/components/ProfileCard.tsx:124 #: src/screens/Profile/components/ProfileFeedHeader.tsx:454 #: src/screens/Search/components/SearchProfileCard.tsx:36 #: src/screens/VideoFeed/index.tsx:790 -- cgit 1.4.1 From 34ea6e8f3499eeeb1013dfbf7c4dcd3bdcf149a3 Mon Sep 17 00:00:00 2001 From: Ana Date: Tue, 29 Jul 2025 18:15:32 -0700 Subject: update: toast styles that reuse consistent style --- src/view/com/util/Toast.tsx | 182 ++++++++++++---------------------- src/view/com/util/Toast.web.tsx | 148 +++++++++++++-------------- src/view/screens/Storybook/Toasts.tsx | 139 ++++++++++++++++---------- 3 files changed, 216 insertions(+), 253 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index fc9bdf672..2f8888bef 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -6,8 +6,8 @@ import { GestureHandlerRootView, } from 'react-native-gesture-handler' import Animated, { - FadeInUp, - FadeOutUp, + FadeIn, + FadeOut, runOnJS, useAnimatedReaction, useAnimatedStyle, @@ -17,53 +17,36 @@ import Animated, { } from 'react-native-reanimated' import RootSiblings from 'react-native-root-siblings' import {useSafeAreaInsets} from 'react-native-safe-area-context' -import { - FontAwesomeIcon, - type Props as FontAwesomeProps, -} from '@fortawesome/react-native-fontawesome' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' -import {isWeb} from '#/platform/detection' import {atoms as a, useTheme} from '#/alf' import {Text} from '#/components/Typography' +import { + type ToastType, + TOAST_TYPE_TO_ICON, + getToastTypeStyles, + TOAST_ANIMATION_CONFIG, +} from './Toast.style' const TIMEOUT = 2e3 -export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' - -const TOAST_TYPE_TO_ICON: Record = { - default: 'check', - success: 'check', - error: 'exclamation', - warning: 'circle-exclamation', - info: 'info', -} - -export function show( - message: string, - type: ToastType | FontAwesomeProps['icon'] = 'default', -) { +export function show(message: string, type: ToastType = 'default') { if (process.env.NODE_ENV === 'test') { return } - const icon = - typeof type === 'string' && type in TOAST_TYPE_TO_ICON - ? TOAST_TYPE_TO_ICON[type as ToastType] - : (type as FontAwesomeProps['icon']) - AccessibilityInfo.announceForAccessibility(message) const item = new RootSiblings( - item.destroy()} />, + item.destroy()} />, ) } function Toast({ message, - icon, + type, destroy, }: { message: string - icon: FontAwesomeProps['icon'] + type: ToastType destroy: () => void }) { const t = useTheme() @@ -72,6 +55,10 @@ function Toast({ const dismissSwipeTranslateY = useSharedValue(0) const [cardHeight, setCardHeight] = useState(0) + const toastStyles = getToastTypeStyles(t) + const colors = toastStyles[type] + const IconComponent = TOAST_TYPE_TO_ICON[type] + // for the exit animation to work on iOS the animated component // must not be the root component // so we need to wrap it in a view and unmount the toast ahead of time @@ -169,103 +156,58 @@ function Toast({ } }) - // Web-specific styles for better compatibility - const webContainerStyle = isWeb - ? { - position: 'absolute' as const, - top: topOffset, - left: 16, - right: 16, - zIndex: 9999, - pointerEvents: 'auto' as const, - } - : {} - - const webToastStyle = isWeb - ? { - backgroundColor: - t.name === 'dark' ? t.palette.contrast_25 : t.palette.white, - shadowColor: '#000', - shadowOffset: {width: 0, height: 10}, - shadowOpacity: 0.1, - shadowRadius: 15, - elevation: 10, - borderColor: t.palette.contrast_300, - borderWidth: 1, - borderRadius: 8, - minHeight: 60, - } - : {} - return ( {alive && ( - setCardHeight(evt.nativeEvent.layout.height)} - accessibilityRole="alert" - accessible={true} - accessibilityLabel={message} - accessibilityHint="" - onAccessibilityEscape={hideAndDestroyImmediately} - style={[ - a.flex_1, - isWeb - ? webToastStyle - : [ - t.name === 'dark' ? t.atoms.bg_contrast_25 : t.atoms.bg, - a.shadow_lg, - t.atoms.border_contrast_medium, - a.rounded_sm, - a.border, - ], - !isWeb && animatedStyle, - ]}> - - - - - - - - {message} - - + entering={FadeIn.duration(TOAST_ANIMATION_CONFIG.duration)} + exiting={FadeOut.duration(TOAST_ANIMATION_CONFIG.duration * 0.7)} + onLayout={evt => setCardHeight(evt.nativeEvent.layout.height)} + accessibilityRole="alert" + accessible={true} + accessibilityLabel={message} + accessibilityHint="" + onAccessibilityEscape={hideAndDestroyImmediately} + style={[ + a.flex_1, + {backgroundColor: colors.backgroundColor}, + a.shadow_sm, + {borderColor: colors.borderColor, borderWidth: 1}, + a.rounded_sm, + animatedStyle, + ]}> + + + + + + + + {message} + - - + + )} diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx index 949dce7ef..331a8b539 100644 --- a/src/view/com/util/Toast.web.tsx +++ b/src/view/com/util/Toast.web.tsx @@ -4,28 +4,19 @@ import {useEffect, useState} from 'react' import {Pressable, StyleSheet, Text, View} from 'react-native' +import {atoms as a, useTheme} from '#/alf' import { - FontAwesomeIcon, - type FontAwesomeIconStyle, - type Props as FontAwesomeProps, -} from '@fortawesome/react-native-fontawesome' -import {atoms as a, useBreakpoints, useTheme} from '#/alf' - -const DURATION = 60000 - -export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' - -const TOAST_TYPE_TO_ICON: Record = { - default: 'check', - success: 'check', - error: 'exclamation', - warning: 'circle-exclamation', - info: 'info', -} + type ToastType, + TOAST_TYPE_TO_ICON, + getToastTypeStyles, + getToastWebAnimationStyles, + TOAST_WEB_KEYFRAMES, +} from './Toast.style' + +const DURATION = 3500 interface ActiveToast { text: string - icon: FontAwesomeProps['icon'] type: ToastType } type GlobalSetActiveToast = (_activeToast: ActiveToast | undefined) => void @@ -40,50 +31,45 @@ let toastTimeout: NodeJS.Timeout | undefined type ToastContainerProps = {} export const ToastContainer: React.FC = ({}) => { const [activeToast, setActiveToast] = useState() + const [isExiting, setIsExiting] = useState(false) + useEffect(() => { globalSetActiveToast = (t: ActiveToast | undefined) => { - setActiveToast(t) + if (!t && activeToast) { + setIsExiting(true) + setTimeout(() => { + setActiveToast(t) + setIsExiting(false) + }, 200) + } else { + setActiveToast(t) + setIsExiting(false) + } } - }) + }, [activeToast]) - const t = useTheme() + useEffect(() => { + const styleId = 'toast-animations' + if (!document.getElementById(styleId)) { + const style = document.createElement('style') + style.id = styleId + style.textContent = TOAST_WEB_KEYFRAMES + document.head.appendChild(style) + } + }, []) - const TOAST_TYPE_TO_STYLES = { - default: { - backgroundColor: t.atoms.text_contrast_low.color, - borderColor: t.atoms.border_contrast_medium.borderColor, - iconColor: '#fff', - textColor: '#fff', - }, - success: { - backgroundColor: '#059669', - borderColor: '#047857', - iconColor: '#fff', - textColor: '#fff', - }, - error: { - backgroundColor: t.palette.negative_100, - borderColor: t.palette.negative_400, - iconColor: t.palette.negative_600, - textColor: t.palette.negative_600, - }, - warning: { - backgroundColor: t.palette.negative_500, - borderColor: t.palette.negative_600, - iconColor: '#fff', - textColor: '#fff', - }, - info: { - backgroundColor: t.atoms.text_contrast_low.color, - borderColor: t.atoms.border_contrast_medium.borderColor, - iconColor: '#fff', - textColor: '#fff', - }, - } + const t = useTheme() + const toastTypeStyles = getToastTypeStyles(t) const toastStyles = activeToast - ? TOAST_TYPE_TO_STYLES[activeToast.type] - : TOAST_TYPE_TO_STYLES.default + ? toastTypeStyles[activeToast.type] + : toastTypeStyles.default + + const IconComponent = activeToast + ? TOAST_TYPE_TO_ICON[activeToast.type] + : TOAST_TYPE_TO_ICON.default + + const animationStyles = getToastWebAnimationStyles() return ( <> @@ -94,18 +80,24 @@ export const ToastContainer: React.FC = ({}) => { { backgroundColor: toastStyles.backgroundColor, borderColor: toastStyles.borderColor, + ...(isExiting + ? animationStyles.exiting + : animationStyles.entering), }, ]}> - + + + = ({}) => { // methods // = -export function show( - text: string, - type: ToastType | FontAwesomeProps['icon'] = 'default', -) { +export function show(text: string, type: ToastType = 'default') { if (toastTimeout) { clearTimeout(toastTimeout) } - // Determine if type is a semantic type or direct icon - const isSemanticType = typeof type === 'string' && type in TOAST_TYPE_TO_ICON - const icon = isSemanticType - ? TOAST_TYPE_TO_ICON[type as ToastType] - : (type as FontAwesomeProps['icon']) - const toastType = isSemanticType ? (type as ToastType) : 'default' - - globalSetActiveToast?.({text, icon, type: toastType}) + globalSetActiveToast?.({text, type}) toastTimeout = setTimeout(() => { globalSetActiveToast?.(undefined) }, DURATION) @@ -161,10 +143,10 @@ const styles = StyleSheet.create({ bottom: 20, // @ts-ignore web only width: 'calc(100% - 40px)', - maxWidth: 350, + maxWidth: 380, padding: 20, flexDirection: 'row', - alignItems: 'center', + alignItems: 'flex-start', borderRadius: 10, borderWidth: 1, }, @@ -175,6 +157,14 @@ const styles = StyleSheet.create({ bottom: 0, right: 0, }, + iconContainer: { + width: 32, + height: 32, + borderRadius: 16, + alignItems: 'center', + justifyContent: 'center', + flexShrink: 0, + }, icon: { flexShrink: 0, }, diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx index 714afdfbd..5197ec2f4 100644 --- a/src/view/screens/Storybook/Toasts.tsx +++ b/src/view/screens/Storybook/Toasts.tsx @@ -1,68 +1,99 @@ -import {View} from 'react-native' +import {View, Pressable} from 'react-native' -import {atoms as a} from '#/alf' -import {Button, ButtonText} from '#/components/Button' -import {H1} from '#/components/Typography' +import {atoms as a, useTheme} from '#/alf' +import {Text, H1} from '#/components/Typography' +import { + type ToastType, + TOAST_TYPE_TO_ICON, + getToastTypeStyles, +} from '#/view/com/util/Toast.style' import * as Toast from '#/view/com/util/Toast' -import * as ToastHelpers from '#/view/com/util/ToastHelpers' + +function ToastPreview({message, type}: {message: string; type: ToastType}) { + const t = useTheme() + const toastStyles = getToastTypeStyles(t) + const colors = toastStyles[type] + const IconComponent = TOAST_TYPE_TO_ICON[type] + + return ( + Toast.show(message, type)} + style={[ + {backgroundColor: colors.backgroundColor}, + a.shadow_sm, + {borderColor: colors.borderColor}, + a.rounded_sm, + a.border, + a.px_sm, + a.py_sm, + a.flex_row, + a.gap_sm, + a.align_center, + ]}> + + + + + + {message} + + + + ) +} export function Toasts() { return ( -

Toasts

+

Toast Examples

+ + + + + - - + + + - + + + - + + + - + + + - + + + ) -- cgit 1.4.1 From 61969e8dfa92fb200b83f13f691093ccaab2a031 Mon Sep 17 00:00:00 2001 From: Ana Date: Tue, 29 Jul 2025 23:28:10 -0700 Subject: add: Toast.style --- src/view/com/util/Toast.style.tsx | 167 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/view/com/util/Toast.style.tsx (limited to 'src') diff --git a/src/view/com/util/Toast.style.tsx b/src/view/com/util/Toast.style.tsx new file mode 100644 index 000000000..9a7e6b82d --- /dev/null +++ b/src/view/com/util/Toast.style.tsx @@ -0,0 +1,167 @@ +import {type Theme, select} from '#/alf' +import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' +import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' +import {Check_Stroke2_Corner0_Rounded as SuccessIcon} from '#/components/icons/Check' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' + +export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' + +export const TOAST_ANIMATION_CONFIG = { + duration: 300, + damping: 15, + stiffness: 150, + mass: 0.8, + overshootClamping: false, + restSpeedThreshold: 0.01, + restDisplacementThreshold: 0.01, +} + +export const TOAST_TYPE_TO_ICON = { + default: SuccessIcon, + success: SuccessIcon, + error: ErrorIcon, + warning: WarningIcon, + info: CircleInfo, +} + +export const getToastTypeStyles = (t: Theme) => ({ + default: { + backgroundColor: select(t.name, { + light: t.atoms.bg_contrast_25.backgroundColor, + dim: t.atoms.bg_contrast_100.backgroundColor, + dark: t.atoms.bg_contrast_100.backgroundColor, + }), + borderColor: select(t.name, { + light: t.atoms.border_contrast_low.borderColor, + dim: t.atoms.border_contrast_high.borderColor, + dark: t.atoms.border_contrast_high.borderColor, + }), + iconColor: select(t.name, { + light: t.atoms.text_contrast_medium.color, + dim: t.atoms.text_contrast_medium.color, + dark: t.atoms.text_contrast_medium.color, + }), + textColor: select(t.name, { + light: t.atoms.text_contrast_medium.color, + dim: t.atoms.text_contrast_medium.color, + dark: t.atoms.text_contrast_medium.color, + }), + }, + success: { + backgroundColor: select(t.name, { + light: t.palette.primary_100, + dim: t.palette.primary_100, + dark: t.palette.primary_50, + }), + borderColor: select(t.name, { + light: t.palette.primary_500, + dim: t.palette.primary_500, + dark: t.palette.primary_500, + }), + iconColor: select(t.name, { + light: t.palette.primary_500, + dim: t.palette.primary_600, + dark: t.palette.primary_600, + }), + textColor: select(t.name, { + light: t.palette.primary_500, + dim: t.palette.primary_600, + dark: t.palette.primary_600, + }), + }, + error: { + backgroundColor: select(t.name, { + light: t.palette.negative_200, + dim: t.palette.negative_25, + dark: t.palette.negative_25, + }), + borderColor: select(t.name, { + light: t.palette.negative_300, + dim: t.palette.negative_300, + dark: t.palette.negative_300, + }), + iconColor: select(t.name, { + light: t.palette.negative_600, + dim: t.palette.negative_600, + dark: t.palette.negative_600, + }), + textColor: select(t.name, { + light: t.palette.negative_600, + dim: t.palette.negative_600, + dark: t.palette.negative_600, + }), + }, + warning: { + backgroundColor: select(t.name, { + light: t.atoms.bg_contrast_25.backgroundColor, + dim: t.atoms.bg_contrast_100.backgroundColor, + dark: t.atoms.bg_contrast_100.backgroundColor, + }), + borderColor: select(t.name, { + light: t.atoms.border_contrast_low.borderColor, + dim: t.atoms.border_contrast_high.borderColor, + dark: t.atoms.border_contrast_high.borderColor, + }), + iconColor: select(t.name, { + light: t.atoms.text_contrast_medium.color, + dim: t.atoms.text_contrast_medium.color, + dark: t.atoms.text_contrast_medium.color, + }), + textColor: select(t.name, { + light: t.atoms.text_contrast_medium.color, + dim: t.atoms.text_contrast_medium.color, + dark: t.atoms.text_contrast_medium.color, + }), + }, + info: { + backgroundColor: select(t.name, { + light: t.atoms.bg_contrast_25.backgroundColor, + dim: t.atoms.bg_contrast_100.backgroundColor, + dark: t.atoms.bg_contrast_100.backgroundColor, + }), + borderColor: select(t.name, { + light: t.atoms.border_contrast_low.borderColor, + dim: t.atoms.border_contrast_high.borderColor, + dark: t.atoms.border_contrast_high.borderColor, + }), + iconColor: select(t.name, { + light: t.atoms.text_contrast_medium.color, + dim: t.atoms.text_contrast_medium.color, + dark: t.atoms.text_contrast_medium.color, + }), + textColor: select(t.name, { + light: t.atoms.text_contrast_medium.color, + dim: t.atoms.text_contrast_medium.color, + dark: t.atoms.text_contrast_medium.color, + }), + }, +}) + +export const getToastWebAnimationStyles = () => ({ + entering: { + animation: 'toastFadeIn 0.3s ease-out forwards', + }, + exiting: { + animation: 'toastFadeOut 0.2s ease-in forwards', + }, +}) + +export const TOAST_WEB_KEYFRAMES = ` + @keyframes toastFadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + @keyframes toastFadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } + } +` -- cgit 1.4.1 From 67ba92fa624f8edb2878fe65ac19439dff042c29 Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 30 Jul 2025 00:02:03 -0700 Subject: update: imports for toast --- src/view/com/util/Toast.tsx | 2 +- src/view/com/util/Toast.web.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index 2f8888bef..9c20e56be 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -25,7 +25,7 @@ import { TOAST_TYPE_TO_ICON, getToastTypeStyles, TOAST_ANIMATION_CONFIG, -} from './Toast.style' +} from '#/view/com/util/Toast.style' const TIMEOUT = 2e3 diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx index 331a8b539..fbe31528e 100644 --- a/src/view/com/util/Toast.web.tsx +++ b/src/view/com/util/Toast.web.tsx @@ -11,7 +11,7 @@ import { getToastTypeStyles, getToastWebAnimationStyles, TOAST_WEB_KEYFRAMES, -} from './Toast.style' +} from '#/view/com/util/Toast.style' const DURATION = 3500 @@ -146,7 +146,7 @@ const styles = StyleSheet.create({ maxWidth: 380, padding: 20, flexDirection: 'row', - alignItems: 'flex-start', + alignItems: 'center', borderRadius: 10, borderWidth: 1, }, -- cgit 1.4.1 From f472c7f540840df7d98af22719742944e70ccfa2 Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 30 Jul 2025 00:14:28 -0700 Subject: update sorting --- src/view/com/util/Toast.style.tsx | 6 +++--- src/view/com/util/Toast.tsx | 18 +++++++++--------- src/view/com/util/Toast.web.tsx | 7 ++++--- src/view/screens/Storybook/Toasts.tsx | 14 +++++++------- 4 files changed, 23 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Toast.style.tsx b/src/view/com/util/Toast.style.tsx index 9a7e6b82d..6bfb12bc1 100644 --- a/src/view/com/util/Toast.style.tsx +++ b/src/view/com/util/Toast.style.tsx @@ -1,8 +1,8 @@ -import {type Theme, select} from '#/alf' -import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' -import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' import {Check_Stroke2_Corner0_Rounded as SuccessIcon} from '#/components/icons/Check' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' +import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' +import {type Theme, select} from '#/alf' +import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index 9c20e56be..6fe04f793 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -1,3 +1,12 @@ +import {atoms as a, useTheme} from '#/alf' +import {Text} from '#/components/Typography' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' +import { + type ToastType, + getToastTypeStyles, + TOAST_ANIMATION_CONFIG, + TOAST_TYPE_TO_ICON, +} from '#/view/com/util/Toast.style' import {useEffect, useMemo, useRef, useState} from 'react' import {AccessibilityInfo, View} from 'react-native' import { @@ -17,15 +26,6 @@ import Animated, { } from 'react-native-reanimated' import RootSiblings from 'react-native-root-siblings' import {useSafeAreaInsets} from 'react-native-safe-area-context' -import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' -import {atoms as a, useTheme} from '#/alf' -import {Text} from '#/components/Typography' -import { - type ToastType, - TOAST_TYPE_TO_ICON, - getToastTypeStyles, - TOAST_ANIMATION_CONFIG, -} from '#/view/com/util/Toast.style' const TIMEOUT = 2e3 diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx index fbe31528e..9ed1f0397 100644 --- a/src/view/com/util/Toast.web.tsx +++ b/src/view/com/util/Toast.web.tsx @@ -4,14 +4,15 @@ import {useEffect, useState} from 'react' import {Pressable, StyleSheet, Text, View} from 'react-native' -import {atoms as a, useTheme} from '#/alf' + import { - type ToastType, - TOAST_TYPE_TO_ICON, getToastTypeStyles, getToastWebAnimationStyles, + TOAST_TYPE_TO_ICON, TOAST_WEB_KEYFRAMES, + type ToastType, } from '#/view/com/util/Toast.style' +import {atoms as a, useTheme} from '#/alf' const DURATION = 3500 diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx index 5197ec2f4..da0f1c416 100644 --- a/src/view/screens/Storybook/Toasts.tsx +++ b/src/view/screens/Storybook/Toasts.tsx @@ -1,13 +1,13 @@ -import {View, Pressable} from 'react-native' +import {Pressable,View} from 'react-native' -import {atoms as a, useTheme} from '#/alf' -import {Text, H1} from '#/components/Typography' +import * as Toast from '#/view/com/util/Toast' import { - type ToastType, - TOAST_TYPE_TO_ICON, getToastTypeStyles, + TOAST_TYPE_TO_ICON, + type ToastType, } from '#/view/com/util/Toast.style' -import * as Toast from '#/view/com/util/Toast' +import {atoms as a, useTheme} from '#/alf' +import {H1,Text} from '#/components/Typography' function ToastPreview({message, type}: {message: string; type: ToastType}) { const t = useTheme() @@ -16,7 +16,7 @@ function ToastPreview({message, type}: {message: string; type: ToastType}) { const IconComponent = TOAST_TYPE_TO_ICON[type] return ( - Toast.show(message, type)} style={[ {backgroundColor: colors.backgroundColor}, -- cgit 1.4.1 From f8781270e5df1d3730192ac463331845af028b4b Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 30 Jul 2025 00:36:14 -0700 Subject: update: toast style after lint --- src/view/com/util/Toast.style.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/view/com/util/Toast.style.tsx b/src/view/com/util/Toast.style.tsx index 6bfb12bc1..dfa4f4fd6 100644 --- a/src/view/com/util/Toast.style.tsx +++ b/src/view/com/util/Toast.style.tsx @@ -1,7 +1,7 @@ +import {select, type Theme} from '#/alf' import {Check_Stroke2_Corner0_Rounded as SuccessIcon} from '#/components/icons/Check' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' -import {type Theme, select} from '#/alf' import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' -- cgit 1.4.1 From 315e7341bf99243bb0249567f62ca20d147e7b53 Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 30 Jul 2025 00:40:34 -0700 Subject: update: lint fixes for toast.tsx --- src/view/com/util/Toast.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index 6fe04f793..7258eac9d 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -1,12 +1,3 @@ -import {atoms as a, useTheme} from '#/alf' -import {Text} from '#/components/Typography' -import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' -import { - type ToastType, - getToastTypeStyles, - TOAST_ANIMATION_CONFIG, - TOAST_TYPE_TO_ICON, -} from '#/view/com/util/Toast.style' import {useEffect, useMemo, useRef, useState} from 'react' import {AccessibilityInfo, View} from 'react-native' import { @@ -27,6 +18,16 @@ import Animated, { import RootSiblings from 'react-native-root-siblings' import {useSafeAreaInsets} from 'react-native-safe-area-context' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' +import { + getToastTypeStyles, + TOAST_ANIMATION_CONFIG, + TOAST_TYPE_TO_ICON, + type ToastType, +} from '#/view/com/util/Toast.style' +import {atoms as a, useTheme} from '#/alf' +import {Text} from '#/components/Typography' + const TIMEOUT = 2e3 export function show(message: string, type: ToastType = 'default') { -- cgit 1.4.1 From d141921abf23d0694ce399615e70011492434e69 Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 30 Jul 2025 00:48:56 -0700 Subject: add: prettier formating --- src/view/screens/Storybook/Toasts.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx index da0f1c416..54735f7bb 100644 --- a/src/view/screens/Storybook/Toasts.tsx +++ b/src/view/screens/Storybook/Toasts.tsx @@ -1,4 +1,4 @@ -import {Pressable,View} from 'react-native' +import {Pressable, View} from 'react-native' import * as Toast from '#/view/com/util/Toast' import { @@ -7,7 +7,7 @@ import { type ToastType, } from '#/view/com/util/Toast.style' import {atoms as a, useTheme} from '#/alf' -import {H1,Text} from '#/components/Typography' +import {H1, Text} from '#/components/Typography' function ToastPreview({message, type}: {message: string; type: ToastType}) { const t = useTheme() @@ -16,7 +16,8 @@ function ToastPreview({message, type}: {message: string; type: ToastType}) { const IconComponent = TOAST_TYPE_TO_ICON[type] return ( - Toast.show(message, type)} style={[ {backgroundColor: colors.backgroundColor}, -- cgit 1.4.1 From 18add1cff9eb36568439d8ea80180c36c1a30260 Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 30 Jul 2025 01:08:14 -0700 Subject: update type errors --- src/view/com/util/Toast.style.tsx | 12 +++++++++++- src/view/com/util/Toast.tsx | 5 +++-- src/view/com/util/Toast.web.tsx | 4 ++-- src/view/screens/Storybook/Toasts.tsx | 5 +++-- 4 files changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Toast.style.tsx b/src/view/com/util/Toast.style.tsx index dfa4f4fd6..8b952fd00 100644 --- a/src/view/com/util/Toast.style.tsx +++ b/src/view/com/util/Toast.style.tsx @@ -4,7 +4,17 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' -export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' +export type ToastType = + | 'default' + | 'success' + | 'error' + | 'warning' + | 'info' + | 'xmark' + | 'exclamation-circle' + | 'check' + | 'clipboard-check' + | 'circle-exclamation' export const TOAST_ANIMATION_CONFIG = { duration: 300, diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index 7258eac9d..4c999ca2a 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -57,8 +57,9 @@ function Toast({ const [cardHeight, setCardHeight] = useState(0) const toastStyles = getToastTypeStyles(t) - const colors = toastStyles[type] - const IconComponent = TOAST_TYPE_TO_ICON[type] + const colors = toastStyles[type as keyof typeof toastStyles] + const IconComponent = + TOAST_TYPE_TO_ICON[type as keyof typeof TOAST_TYPE_TO_ICON] // for the exit animation to work on iOS the animated component // must not be the root component diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx index 9ed1f0397..1abbaa003 100644 --- a/src/view/com/util/Toast.web.tsx +++ b/src/view/com/util/Toast.web.tsx @@ -63,11 +63,11 @@ export const ToastContainer: React.FC = ({}) => { const toastTypeStyles = getToastTypeStyles(t) const toastStyles = activeToast - ? toastTypeStyles[activeToast.type] + ? toastTypeStyles[activeToast.type as keyof typeof toastTypeStyles] : toastTypeStyles.default const IconComponent = activeToast - ? TOAST_TYPE_TO_ICON[activeToast.type] + ? TOAST_TYPE_TO_ICON[activeToast.type as keyof typeof TOAST_TYPE_TO_ICON] : TOAST_TYPE_TO_ICON.default const animationStyles = getToastWebAnimationStyles() diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx index 54735f7bb..4c17f1c33 100644 --- a/src/view/screens/Storybook/Toasts.tsx +++ b/src/view/screens/Storybook/Toasts.tsx @@ -12,8 +12,9 @@ import {H1, Text} from '#/components/Typography' function ToastPreview({message, type}: {message: string; type: ToastType}) { const t = useTheme() const toastStyles = getToastTypeStyles(t) - const colors = toastStyles[type] - const IconComponent = TOAST_TYPE_TO_ICON[type] + const colors = toastStyles[type as keyof typeof toastStyles] + const IconComponent = + TOAST_TYPE_TO_ICON[type as keyof typeof TOAST_TYPE_TO_ICON] return ( Date: Wed, 30 Jul 2025 18:17:57 +0300 Subject: Fix dataSet for noFeedback links (#8745) * fix dataSet for noFeedback links * rm memo * rm useless spread --- src/view/com/util/Link.tsx | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index 6a931d9a4..496b77182 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -101,13 +101,9 @@ export const Link = memo(function Link({ {name: 'activate', label: title}, ] - const dataSet = useMemo(() => { - const ds = {...dataSetProp} - if (anchorNoUnderline) { - ds.noUnderline = 1 - } - return ds - }, [dataSetProp, anchorNoUnderline]) + const dataSet = anchorNoUnderline + ? {...dataSetProp, noUnderline: 1} + : dataSetProp if (noFeedback) { return ( @@ -125,6 +121,8 @@ export const Link = memo(function Link({ onAccessibilityAction?.(e) } }} + // @ts-ignore web only -sfn + dataSet={dataSet} {...props} android_ripple={{ color: t.atoms.bg_contrast_25.backgroundColor, @@ -198,13 +196,9 @@ export const TextLink = memo(function TextLink({ console.error('Unable to detect mismatching label') } - const dataSet = useMemo(() => { - const ds = {...dataSetProp} - if (anchorNoUnderline) { - ds.noUnderline = 1 - } - return ds - }, [dataSetProp, anchorNoUnderline]) + const dataSet = anchorNoUnderline + ? {...dataSetProp, noUnderline: 1} + : dataSetProp const onPress = useCallback( (e?: Event) => { -- cgit 1.4.1 From db7bdae51a1a06e67856b887e4e63a183fa5f479 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Wed, 30 Jul 2025 18:18:36 +0300 Subject: Convert old toast types to new ones, mark as deprecated (#8746) * convert old types to new types * add depreciation warning for old warnings * rm as consts --- src/view/com/util/Toast.style.tsx | 38 +++++++++++++++++++++++++++++++------- src/view/com/util/Toast.tsx | 27 ++++++++++++++++++++++----- src/view/com/util/Toast.web.tsx | 13 +++++++++---- 3 files changed, 62 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/view/com/util/Toast.style.tsx b/src/view/com/util/Toast.style.tsx index 8b952fd00..3869e6890 100644 --- a/src/view/com/util/Toast.style.tsx +++ b/src/view/com/util/Toast.style.tsx @@ -4,18 +4,42 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' -export type ToastType = - | 'default' - | 'success' - | 'error' - | 'warning' - | 'info' +export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' + +export type LegacyToastType = | 'xmark' | 'exclamation-circle' | 'check' | 'clipboard-check' | 'circle-exclamation' +export const convertLegacyToastType = ( + type: ToastType | LegacyToastType, +): ToastType => { + switch (type) { + // these ones are fine + case 'default': + case 'success': + case 'error': + case 'warning': + case 'info': + return type + // legacy ones need conversion + case 'xmark': + return 'error' + case 'exclamation-circle': + return 'warning' + case 'check': + return 'success' + case 'clipboard-check': + return 'success' + case 'circle-exclamation': + return 'warning' + default: + return 'default' + } +} + export const TOAST_ANIMATION_CONFIG = { duration: 300, damping: 15, @@ -165,7 +189,7 @@ export const TOAST_WEB_KEYFRAMES = ` opacity: 1; } } - + @keyframes toastFadeOut { from { opacity: 1; diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index 4c999ca2a..54ef7042d 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -20,7 +20,9 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import { + convertLegacyToastType, getToastTypeStyles, + type LegacyToastType, TOAST_ANIMATION_CONFIG, TOAST_TYPE_TO_ICON, type ToastType, @@ -30,14 +32,30 @@ import {Text} from '#/components/Typography' const TIMEOUT = 2e3 -export function show(message: string, type: ToastType = 'default') { +// Use type overloading to mark certain types as deprecated -sfn +// https://stackoverflow.com/a/78325851/13325987 +export function show(message: string, type?: ToastType): void +/** + * @deprecated type is deprecated - use one of `'default' | 'success' | 'error' | 'warning' | 'info'` + */ +export function show(message: string, type?: LegacyToastType): void +export function show( + message: string, + type: ToastType | LegacyToastType = 'default', +): void { if (process.env.NODE_ENV === 'test') { return } AccessibilityInfo.announceForAccessibility(message) const item = new RootSiblings( - item.destroy()} />, + ( + item.destroy()} + /> + ), ) } @@ -57,9 +75,8 @@ function Toast({ const [cardHeight, setCardHeight] = useState(0) const toastStyles = getToastTypeStyles(t) - const colors = toastStyles[type as keyof typeof toastStyles] - const IconComponent = - TOAST_TYPE_TO_ICON[type as keyof typeof TOAST_TYPE_TO_ICON] + const colors = toastStyles[type] + const IconComponent = TOAST_TYPE_TO_ICON[type] // for the exit animation to work on iOS the animated component // must not be the root component diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx index 1abbaa003..6b99b30bf 100644 --- a/src/view/com/util/Toast.web.tsx +++ b/src/view/com/util/Toast.web.tsx @@ -6,8 +6,10 @@ import {useEffect, useState} from 'react' import {Pressable, StyleSheet, Text, View} from 'react-native' import { + convertLegacyToastType, getToastTypeStyles, getToastWebAnimationStyles, + type LegacyToastType, TOAST_TYPE_TO_ICON, TOAST_WEB_KEYFRAMES, type ToastType, @@ -63,11 +65,11 @@ export const ToastContainer: React.FC = ({}) => { const toastTypeStyles = getToastTypeStyles(t) const toastStyles = activeToast - ? toastTypeStyles[activeToast.type as keyof typeof toastTypeStyles] + ? toastTypeStyles[activeToast.type] : toastTypeStyles.default const IconComponent = activeToast - ? TOAST_TYPE_TO_ICON[activeToast.type as keyof typeof TOAST_TYPE_TO_ICON] + ? TOAST_TYPE_TO_ICON[activeToast.type] : TOAST_TYPE_TO_ICON.default const animationStyles = getToastWebAnimationStyles() @@ -125,12 +127,15 @@ export const ToastContainer: React.FC = ({}) => { // methods // = -export function show(text: string, type: ToastType = 'default') { +export function show( + text: string, + type: ToastType | LegacyToastType = 'default', +) { if (toastTimeout) { clearTimeout(toastTimeout) } - globalSetActiveToast?.({text, type}) + globalSetActiveToast?.({text, type: convertLegacyToastType(type)}) toastTimeout = setTimeout(() => { globalSetActiveToast?.(undefined) }, DURATION) -- cgit 1.4.1 From d4b23d3ab4e8448321fecc7bd46b6531ada80348 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 30 Jul 2025 12:33:40 -0500 Subject: [APP-1173] Clean up env (#8701) * Clean up env files * Use new env in Sentry setup file * Use new env in Bitdrift setup file * Use new env in chat proxy header * Prefix Bitdrift key with EXPO_PUBLIC * Deprecate SENTRY_RELEASE since we use package.json now * Use existing EXPO_PUBLIC_BUNDLE_IDENTIFIER short commit has as Sentry dist value * Fix missing bundle identifier for Render deploys * Deprecate SENTRY_DIST in favor of EXPO_PUBLIC_BUNDLE_IDENTIFIER * Prefix SENTRY_DSN with EXPO_PUBLIC to match others * Remove debugging field * Replace NODE_ENV in places where its safe * Self review * Properly patch Sentry package * Echo variables to .env in Dockerfile instead of passing to shell script * Make sure EXPO_PUBLIC_ENV is set for web container builds * Update IS_TESTFLIGHT to include testflight-android * Slice bundle hash to match other platforms, needed for render.com deployments * [APP-1331] Migrate `app-info` to new env (#8703) * Move env files into directory with platform specific files * Migrate usages of app-info to new env * Fix bad import * Update BUNDLE_DATE format comment * Trim RENDER_GIT_COMMIT to first 7 to match --short sha * Clarify build process env vars and ensure they are explicitly passed in * Revert Sentry patch as a result of prev commit * Update webpack Sentry dist value based on prev commits * Add PACKAGE_VERSION and replace in statsig to fix conflict * Fix render substitution syntax * Remove invalid syntax * Remove unnecessary testflight check * Just use long commit hash * Slice full hash for display in app * Fix missing space in ios workflow * Pass in sentry CLI env vars, align matching values * Align on RELEASE_VERSION * Add new env setup to missed OTA spot * Update webpack to use same SENTRY_RELEASE var * Just fallback to package version for Render deploys * Remove TF check for BUNDLE_DATE * Set EXPO_PUBLIC_ENV for bundle update * Consistent naming "Env" * Add comment * Use RELEASE_VERSION instead of package.json * Update PR comment CI --- .env.example | 34 ++++++++-- .github/workflows/build-and-push-bskyweb-aws.yaml | 17 +++-- .github/workflows/build-submit-android.yml | 36 +++++++--- .github/workflows/build-submit-ios.yml | 25 ++++--- .github/workflows/bundle-deploy-eas-update.yml | 67 +++++++++++++----- .github/workflows/pull-request-comment.yml | 24 ++++--- Dockerfile | 29 ++++---- docs/build.md | 4 +- src/components/PostControls/DiscoverDebug.tsx | 2 +- .../PostControls/PostMenu/PostMenuItems.tsx | 2 +- src/env.ts | 6 -- src/env/common.ts | 79 ++++++++++++++++++++++ src/env/index.ts | 19 ++++++ src/env/index.web.ts | 15 ++++ src/lib/app-info.ts | 18 ----- src/lib/app-info.web.ts | 18 ----- src/lib/hooks/useOTAUpdates.ts | 2 +- src/lib/statsig/statsig.tsx | 20 +++--- src/logger/bitdrift/setup/index.ts | 3 +- src/logger/index.ts | 3 +- src/logger/sentry/setup/index.ts | 29 ++------ src/screens/Settings/AboutSettings.tsx | 10 +-- src/screens/Settings/AppIconSettings/index.tsx | 8 +-- src/screens/Settings/AppearanceSettings.tsx | 2 +- src/screens/Settings/Settings.tsx | 2 +- src/state/queries/messages/const.ts | 4 +- src/state/session/logging.ts | 10 +-- webpack.config.js | 2 +- 28 files changed, 313 insertions(+), 177 deletions(-) delete mode 100644 src/env.ts create mode 100644 src/env/common.ts create mode 100644 src/env/index.ts create mode 100644 src/env/index.web.ts delete mode 100644 src/lib/app-info.ts delete mode 100644 src/lib/app-info.web.ts (limited to 'src') diff --git a/.env.example b/.env.example index a4d21ac33..e18cda4e5 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,32 @@ -# Copy this to `.env` and `.env.test` files +# The env the app is running in e.g. development, testflight, production +EXPO_PUBLIC_ENV=development -BITDRIFT_API_KEY= -SENTRY_AUTH_TOKEN= -EXPO_PUBLIC_LOG_LEVEL=debug -EXPO_PUBLIC_LOG_DEBUG= +# This is the semver release version of the app, pulled from package.json +EXPO_PUBLIC_RELEASE_VERSION= + +# This is the commit hash that the current bundle was made from. EXPO_PUBLIC_BUNDLE_IDENTIFIER= + +# Should be formatted YYMMDDHH so that it increases for each build. EXPO_PUBLIC_BUNDLE_DATE=0 + +# The log level for the app's logger transports +EXPO_PUBLIC_LOG_LEVEL=debug + +# Enable debug logs for specific logger instances +EXPO_PUBLIC_LOG_DEBUG=session + +# Chat service DID +EXPO_PUBLIC_CHAT_PROXY_DID= + +# +# +# Bluesky specific values +# +# + +# Sentry DSN for telemetry +EXPO_PUBLIC_SENTRY_DSN= + +# Bitdrift API key. If undefined, Bitdrift will be disabled. +EXPO_PUBLIC_BITDRIFT_API_KEY= diff --git a/.github/workflows/build-and-push-bskyweb-aws.yaml b/.github/workflows/build-and-push-bskyweb-aws.yaml index 399e8669f..6d573b0f7 100644 --- a/.github/workflows/build-and-push-bskyweb-aws.yaml +++ b/.github/workflows/build-and-push-bskyweb-aws.yaml @@ -43,12 +43,11 @@ jobs: tags: | type=sha,enable=true,priority=100,prefix=,suffix=,format=long - - name: Set outputs - id: vars + - name: Env + id: env run: | - echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - name: Build and push Docker image id: build-and-push @@ -62,8 +61,8 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max build-args: | - EXPO_PUBLIC_BUNDLE_IDENTIFIER=${{ steps.vars.outputs.sha_short }} - SENTRY_DIST=${{ steps.vars.outputs.SENTRY_DIST }} - SENTRY_RELEASE=${{ steps.vars.outputs.SENTRY_RELEASE }} + EXPO_PUBLIC_ENV=production + EXPO_PUBLIC_RELEASE_VERSION=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + EXPO_PUBLIC_BUNDLE_IDENTIFIER=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} - SENTRY_DSN=${{ secrets.SENTRY_DSN }} diff --git a/.github/workflows/build-submit-android.yml b/.github/workflows/build-submit-android.yml index e862a701f..f1e75f87e 100644 --- a/.github/workflows/build-submit-android.yml +++ b/.github/workflows/build-submit-android.yml @@ -62,23 +62,30 @@ jobs: - name: Check for i18n compilation errors run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi - - name: ✏️ Write environment variables + # EXPO_PUBLIC_ENV is handled in eas.json + - name: Env + id: env run: | export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}' echo "${{ secrets.ENV_TOKEN }}" > .env - echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env - echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env + echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env + echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env echo "$json" > google-services.json - - name: Setup Sentry vars for build-time injection - id: sentry - run: | - echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT - - name: 🏗️ EAS Build - run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p android --profile ${{ inputs.profile || 'testflight-android' }} --local --output build.aab --non-interactive + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn use-build-number-with-bump + eas build -p android + --profile ${{ inputs.profile || 'testflight-android' }} + --local --output build.aab --non-interactive - name: ✍️ Rename Testflight bundle if: ${{ inputs.profile != 'production' }} @@ -140,7 +147,14 @@ jobs: - name: 🏗️ Build Production APK if: ${{ inputs.profile == 'production' }} - run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p android --profile production-apk --local --output build.apk --non-interactive + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn use-build-number-with-bump + eas build -p android + --profile production-apk + --local --output build.apk --non-interactive - name: 🚀 Upload Production APK Artifact id: upload-artifact-production-apk diff --git a/.github/workflows/build-submit-ios.yml b/.github/workflows/build-submit-ios.yml index a197695db..f3759d0dd 100644 --- a/.github/workflows/build-submit-ios.yml +++ b/.github/workflows/build-submit-ios.yml @@ -75,22 +75,29 @@ jobs: - name: Check for i18n compilation errors run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi + # EXPO_PUBLIC_ENV is handled in eas.json - name: ✏️ Write environment variables + id: env run: | echo "${{ secrets.ENV_TOKEN }}" > .env - echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env - echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env + echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env + echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json - - name: Setup Sentry vars for build-time injection - id: sentry - run: | - echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT - - name: 🏗️ EAS Build - run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p ios --profile ${{ inputs.profile || 'testflight' }} --local --output build.ipa --non-interactive + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn use-build-number-with-bump + eas build -p ios + --profile ${{ inputs.profile || 'testflight' }} + --local --output build.ipa --non-interactive - name: 🚀 Deploy run: eas submit -p ios --non-interactive --path build.ipa diff --git a/.github/workflows/bundle-deploy-eas-update.yml b/.github/workflows/bundle-deploy-eas-update.yml index 475bc087f..1bd0b71c4 100644 --- a/.github/workflows/bundle-deploy-eas-update.yml +++ b/.github/workflows/bundle-deploy-eas-update.yml @@ -101,25 +101,30 @@ jobs: if: ${{ !steps.fingerprint.outputs.includes-changes }} uses: dcarbone/install-jq-action@v2 - - name: ✏️ Write environment variables + # eas.json not used here, set EXPO_PUBLIC_ENV + - name: Env + id: env if: ${{ !steps.fingerprint.outputs.includes-changes }} run: | export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}' echo "${{ secrets.ENV_TOKEN }}" > .env - echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env + echo "EXPO_PUBLIC_ENV=${{ inputs.channel || 'testflight' }}" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env - echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env + echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env + echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env echo "$json" > google-services.json - - name: Setup Sentry vars for build-time injection - id: sentry - run: | - echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT - - name: 🏗️ Create Bundle if: ${{ !steps.fingerprint.outputs.includes-changes }} - run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn export - name: 📦 Package Bundle and 🚀 Deploy if: ${{ !steps.fingerprint.outputs.includes-changes }} @@ -205,16 +210,29 @@ jobs: - name: 🔤 Compile translations run: yarn intl:build - - name: ✏️ Write environment variables + # EXPO_PUBLIC_ENV is handled in eas.json + - name: Env + id: env run: | echo "${{ secrets.ENV_TOKEN }}" > .env - echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env - echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env + echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env + echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json - name: 🏗️ EAS Build - run: yarn use-build-number-with-bump eas build -p ios --profile testflight --local --output build.ipa --non-interactive + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn use-build-number-with-bump + eas build -p ios + --profile testflight + --local --output build.ipa --non-interactive - name: 🚀 Deploy run: eas submit -p ios --non-interactive --path build.ipa @@ -282,17 +300,30 @@ jobs: - name: 🔤 Compile translations run: yarn intl:build - - name: ✏️ Write environment variables + # EXPO_PUBLIC_ENV is handled in eas.json + - name: Env + id: env run: | export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}' echo "${{ secrets.ENV_TOKEN }}" > .env - echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env - echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env + echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env + echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env echo "$json" > google-services.json - name: 🏗️ EAS Build - run: yarn use-build-number-with-bump eas build -p android --profile testflight-android --local --output build.apk --non-interactive + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn use-build-number-with-bump + eas build -p android + --profile testflight-android + --local --output build.apk --non-interactive - name: ⏰ Get a timestamp id: timestamp diff --git a/.github/workflows/pull-request-comment.yml b/.github/workflows/pull-request-comment.yml index e40eff6c7..d04301002 100644 --- a/.github/workflows/pull-request-comment.yml +++ b/.github/workflows/pull-request-comment.yml @@ -152,23 +152,27 @@ jobs: - name: 🪛 Setup jq uses: dcarbone/install-jq-action@v2 - - name: ✏️ Write environment variables + - name: Env + id: env run: | export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}' echo "${{ secrets.ENV_TOKEN }}" > .env - echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env + echo "EXPO_PUBLIC_ENV=testflight" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env + echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env + echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env - echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env + echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env + echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env echo "$json" > google-services.json - - name: Setup Sentry vars for build-time injection - id: sentry - run: | - echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT - - name: 🏗️ Create Bundle - run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="testflight" yarn export + run: > + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }} + SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }} + yarn export - name: 📦 Package Bundle and 🚀 Deploy run: yarn use-build-number bash scripts/bundleUpdate.sh diff --git a/Dockerfile b/Dockerfile index 50dc28b4b..43d7f4eb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,28 +19,28 @@ ENV GOARCH="amd64" ENV CGO_ENABLED=1 ENV GOEXPERIMENT="loopvar" +# The latest git hash of the preview branch on render.com +# https://render.com/docs/docker-secrets#environment-variables-in-docker-builds +ARG RENDER_GIT_COMMIT + # # Expo # +ARG EXPO_PUBLIC_ENV +ENV EXPO_PUBLIC_ENV=${EXPO_PUBLIC_ENV:-development} +ARG EXPO_PUBLIC_RELEASE_VERSION +ENV EXPO_PUBLIC_RELEASE_VERSION=$EXPO_PUBLIC_RELEASE_VERSION ARG EXPO_PUBLIC_BUNDLE_IDENTIFIER -ENV EXPO_PUBLIC_BUNDLE_IDENTIFIER=${EXPO_PUBLIC_BUNDLE_IDENTIFIER:-dev} - -# The latest git hash of the preview branch on render.com -ARG RENDER_GIT_COMMIT +# If not set by GitHub workflows, we're probably in Render +ENV EXPO_PUBLIC_BUNDLE_IDENTIFIER=${EXPO_PUBLIC_BUNDLE_IDENTIFIER:-$RENDER_GIT_COMMIT} # # Sentry # ARG SENTRY_AUTH_TOKEN ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN:-unknown} -# Will fall back to package.json#version, but this is handled elsewhere -ARG SENTRY_RELEASE -ENV SENTRY_RELEASE=$SENTRY_RELEASE -ARG SENTRY_DIST -# Default to RENDER_GIT_COMMIT if not set by GitHub workflows -ENV SENTRY_DIST=${SENTRY_DIST:-$RENDER_GIT_COMMIT} -ARG SENTRY_DSN -ENV SENTRY_DSN=$SENTRY_DSN +ARG EXPO_PUBLIC_SENTRY_DSN +ENV EXPO_PUBLIC_SENTRY_DSN=$EXPO_PUBLIC_SENTRY_DSN # # Copy everything into the container @@ -60,13 +60,16 @@ RUN \. "$NVM_DIR/nvm.sh" && \ nvm install $NODE_VERSION && \ nvm use $NODE_VERSION && \ echo "Using bundle identifier: $EXPO_PUBLIC_BUNDLE_IDENTIFIER" && \ + echo "EXPO_PUBLIC_ENV=$EXPO_PUBLIC_ENV" >> .env && \ + echo "EXPO_PUBLIC_RELEASE_VERSION=$EXPO_PUBLIC_RELEASE_VERSION" >> .env && \ echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER" >> .env && \ echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env && \ + echo "EXPO_PUBLIC_SENTRY_DSN=$EXPO_PUBLIC_SENTRY_DSN" >> .env && \ npm install --global yarn && \ yarn && \ yarn intl:build 2>&1 | tee i18n.log && \ if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compile errors!\n\n"; fi && \ - EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER EXPO_PUBLIC_BUNDLE_DATE=$() SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN SENTRY_RELEASE=$SENTRY_RELEASE SENTRY_DIST=$SENTRY_DIST SENTRY_DSN=$SENTRY_DSN yarn build-web + SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN SENTRY_RELEASE=$EXPO_PUBLIC_RELEASE_VERSION SENTRY_DIST=$EXPO_PUBLIC_BUNDLE_IDENTIFIER yarn build-web # DEBUG RUN find ./bskyweb/static && find ./web-build/static diff --git a/docs/build.md b/docs/build.md index 7817dd095..87b653bdb 100644 --- a/docs/build.md +++ b/docs/build.md @@ -89,9 +89,9 @@ If you change `SENTRY_AUTH_TOKEN`, you need to do `yarn prebuild` before running ### Adding bitdrift -Adding bitdirft is NOT required. You can keep `BITDRIFT_API_KEY=` in `.env` which will avoid initializing bitdrift during startup. +Adding bitdrift is NOT required. You can keep `EXPO_PUBLIC_BITDRIFT_API_KEY=` in `.env` which will avoid initializing bitdrift during startup. -However, if you're a part of the Bluesky team and want to enable bitdrift, fill in `BITDRIFT_API_KEY` in your `.env` to enable bitdrift. +However, if you're a part of the Bluesky team and want to enable bitdrift, fill in `EXPO_PUBLIC_BITDRIFT_API_KEY` in your `.env` to enable bitdrift. ### Adding and Updating Locales diff --git a/src/components/PostControls/DiscoverDebug.tsx b/src/components/PostControls/DiscoverDebug.tsx index 796981f0c..403b50cca 100644 --- a/src/components/PostControls/DiscoverDebug.tsx +++ b/src/components/PostControls/DiscoverDebug.tsx @@ -2,13 +2,13 @@ import {Pressable} from 'react-native' import * as Clipboard from 'expo-clipboard' import {t} from '@lingui/macro' -import {IS_INTERNAL} from '#/lib/app-info' import {DISCOVER_DEBUG_DIDS} from '#/lib/constants' import {useGate} from '#/lib/statsig/statsig' import {useSession} from '#/state/session' import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {Text} from '#/components/Typography' +import {IS_INTERNAL} from '#/env' export function DiscoverDebug({ feedContext, diff --git a/src/components/PostControls/PostMenu/PostMenuItems.tsx b/src/components/PostControls/PostMenu/PostMenuItems.tsx index f0ef9ed05..ecc3d0174 100644 --- a/src/components/PostControls/PostMenu/PostMenuItems.tsx +++ b/src/components/PostControls/PostMenu/PostMenuItems.tsx @@ -17,7 +17,6 @@ import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' -import {IS_INTERNAL} from '#/lib/app-info' import {DISCOVER_DEBUG_DIDS} from '#/lib/constants' import {useOpenLink} from '#/lib/hooks/useOpenLink' import {getCurrentRoute} from '#/lib/routes/helpers' @@ -83,6 +82,7 @@ import { useReportDialogControl, } from '#/components/moderation/ReportDialog' import * as Prompt from '#/components/Prompt' +import {IS_INTERNAL} from '#/env' import * as bsky from '#/types/bsky' let PostMenuItems = ({ diff --git a/src/env.ts b/src/env.ts deleted file mode 100644 index 32ce70670..000000000 --- a/src/env.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const LOG_DEBUG = process.env.EXPO_PUBLIC_LOG_DEBUG || '' -export const LOG_LEVEL = (process.env.EXPO_PUBLIC_LOG_LEVEL || 'info') as - | 'debug' - | 'info' - | 'warn' - | 'error' diff --git a/src/env/common.ts b/src/env/common.ts new file mode 100644 index 000000000..e68e9fab8 --- /dev/null +++ b/src/env/common.ts @@ -0,0 +1,79 @@ +import {type Did} from '@atproto/api' + +import packageJson from '#/../package.json' + +/** + * The semver version of the app, as defined in `package.json.` + * + * N.B. The fallback is needed for Render.com deployments + */ +export const RELEASE_VERSION: string = + process.env.EXPO_PUBLIC_RELEASE_VERSION || packageJson.version + +/** + * The env the app is running in e.g. development, testflight, production + */ +export const ENV: string = process.env.EXPO_PUBLIC_ENV + +/** + * Indicates whether the app is running in TestFlight + */ +export const IS_TESTFLIGHT = ENV === 'testflight' + +/** + * Indicates whether the app is __DEV__ + */ +export const IS_DEV = __DEV__ + +/** + * Indicates whether the app is __DEV__ or TestFlight + */ +export const IS_INTERNAL = IS_DEV || IS_TESTFLIGHT + +/** + * The commit hash that the current bundle was made from. The user can + * see the commit hash in the app's settings along with the other version info. + * Useful for debugging/reporting. + */ +export const BUNDLE_IDENTIFIER: string = + process.env.EXPO_PUBLIC_BUNDLE_IDENTIFIER || 'dev' + +/** + * This will always be in the format of YYMMDDHH, so that it always increases + * for each build. This should only be used for StatSig reporting and shouldn't + * be used to identify a specific bundle. + */ +export const BUNDLE_DATE: number = !process.env.EXPO_PUBLIC_BUNDLE_DATE + ? 0 + : Number(process.env.EXPO_PUBLIC_BUNDLE_DATE) + +/** + * The log level for the app. + */ +export const LOG_LEVEL = (process.env.EXPO_PUBLIC_LOG_LEVEL || 'info') as + | 'debug' + | 'info' + | 'warn' + | 'error' + +/** + * Enable debug logs for specific logger instances + */ +export const LOG_DEBUG: string = process.env.EXPO_PUBLIC_LOG_DEBUG || '' + +/** + * The DID of the chat service to proxy to + */ +export const CHAT_PROXY_DID: Did = + process.env.EXPO_PUBLIC_CHAT_PROXY_DID || 'did:web:api.bsky.chat' + +/** + * Sentry DSN for telemetry + */ +export const SENTRY_DSN: string | undefined = process.env.EXPO_PUBLIC_SENTRY_DSN + +/** + * Bitdrift API key. If undefined, Bitdrift should be disabled. + */ +export const BITDRIFT_API_KEY: string | undefined = + process.env.EXPO_PUBLIC_BITDRIFT_API_KEY diff --git a/src/env/index.ts b/src/env/index.ts new file mode 100644 index 000000000..8558c55b5 --- /dev/null +++ b/src/env/index.ts @@ -0,0 +1,19 @@ +import {nativeBuildVersion} from 'expo-application' + +import {BUNDLE_IDENTIFIER, IS_TESTFLIGHT, RELEASE_VERSION} from '#/env/common' + +export * from '#/env/common' + +/** + * The semver version of the app, specified in our `package.json`.file. On + * iOs/Android, the native build version is appended to the semver version, so + * that it can be used to identify a specific build. + */ +export const APP_VERSION = `${RELEASE_VERSION}.${nativeBuildVersion}` + +/** + * The short commit hash and environment of the current bundle. + */ +export const APP_METADATA = `${BUNDLE_IDENTIFIER.slice(0, 7)} (${ + __DEV__ ? 'dev' : IS_TESTFLIGHT ? 'tf' : 'prod' +})` diff --git a/src/env/index.web.ts b/src/env/index.web.ts new file mode 100644 index 000000000..66087749b --- /dev/null +++ b/src/env/index.web.ts @@ -0,0 +1,15 @@ +import {BUNDLE_IDENTIFIER, RELEASE_VERSION} from '#/env/common' + +export * from '#/env/common' + +/** + * The semver version of the app, specified in our `package.json`.file. On + * iOs/Android, the native build version is appended to the semver version, so + * that it can be used to identify a specific build. + */ +export const APP_VERSION = RELEASE_VERSION + +/** + * The short commit hash and environment of the current bundle. + */ +export const APP_METADATA = `${BUNDLE_IDENTIFIER.slice(0, 7)} (${__DEV__ ? 'dev' : 'prod'})` diff --git a/src/lib/app-info.ts b/src/lib/app-info.ts deleted file mode 100644 index 0749087ea..000000000 --- a/src/lib/app-info.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {nativeApplicationVersion, nativeBuildVersion} from 'expo-application' - -export const IS_TESTFLIGHT = process.env.EXPO_PUBLIC_ENV === 'testflight' -export const IS_INTERNAL = __DEV__ || IS_TESTFLIGHT - -// This is the commit hash that the current bundle was made from. The user can see the commit hash in the app's settings -// along with the other version info. Useful for debugging/reporting. -export const BUNDLE_IDENTIFIER = process.env.EXPO_PUBLIC_BUNDLE_IDENTIFIER ?? '' - -// This will always be in the format of YYMMDD, so that it always increases for each build. This should only be used -// for Statsig reporting and shouldn't be used to identify a specific bundle. -export const BUNDLE_DATE = - IS_TESTFLIGHT || __DEV__ ? 0 : Number(process.env.EXPO_PUBLIC_BUNDLE_DATE) - -export const appVersion = `${nativeApplicationVersion}.${nativeBuildVersion}` -export const bundleInfo = `${BUNDLE_IDENTIFIER} (${ - __DEV__ ? 'dev' : IS_TESTFLIGHT ? 'tf' : 'prod' -})` diff --git a/src/lib/app-info.web.ts b/src/lib/app-info.web.ts deleted file mode 100644 index 1530d9976..000000000 --- a/src/lib/app-info.web.ts +++ /dev/null @@ -1,18 +0,0 @@ -import packageDotJson from '../../package.json' - -export const IS_TESTFLIGHT = false -export const IS_INTERNAL = __DEV__ - -// This is the commit hash that the current bundle was made from. The user can see the commit hash in the app's settings -// along with the other version info. Useful for debugging/reporting. -export const BUNDLE_IDENTIFIER = - process.env.EXPO_PUBLIC_BUNDLE_IDENTIFIER ?? 'dev' - -// This will always be in the format of YYMMDD, so that it always increases for each build. This should only be used -// for Statsig reporting and shouldn't be used to identify a specific bundle. -export const BUNDLE_DATE = __DEV__ - ? 0 - : Number(process.env.EXPO_PUBLIC_BUNDLE_DATE) - -export const appVersion = packageDotJson.version -export const bundleInfo = `${BUNDLE_IDENTIFIER} (${__DEV__ ? 'dev' : 'prod'})` diff --git a/src/lib/hooks/useOTAUpdates.ts b/src/lib/hooks/useOTAUpdates.ts index 864d5d697..ba46b6055 100644 --- a/src/lib/hooks/useOTAUpdates.ts +++ b/src/lib/hooks/useOTAUpdates.ts @@ -10,9 +10,9 @@ import { useUpdates, } from 'expo-updates' -import {IS_TESTFLIGHT} from '#/lib/app-info' import {logger} from '#/logger' import {isIOS} from '#/platform/detection' +import {IS_TESTFLIGHT} from '#/env' const MINIMUM_MINIMIZE_TIME = 15 * 60e3 diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx index f2d3ffca9..1091c82e0 100644 --- a/src/lib/statsig/statsig.tsx +++ b/src/lib/statsig/statsig.tsx @@ -3,12 +3,11 @@ import {Platform} from 'react-native' import {AppState, type AppStateStatus} from 'react-native' import {Statsig, StatsigProvider} from 'statsig-react-native-expo' -import {BUNDLE_DATE, BUNDLE_IDENTIFIER, IS_TESTFLIGHT} from '#/lib/app-info' import {logger} from '#/logger' import {type MetricEvents} from '#/logger/metrics' import {isWeb} from '#/platform/detection' import * as persisted from '#/state/persisted' -import packageDotJson from '../../../package.json' +import * as env from '#/env' import {useSession} from '../../state/session' import {timeout} from '../async/timeout' import {useNonReactiveCallback} from '../hooks/useNonReactiveCallback' @@ -49,12 +48,11 @@ export type {MetricEvents as LogEvents} function createStatsigOptions(prefetchUsers: StatsigUser[]) { return { environment: { - tier: - process.env.NODE_ENV === 'development' - ? 'development' - : IS_TESTFLIGHT - ? 'staging' - : 'production', + tier: env.IS_DEV + ? 'development' + : env.IS_TESTFLIGHT + ? 'staging' + : 'production', }, // Don't block on waiting for network. The fetched config will kick in on next load. // This ensures the UI is always consistent and doesn't update mid-session. @@ -212,9 +210,9 @@ function toStatsigUser(did: string | undefined): StatsigUser { refSrc, refUrl, platform: Platform.OS as 'ios' | 'android' | 'web', - appVersion: packageDotJson.version, - bundleIdentifier: BUNDLE_IDENTIFIER, - bundleDate: BUNDLE_DATE, + appVersion: env.RELEASE_VERSION, + bundleIdentifier: env.BUNDLE_IDENTIFIER, + bundleDate: env.BUNDLE_DATE, appLanguage: languagePrefs.appLanguage, contentLanguages: languagePrefs.contentLanguages, }, diff --git a/src/logger/bitdrift/setup/index.ts b/src/logger/bitdrift/setup/index.ts index d6af3fe24..dd2560acc 100644 --- a/src/logger/bitdrift/setup/index.ts +++ b/src/logger/bitdrift/setup/index.ts @@ -2,8 +2,7 @@ import {init, SessionStrategy} from '@bitdrift/react-native' import {Statsig} from 'statsig-react-native-expo' import {initPromise} from '#/lib/statsig/statsig' - -const BITDRIFT_API_KEY = process.env.BITDRIFT_API_KEY +import {BITDRIFT_API_KEY} from '#/env' initPromise.then(() => { let isEnabled = false diff --git a/src/logger/index.ts b/src/logger/index.ts index e7aaf666a..998d02581 100644 --- a/src/logger/index.ts +++ b/src/logger/index.ts @@ -14,9 +14,10 @@ import { } from '#/logger/types' import {enabledLogLevels} from '#/logger/util' import {isNative} from '#/platform/detection' +import {ENV} from '#/env' const TRANSPORTS: Transport[] = (function configureTransports() { - switch (process.env.NODE_ENV) { + switch (ENV) { case 'production': { return [sentryTransport, isNative && bitdriftTransport].filter( Boolean, diff --git a/src/logger/sentry/setup/index.ts b/src/logger/sentry/setup/index.ts index f05a7fc83..d062f05d2 100644 --- a/src/logger/sentry/setup/index.ts +++ b/src/logger/sentry/setup/index.ts @@ -1,32 +1,15 @@ -/** - * Importing these separately from `platform/detection` and `lib/app-info` to - * avoid future conflicts and/or circular deps - */ - import {init} from '@sentry/react-native' -import pkgJson from '#/../package.json' - -/** - * Examples: - * - `dev` - * - `1.99.0` - */ -const release = process.env.SENTRY_RELEASE || pkgJson.version - -/** - * The latest deployed commit hash - */ -const dist = process.env.SENTRY_DIST || 'dev' +import * as env from '#/env' init({ - enabled: !__DEV__ && !!process.env.SENTRY_DSN, + enabled: !env.IS_DEV && !!env.SENTRY_DSN, autoSessionTracking: false, - dsn: process.env.SENTRY_DSN, + dsn: env.SENTRY_DSN, debug: false, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production - environment: process.env.NODE_ENV, - dist, - release, + environment: env.ENV, + dist: env.BUNDLE_IDENTIFIER, + release: env.RELEASE_VERSION, ignoreErrors: [ /* * Unknown internals errors diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx index 0ce127ff3..e48841d9f 100644 --- a/src/screens/Settings/AboutSettings.tsx +++ b/src/screens/Settings/AboutSettings.tsx @@ -9,7 +9,6 @@ import {type NativeStackScreenProps} from '@react-navigation/native-stack' import {useMutation} from '@tanstack/react-query' import {Statsig} from 'statsig-react-native-expo' -import {appVersion, BUNDLE_DATE, bundleInfo} from '#/lib/app-info' import {STATUS_PAGE_URL} from '#/lib/constants' import {type CommonNavigatorParams} from '#/lib/routes/types' import {isAndroid, isIOS, isNative} from '#/platform/detection' @@ -23,6 +22,7 @@ import {Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon} from '#/components/i import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import * as env from '#/env' import {useDemoMode} from '#/storage/hooks/demo-mode' import {useDevMode} from '#/storage/hooks/dev-mode' import {OTAInfo} from './components/OTAInfo' @@ -123,7 +123,7 @@ export function AboutSettingsScreen({}: Props) { )} { const newDevModeEnabled = !devModeEnabled @@ -146,15 +146,15 @@ export function AboutSettingsScreen({}: Props) { }} onPress={() => { setStringAsync( - `Build version: ${appVersion}; Bundle info: ${bundleInfo}; Bundle date: ${BUNDLE_DATE}; Platform: ${Platform.OS}; Platform version: ${Platform.Version}; Anonymous ID: ${stableID}`, + `Build version: ${env.APP_VERSION}; Bundle info: ${env.APP_METADATA}; Bundle date: ${env.BUNDLE_DATE}; Platform: ${Platform.OS}; Platform version: ${Platform.Version}; Anonymous ID: ${stableID}`, ) Toast.show(_(msg`Copied build version to clipboard`)) }}> - Version {appVersion} + Version {env.APP_VERSION} - {bundleInfo} + {env.APP_METADATA} {devModeEnabled && ( <> diff --git a/src/screens/Settings/AppIconSettings/index.tsx b/src/screens/Settings/AppIconSettings/index.tsx index 954bac68a..799873c2d 100644 --- a/src/screens/Settings/AppIconSettings/index.tsx +++ b/src/screens/Settings/AppIconSettings/index.tsx @@ -3,20 +3,20 @@ import {Alert, View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import * as DynamicAppIcon from '@mozzius/expo-dynamic-app-icon' -import {NativeStackScreenProps} from '@react-navigation/native-stack' +import {type NativeStackScreenProps} from '@react-navigation/native-stack' -import {IS_INTERNAL} from '#/lib/app-info' import {PressableScale} from '#/lib/custom-animations/PressableScale' -import {CommonNavigatorParams} from '#/lib/routes/types' +import {type CommonNavigatorParams} from '#/lib/routes/types' import {useGate} from '#/lib/statsig/statsig' import {isAndroid} from '#/platform/detection' import {AppIconImage} from '#/screens/Settings/AppIconSettings/AppIconImage' -import {AppIconSet} from '#/screens/Settings/AppIconSettings/types' +import {type AppIconSet} from '#/screens/Settings/AppIconSettings/types' import {useAppIconSets} from '#/screens/Settings/AppIconSettings/useAppIconSets' import {atoms as a, useTheme} from '#/alf' import * as Toggle from '#/components/forms/Toggle' import * as Layout from '#/components/Layout' import {Text} from '#/components/Typography' +import {IS_INTERNAL} from '#/env' type Props = NativeStackScreenProps export function AppIconSettingsScreen({}: Props) { diff --git a/src/screens/Settings/AppearanceSettings.tsx b/src/screens/Settings/AppearanceSettings.tsx index d0158aaa8..492d6d172 100644 --- a/src/screens/Settings/AppearanceSettings.tsx +++ b/src/screens/Settings/AppearanceSettings.tsx @@ -8,7 +8,6 @@ import Animated, { import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {IS_INTERNAL} from '#/lib/app-info' import { type CommonNavigatorParams, type NativeStackScreenProps, @@ -26,6 +25,7 @@ import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/T import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase' import * as Layout from '#/components/Layout' import {Text} from '#/components/Typography' +import {IS_INTERNAL} from '#/env' import * as SettingsList from './components/SettingsList' type Props = NativeStackScreenProps diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx index b712c054c..719bbf9a2 100644 --- a/src/screens/Settings/Settings.tsx +++ b/src/screens/Settings/Settings.tsx @@ -9,7 +9,6 @@ import {useNavigation} from '@react-navigation/native' import {type NativeStackScreenProps} from '@react-navigation/native-stack' import {useActorStatus} from '#/lib/actor-status' -import {IS_INTERNAL} from '#/lib/app-info' import {HELP_DESK_URL} from '#/lib/constants' import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' import {useApplyPullRequestOTAUpdate} from '#/lib/hooks/useOTAUpdates' @@ -66,6 +65,7 @@ import { shouldShowVerificationCheckButton, VerificationCheckButton, } from '#/components/verification/VerificationCheckButton' +import {IS_INTERNAL} from '#/env' import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged' type Props = NativeStackScreenProps diff --git a/src/state/queries/messages/const.ts b/src/state/queries/messages/const.ts index 7642c5d7b..1c5519a63 100644 --- a/src/state/queries/messages/const.ts +++ b/src/state/queries/messages/const.ts @@ -1,3 +1,5 @@ +import {CHAT_PROXY_DID} from '#/env' + export const DM_SERVICE_HEADERS = { - 'atproto-proxy': 'did:web:api.bsky.chat#bsky_chat', + 'atproto-proxy': `${CHAT_PROXY_DID}#bsky_chat`, } diff --git a/src/state/session/logging.ts b/src/state/session/logging.ts index 98de5a396..bf847f08f 100644 --- a/src/state/session/logging.ts +++ b/src/state/session/logging.ts @@ -1,11 +1,11 @@ -import {AtpSessionData, AtpSessionEvent} from '@atproto/api' +import {type AtpSessionData, type AtpSessionEvent} from '@atproto/api' import {sha256} from 'js-sha256' import {Statsig} from 'statsig-react-native-expo' -import {IS_INTERNAL} from '#/lib/app-info' -import {Schema} from '../persisted' -import {Action, State} from './reducer' -import {SessionAccount} from './types' +import {IS_INTERNAL} from '#/env' +import {type Schema} from '../persisted' +import {type Action, type State} from './reducer' +import {type SessionAccount} from './types' type Reducer = (state: State, action: Action) => State diff --git a/webpack.config.js b/webpack.config.js index 9a238e549..7f58a7448 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -53,7 +53,7 @@ module.exports = async function (env, argv) { project: 'app', authToken: process.env.SENTRY_AUTH_TOKEN, release: { - // env is undefined for Render.com builds, fall back + // fallback needed for Render.com deployments name: process.env.SENTRY_RELEASE || version, dist: process.env.SENTRY_DIST, }, -- cgit 1.4.1