[APP-1759] Live Now Open Beta (#9699)

* Add report dialog to LiveStatus dialog

* Mr Worldwide™

* Bug fix bug fix

* Copy update

* Simplify parsing

* Bump api sdk

* update dev-env

* Update yarn.lock

* Bump api sdk

* Refactor useActorStatus, add disablement and appeal dialog

* Fix types

* Guard against chat profile views

* Go live (disabled)

* Fix types

* Update config and gates

* Add allowed services

* Merge conflicts

* Fix gradient handling for nudge

* Only show nudge on your own profile

* Fix live avi overflow breakage

* Add TODO

* Feedback

* Update nux image

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
Eric Bailey
2026-01-14 16:57:21 -06:00
committed by GitHub
parent 5922c6622f
commit 2223babc2b
19 changed files with 456 additions and 107 deletions
@@ -0,0 +1,209 @@
import {useCallback, useMemo} from 'react'
import {View} from 'react-native'
import {Image} from 'expo-image'
import {LinearGradient} from 'expo-linear-gradient'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isWeb} from '#/platform/detection'
import {atoms as a, select, useTheme, utils, web} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {useNuxDialogContext} from '#/components/dialogs/nuxs'
import {
createIsEnabledCheck,
isExistingUserAsOf,
} from '#/components/dialogs/nuxs/utils'
import {Beaker_Stroke2_Corner2_Rounded as BeakerIcon} from '#/components/icons/Beaker'
import {Text} from '#/components/Typography'
import {IS_E2E} from '#/env'
export const enabled = createIsEnabledCheck(props => {
return (
!IS_E2E &&
isExistingUserAsOf(
'2026-01-16T00:00:00.000Z',
props.currentProfile.createdAt,
) &&
props.gate('live_now_beta')
)
})
export function LiveNowBetaDialog() {
const t = useTheme()
const {_} = useLingui()
const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl()
Dialog.useAutoOpen(control)
const onClose = useCallback(() => {
nuxDialogs.dismissActiveNux()
}, [nuxDialogs])
const shadowColor = useMemo(() => {
return select(t.name, {
light: utils.alpha(t.palette.primary_900, 0.4),
dark: utils.alpha(t.palette.primary_25, 0.4),
dim: utils.alpha(t.palette.primary_25, 0.4),
})
}, [t])
return (
<Dialog.Outer
control={control}
onClose={onClose}
nativeOptions={{preventExpansion: true}}>
<Dialog.Handle fill={t.palette.primary_700} />
<Dialog.ScrollableInner
label={_(msg`Show when youre live`)}
style={[web({maxWidth: 440})]}
contentContainerStyle={[
{
paddingTop: 0,
paddingLeft: 0,
paddingRight: 0,
},
]}>
<View
style={[
a.align_center,
a.overflow_hidden,
{
gap: 16,
paddingTop: isWeb ? 24 : 40,
borderTopLeftRadius: a.rounded_md.borderRadius,
borderTopRightRadius: a.rounded_md.borderRadius,
},
]}>
<LinearGradient
colors={[
t.palette.primary_100,
utils.alpha(t.palette.primary_100, 0),
]}
locations={[0, 1]}
start={{x: 0, y: 0}}
end={{x: 0, y: 1}}
style={[a.absolute, a.inset_0]}
/>
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
<BeakerIcon fill={t.palette.primary_700} size="sm" />
<Text
style={[
a.font_semi_bold,
{
color: t.palette.primary_700,
},
]}>
<Trans>Beta Feature</Trans>
</Text>
</View>
<View
style={[
a.relative,
a.w_full,
{
paddingTop: 8,
paddingHorizontal: 32,
paddingBottom: 32,
},
]}>
<View
style={[
{
borderRadius: 24,
aspectRatio: 652 / 211,
},
isWeb
? [
{
boxShadow: `0px 10px 15px -3px ${shadowColor}`,
},
]
: [
t.atoms.shadow_md,
{
shadowColor,
shadowOpacity: 0.2,
shadowOffset: {
width: 0,
height: 10,
},
},
],
]}>
<Image
accessibilityIgnoresInvertColors
source={require('../../../../assets/images/live_now_beta.webp')}
style={[
a.w_full,
{
aspectRatio: 652 / 211,
},
]}
alt={_(
msg({
message: `A screenshot of a post from @esb.lol, showing the user is currently livestreaming content on Twitch. The post reads: "Hello! I'm live on Twitch, and I'm testing Bluesky's latest feature too!"`,
comment:
'Contains a post that originally appeared in English. Consider translating the post text if it makes sense in your language, and noting that the post was translated from English.',
}),
)}
/>
</View>
</View>
</View>
<View style={[a.align_center, a.px_xl, a.gap_2xl, a.pb_sm]}>
<View style={[a.gap_sm, a.align_center]}>
<Text
style={[
a.text_3xl,
a.leading_tight,
a.font_bold,
a.text_center,
{
fontSize: isWeb ? 28 : 32,
maxWidth: 360,
},
]}>
<Trans>Show when youre live</Trans>
</Text>
<Text
style={[
a.text_md,
a.leading_snug,
a.text_center,
{
maxWidth: 340,
},
]}>
<Trans>
Streaming on Twitch? Set your live status on Bluesky to add a
badge to your avatar. Tapping it takes people straight to your
stream.
</Trans>
</Text>
</View>
{!isWeb && (
<Button
label={_(msg`Close`)}
size="large"
color="primary"
onPress={() => {
control.close()
}}
style={[a.w_full]}>
<ButtonText>
<Trans>Close</Trans>
</ButtonText>
</Button>
)}
</View>
<Dialog.Close />
</Dialog.ScrollableInner>
</Dialog.Outer>
)
}
+6 -8
View File
@@ -20,9 +20,9 @@ import {useProfileQuery} from '#/state/queries/profile'
import {type SessionAccount, useSession} from '#/state/session'
import {useOnboardingState} from '#/state/shell'
import {
enabled as isFindContactsAnnouncementEnabled,
FindContactsAnnouncement,
} from '#/components/dialogs/nuxs/FindContactsAnnouncement'
enabled as isLiveNowBetaDialogEnabled,
LiveNowBetaDialog,
} from '#/components/dialogs/nuxs/LiveNowBetaDialog'
import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
import {type EnabledCheckProps} from '#/components/dialogs/nuxs/utils'
import {useGeolocation} from '#/geolocation'
@@ -37,8 +37,8 @@ const queuedNuxs: {
enabled?: (props: EnabledCheckProps) => boolean
}[] = [
{
id: Nux.FindContactsAnnouncement,
enabled: isFindContactsAnnouncementEnabled,
id: Nux.LiveNowBetaDialog,
enabled: isLiveNowBetaDialogEnabled,
},
]
@@ -186,9 +186,7 @@ function Inner({
return (
<Context.Provider value={ctx}>
{/*For example, activeNux === Nux.NeueTypography && <NeueTypography />*/}
{activeNux === Nux.FindContactsAnnouncement && (
<FindContactsAnnouncement />
)}
{activeNux === Nux.LiveNowBetaDialog && <LiveNowBetaDialog />}
</Context.Provider>
)
}