Starter Packs (#4332)

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
Hailey
2024-06-21 21:38:04 -07:00
committed by GitHub
parent 35f64535cb
commit f089f45781
115 changed files with 6336 additions and 237 deletions
@@ -0,0 +1,182 @@
import React from 'react'
import {Keyboard, View} from 'react-native'
import {
AppBskyActorDefs,
AppBskyFeedDefs,
moderateFeedGenerator,
moderateProfile,
ModerationOpts,
ModerationUI,
} from '@atproto/api'
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {DISCOVER_FEED_URI} from 'lib/constants'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles'
import {useSession} from 'state/session'
import {UserAvatar} from 'view/com/util/UserAvatar'
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
import {atoms as a, useTheme} from '#/alf'
import * as Toggle from '#/components/forms/Toggle'
import {Checkbox} from '#/components/forms/Toggle'
import {Text} from '#/components/Typography'
function WizardListCard({
type,
displayName,
subtitle,
onPress,
avatar,
included,
disabled,
moderationUi,
}: {
type: 'user' | 'algo'
profile?: AppBskyActorDefs.ProfileViewBasic
feed?: AppBskyFeedDefs.GeneratorView
displayName: string
subtitle: string
onPress: () => void
avatar?: string
included?: boolean
disabled?: boolean
moderationUi: ModerationUI
}) {
const t = useTheme()
const {_} = useLingui()
return (
<Toggle.Item
name={type === 'user' ? _(msg`Person toggle`) : _(msg`Feed toggle`)}
label={
included
? _(msg`Remove ${displayName} from starter pack`)
: _(msg`Add ${displayName} to starter pack`)
}
value={included}
disabled={disabled}
onChange={onPress}
style={[
a.flex_row,
a.align_center,
a.px_lg,
a.py_md,
a.gap_md,
a.border_b,
t.atoms.border_contrast_low,
]}>
<UserAvatar
size={45}
avatar={avatar}
moderation={moderationUi}
type={type}
/>
<View style={[a.flex_1, a.gap_2xs]}>
<Text
style={[a.flex_1, a.font_bold, a.text_md, a.leading_tight]}
numberOfLines={1}>
{displayName}
</Text>
<Text
style={[a.flex_1, a.leading_tight, t.atoms.text_contrast_medium]}
numberOfLines={1}>
{subtitle}
</Text>
</View>
<Checkbox />
</Toggle.Item>
)
}
export function WizardProfileCard({
state,
dispatch,
profile,
moderationOpts,
}: {
state: WizardState
dispatch: (action: WizardAction) => void
profile: AppBskyActorDefs.ProfileViewBasic
moderationOpts: ModerationOpts
}) {
const {currentAccount} = useSession()
const isMe = profile.did === currentAccount?.did
const included = isMe || state.profiles.some(p => p.did === profile.did)
const disabled = isMe || (!included && state.profiles.length >= 49)
const moderationUi = moderateProfile(profile, moderationOpts).ui('avatar')
const displayName = profile.displayName
? sanitizeDisplayName(profile.displayName)
: `@${sanitizeHandle(profile.handle)}`
const onPress = () => {
if (disabled) return
Keyboard.dismiss()
if (profile.did === currentAccount?.did) return
if (!included) {
dispatch({type: 'AddProfile', profile})
} else {
dispatch({type: 'RemoveProfile', profileDid: profile.did})
}
}
return (
<WizardListCard
type="user"
displayName={displayName}
subtitle={`@${sanitizeHandle(profile.handle)}`}
onPress={onPress}
avatar={profile.avatar}
included={included}
disabled={disabled}
moderationUi={moderationUi}
/>
)
}
export function WizardFeedCard({
generator,
state,
dispatch,
moderationOpts,
}: {
generator: GeneratorView
state: WizardState
dispatch: (action: WizardAction) => void
moderationOpts: ModerationOpts
}) {
const isDiscover = generator.uri === DISCOVER_FEED_URI
const included = isDiscover || state.feeds.some(f => f.uri === generator.uri)
const disabled = isDiscover || (!included && state.feeds.length >= 3)
const moderationUi = moderateFeedGenerator(generator, moderationOpts).ui(
'avatar',
)
const onPress = () => {
if (disabled) return
Keyboard.dismiss()
if (included) {
dispatch({type: 'RemoveFeed', feedUri: generator.uri})
} else {
dispatch({type: 'AddFeed', feed: generator})
}
}
return (
<WizardListCard
type="algo"
displayName={sanitizeDisplayName(generator.displayName)}
subtitle={`Feed by @${sanitizeHandle(generator.creator.handle)}`}
onPress={onPress}
avatar={generator.avatar}
included={included}
disabled={disabled}
moderationUi={moderationUi}
/>
)
}