Handle live event in feed card
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, {useMemo} from 'react'
|
||||||
import {type GestureResponderEvent, View} from 'react-native'
|
import {type GestureResponderEvent, View} from 'react-native'
|
||||||
import {
|
import {
|
||||||
type AppBskyFeedDefs,
|
type AppBskyFeedDefs,
|
||||||
@@ -21,19 +21,21 @@ import {
|
|||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, select, useTheme} from '#/alf'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonIcon,
|
ButtonIcon,
|
||||||
type ButtonProps,
|
type ButtonProps,
|
||||||
ButtonText,
|
ButtonText,
|
||||||
} from '#/components/Button'
|
} from '#/components/Button'
|
||||||
|
import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live'
|
||||||
import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
|
import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
|
||||||
import {Link as InternalLink, type LinkProps} from '#/components/Link'
|
import {Link as InternalLink, type LinkProps} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {RichText, type RichTextProps} from '#/components/RichText'
|
import {RichText, type RichTextProps} from '#/components/RichText'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useActiveLiveEventFeedUris} from '#/features/liveEvents/context'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from './icons/Trash'
|
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from './icons/Trash'
|
||||||
|
|
||||||
@@ -49,7 +51,11 @@ export function Default(props: Props) {
|
|||||||
<Outer>
|
<Outer>
|
||||||
<Header>
|
<Header>
|
||||||
<Avatar src={view.avatar} />
|
<Avatar src={view.avatar} />
|
||||||
<TitleAndByline title={view.displayName} creator={view.creator} />
|
<TitleAndByline
|
||||||
|
title={view.displayName}
|
||||||
|
creator={view.creator}
|
||||||
|
uri={view.uri}
|
||||||
|
/>
|
||||||
<SaveButton view={view} pin />
|
<SaveButton view={view} pin />
|
||||||
</Header>
|
</Header>
|
||||||
<Description description={view.description} />
|
<Description description={view.description} />
|
||||||
@@ -118,14 +124,40 @@ export function AvatarPlaceholder({size = 40}: Omit<AvatarProps, 'src'>) {
|
|||||||
export function TitleAndByline({
|
export function TitleAndByline({
|
||||||
title,
|
title,
|
||||||
creator,
|
creator,
|
||||||
|
uri,
|
||||||
}: {
|
}: {
|
||||||
title: string
|
title: string
|
||||||
creator?: bsky.profile.AnyProfileView
|
creator?: bsky.profile.AnyProfileView
|
||||||
|
uri?: string
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const activeLiveEvents = useActiveLiveEventFeedUris()
|
||||||
|
const liveColor = useMemo(
|
||||||
|
() =>
|
||||||
|
select(t.name, {
|
||||||
|
dark: t.palette.negative_600,
|
||||||
|
dim: t.palette.negative_600,
|
||||||
|
light: t.palette.negative_500,
|
||||||
|
}),
|
||||||
|
[t],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_1]}>
|
<View style={[a.flex_1]}>
|
||||||
|
{uri && activeLiveEvents.has(uri) && (
|
||||||
|
<View style={[a.flex_row, a.align_center, a.gap_2xs]}>
|
||||||
|
<LiveIcon size="xs" fill={liveColor} />
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_2xs,
|
||||||
|
a.font_medium,
|
||||||
|
a.leading_snug,
|
||||||
|
{color: liveColor},
|
||||||
|
]}>
|
||||||
|
<Trans>Happening now</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
<Text
|
<Text
|
||||||
emoji
|
emoji
|
||||||
style={[a.text_md, a.font_semi_bold, a.leading_snug]}
|
style={[a.text_md, a.font_semi_bold, a.leading_snug]}
|
||||||
|
|||||||
@@ -842,6 +842,7 @@ export function SuggestedFeeds() {
|
|||||||
<FeedCard.TitleAndByline
|
<FeedCard.TitleAndByline
|
||||||
title={feed.displayName}
|
title={feed.displayName}
|
||||||
creator={feed.creator}
|
creator={feed.creator}
|
||||||
|
uri={feed.uri}
|
||||||
/>
|
/>
|
||||||
</FeedCard.Header>
|
</FeedCard.Header>
|
||||||
<FeedCard.Description
|
<FeedCard.Description
|
||||||
|
|||||||
@@ -17,16 +17,16 @@ export function FeedEmbed({
|
|||||||
return (
|
return (
|
||||||
<FeedCard.Link
|
<FeedCard.Link
|
||||||
view={embed.view}
|
view={embed.view}
|
||||||
style={[a.border, t.atoms.border_contrast_low, a.p_md, a.rounded_sm]}>
|
style={[a.border, t.atoms.border_contrast_low, a.p_sm, a.rounded_md]}>
|
||||||
<FeedCard.Outer>
|
<FeedCard.Outer>
|
||||||
<FeedCard.Header>
|
<FeedCard.Header>
|
||||||
<FeedCard.Avatar src={embed.view.avatar} />
|
<FeedCard.Avatar src={embed.view.avatar} size={48} />
|
||||||
<FeedCard.TitleAndByline
|
<FeedCard.TitleAndByline
|
||||||
title={embed.view.displayName}
|
title={embed.view.displayName}
|
||||||
creator={embed.view.creator}
|
creator={embed.view.creator}
|
||||||
|
uri={embed.view.uri}
|
||||||
/>
|
/>
|
||||||
</FeedCard.Header>
|
</FeedCard.Header>
|
||||||
<FeedCard.Likes count={embed.view.likeCount || 0} />
|
|
||||||
</FeedCard.Outer>
|
</FeedCard.Outer>
|
||||||
</FeedCard.Link>
|
</FeedCard.Link>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import {createContext, useContext} from 'react'
|
|||||||
import {QueryClient, useQuery} from '@tanstack/react-query'
|
import {QueryClient, useQuery} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useIsBskyTeam} from '#/lib/hooks/useIsBskyTeam'
|
import {useIsBskyTeam} from '#/lib/hooks/useIsBskyTeam'
|
||||||
|
import {
|
||||||
|
convertBskyAppUrlIfNeeded,
|
||||||
|
isBskyCustomFeedUrl,
|
||||||
|
makeRecordUri,
|
||||||
|
} from '#/lib/strings/url-helpers'
|
||||||
import {IS_DEV, LIVE_EVENTS_URL} from '#/env'
|
import {IS_DEV, LIVE_EVENTS_URL} from '#/env'
|
||||||
import {useLiveEventPreferences} from '#/features/liveEvents/preferences'
|
import {useLiveEventPreferences} from '#/features/liveEvents/preferences'
|
||||||
import {type LiveEventsWorkerResponse} from '#/features/liveEvents/types'
|
import {type LiveEventsWorkerResponse} from '#/features/liveEvents/types'
|
||||||
@@ -88,3 +93,19 @@ export function useUserPreferencedLiveEvents() {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useActiveLiveEventFeedUris() {
|
||||||
|
const {feeds} = useLiveEvents()
|
||||||
|
|
||||||
|
return new Set(
|
||||||
|
feeds
|
||||||
|
// insurance
|
||||||
|
.filter(f => isBskyCustomFeedUrl(f.url))
|
||||||
|
.map(f => {
|
||||||
|
const uri = convertBskyAppUrlIfNeeded(f.url)
|
||||||
|
const [_0, did, _1, rkey] = uri.split('/').filter(Boolean)
|
||||||
|
const urip = makeRecordUri(did, 'app.bsky.feed.generator', rkey)
|
||||||
|
return urip.toString()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user