[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
+1 -1
View File
@@ -954,7 +954,7 @@ let PostFeed = ({
const actor = post.author
if (
actor.status &&
validateStatus(actor.did, actor.status, liveNowConfig) &&
validateStatus(actor.status, liveNowConfig) &&
isStatusStillActive(actor.status.expiresAt)
) {
if (!seenActorWithStatusRef.current.has(actor.did)) {
+62 -18
View File
@@ -15,6 +15,7 @@ import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {type Shadow} from '#/state/cache/types'
import {useModalControls} from '#/state/modals'
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
import {
RQKEY as profileQueryKey,
useProfileBlockMutationQueue,
@@ -25,6 +26,7 @@ import {useCanGoLive} from '#/state/service-config'
import {useSession} from '#/state/session'
import {EventStopper} from '#/view/com/util/EventStopper'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog'
import {StarterPackDialog} from '#/components/dialogs/StarterPackDialog'
@@ -59,6 +61,8 @@ import * as Prompt from '#/components/Prompt'
import {useFullVerificationState} from '#/components/verification'
import {VerificationCreatePrompt} from '#/components/verification/VerificationCreatePrompt'
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
import {Dot} from '#/features/nuxs/components/Dot'
import {Gradient} from '#/features/nuxs/components/Gradient'
import {useDevMode} from '#/storage/hooks/dev-mode'
let ProfileMenu = ({
@@ -66,6 +70,7 @@ let ProfileMenu = ({
}: {
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
}): React.ReactNode => {
const t = useTheme()
const {_} = useLingui()
const {currentAccount, hasSession} = useSession()
const {openModal} = useModalControls()
@@ -79,8 +84,15 @@ let ProfileMenu = ({
const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked
const [devModeEnabled] = useDevMode()
const verification = useFullVerificationState({profile})
const canGoLive = useCanGoLive(currentAccount?.did)
const canGoLive = useCanGoLive()
const status = useActorStatus(profile)
const statusNudge = useNux(Nux.LiveNowBetaNudge)
const statusNudgeActive =
isSelf &&
canGoLive &&
statusNudge.status === 'ready' &&
!statusNudge.nux?.completed
const {mutate: saveNux} = useSaveNux()
const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile)
const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
@@ -229,17 +241,22 @@ let ProfileMenu = ({
<Menu.Trigger label={_(msg`More options`)}>
{({props}) => {
return (
<Button
{...props}
testID="profileHeaderDropdownBtn"
label={_(msg`More options`)}
hitSlop={HITSLOP_20}
variant="solid"
color="secondary"
size="small"
shape="round">
<ButtonIcon icon={Ellipsis} size="sm" />
</Button>
<>
<Button
{...props}
testID="profileHeaderDropdownBtn"
label={_(msg`More options`)}
hitSlop={HITSLOP_20}
variant="solid"
color="secondary"
size="small"
shape="round">
{statusNudgeActive && <Gradient style={[a.rounded_full]} />}
<ButtonIcon icon={Ellipsis} size="sm" />
</Button>
{statusNudgeActive && <Dot top={1} right={1} />}
</>
)
}}
</Menu.Trigger>
@@ -337,11 +354,19 @@ let ProfileMenu = ({
? _(msg`Edit live status`)
: _(msg`Go live`)
}
onPress={
status.isDisabled
? goLiveDisabledDialogControl.open
: goLiveDialogControl.open
}>
onPress={() => {
if (status.isDisabled) {
goLiveDisabledDialogControl.open()
} else {
goLiveDialogControl.open()
}
saveNux({
id: Nux.LiveNowBetaNudge,
data: undefined,
completed: true,
})
}}>
{statusNudgeActive && <Gradient />}
<Menu.ItemText>
{status.isDisabled ? (
<Trans>Go live (disabled)</Trans>
@@ -351,7 +376,26 @@ let ProfileMenu = ({
<Trans>Go live</Trans>
)}
</Menu.ItemText>
<Menu.ItemIcon icon={LiveIcon} />
{statusNudgeActive && (
<Menu.ItemText
style={[
a.flex_0,
{
color: t.palette.primary_500,
right: isWeb ? -8 : -4,
},
]}>
<Trans>New</Trans>
</Menu.ItemText>
)}
<Menu.ItemIcon
icon={LiveIcon}
fill={
statusNudgeActive
? () => t.palette.primary_500
: undefined
}
/>
</Menu.Item>
)}
{verification.viewer.role === 'verifier' &&