import {useCallback, useState} from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {cleanError} from '#/lib/strings/errors'
import {definitelyUrl} from '#/lib/strings/url-helpers'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useTickEveryMinute} from '#/state/shell'
import {atoms as a, ios, native, platform, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import * as TextField from '#/components/forms/TextField'
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
import {Loader} from '#/components/Loader'
import * as ProfileCard from '#/components/ProfileCard'
import * as Select from '#/components/Select'
import {Text} from '#/components/Typography'
import type * as bsky from '#/types/bsky'
import {LinkPreview} from './LinkPreview'
import {useLiveLinkMetaQuery, useUpsertLiveStatusMutation} from './queries'
import {displayDuration, useDebouncedValue} from './utils'
export function GoLiveDialog({
control,
profile,
}: {
control: Dialog.DialogControlProps
profile: bsky.profile.AnyProfileView
}) {
return (
)
}
// Possible durations: max 4 hours, 5 minute intervals
const DURATIONS = Array.from({length: (4 * 60) / 5}).map((_, i) => (i + 1) * 5)
function DialogInner({profile}: {profile: bsky.profile.AnyProfileView}) {
const control = Dialog.useDialogContext()
const {_, i18n} = useLingui()
const t = useTheme()
const [liveLink, setLiveLink] = useState('')
const [liveLinkError, setLiveLinkError] = useState('')
const [duration, setDuration] = useState(60)
const moderationOpts = useModerationOpts()
const tick = useTickEveryMinute()
const time = useCallback(
(offset: number) => {
tick!
const date = new Date()
date.setMinutes(date.getMinutes() + offset)
return i18n
.date(date, {hour: 'numeric', minute: '2-digit', hour12: true})
.toLocaleUpperCase()
.replace(' ', '')
},
[tick, i18n],
)
const onChangeDuration = useCallback((newDuration: string) => {
setDuration(Number(newDuration))
}, [])
const liveLinkUrl = definitelyUrl(liveLink)
const debouncedUrl = useDebouncedValue(liveLinkUrl, 500)
const {
data: linkMeta,
isSuccess: hasValidLinkMeta,
isLoading: linkMetaLoading,
error: linkMetaError,
} = useLiveLinkMetaQuery(debouncedUrl)
const {
mutate: goLive,
isPending: isGoingLive,
error: goLiveError,
} = useUpsertLiveStatusMutation(duration, linkMeta)
const isSourceInvalid = !!liveLinkError || !!linkMetaError
const hasLink = !!debouncedUrl && !isSourceInvalid
return (
Go Live
Add a temporary live status to your profile. When someone clicks
on your avatar, they’ll see information about your live event.
{moderationOpts && (
)}
Live link
setLiveLinkError('')}
onBlur={() => {
if (!definitelyUrl(liveLink)) {
setLiveLinkError('Invalid URL')
}
}}
returnKeyType="done"
autoCapitalize="none"
autoComplete="url"
autoCorrect={false}
/>
{(liveLinkError || linkMetaError) && (
{liveLinkError ? (
This is not a valid link
) : (
cleanError(linkMetaError)
)}
)}
{hasLink && (
Go live for
{displayDuration(i18n, duration)}
{' '}
{time(duration)}
{
const label = displayDuration(i18n, item)
return (
{label}
{' '}
{time(item)}
)
}}
items={DURATIONS}
valueExtractor={d => String(d)}
/>
)}
{goLiveError && (
{cleanError(goLiveError)}
)}
{hasLink && (
)}
)
}