···11import React from 'react'
22-import {Text as RNText, TextStyle, TextProps as RNTextProps} from 'react-native'
22+import {
33+ Text as RNText,
44+ StyleProp,
55+ TextStyle,
66+ TextProps as RNTextProps,
77+} from 'react-native'
38import {UITextView} from 'react-native-ui-text-view'
49510import {useTheme, atoms, web, flatten} from '#/alf'
···3439 * If the `lineHeight` value is > 2, we assume it's an absolute value and
3540 * returns it as-is.
3641 */
3737-function normalizeTextStyles(styles: TextStyle[]) {
4242+export function normalizeTextStyles(styles: StyleProp<TextStyle>) {
3843 const s = flatten(styles)
3944 // should always be defined on these components
4045 const fontSize = s.fontSize || atoms.text_md.fontSize
···11import {
22 BskyPreferences,
33- LabelPreference,
43 BskyThreadViewPreference,
54 BskyFeedViewPreference,
65} from '@atproto/api'
7688-export const configurableAdultLabelGroups = [
99- 'nsfw',
1010- 'nudity',
1111- 'suggestive',
1212- 'gore',
1313-] as const
1414-1515-export const configurableOtherLabelGroups = [
1616- 'hate',
1717- 'spam',
1818- 'impersonation',
1919-] as const
2020-2121-export const configurableLabelGroups = [
2222- ...configurableAdultLabelGroups,
2323- ...configurableOtherLabelGroups,
2424-] as const
2525-export type ConfigurableLabelGroup = (typeof configurableLabelGroups)[number]
2626-2727-export type LabelGroup =
2828- | ConfigurableLabelGroup
2929- | 'illegal'
3030- | 'always-filter'
3131- | 'always-warn'
3232- | 'unknown'
3333-347export type UsePreferencesQueryResponse = Omit<
358 BskyPreferences,
369 'contentLabels' | 'feedViewPrefs' | 'feeds'
3710> & {
3838- /*
3939- * Content labels previously included 'show', which has been deprecated in
4040- * favor of 'ignore'. The API can return legacy data from the database, and
4141- * we clean up the data in `usePreferencesQuery`.
4242- */
4343- contentLabels: Record<ConfigurableLabelGroup, LabelPreference>
4411 feedViewPrefs: BskyFeedViewPreference & {
4512 lab_mergeFeedEnabled?: boolean
4613 }
-16
src/state/queries/preferences/util.ts
···11-import {LabelPreference} from '@atproto/api'
22-33-/**
44- * Content labels previously included 'show', which has been deprecated in
55- * favor of 'ignore'. The API can return legacy data from the database, and
66- * we clean up the data in `usePreferencesQuery`.
77- *
88- * @deprecated
99- */
1010-export function temp__migrateLabelPref(
1111- pref: LabelPreference | 'show',
1212-): LabelPreference {
1313- // @ts-ignore
1414- if (pref === 'show') return 'ignore'
1515- return pref
1616-}
-34
src/state/queries/profile-extra-info.ts
···11-import {useQuery} from '@tanstack/react-query'
22-33-import {getAgent} from '#/state/session'
44-import {STALE} from '#/state/queries'
55-66-// TODO refactor invalidate on mutate?
77-export const RQKEY = (did: string) => ['profile-extra-info', did]
88-99-/**
1010- * Fetches some additional information for the profile screen which
1111- * is not available in the API's ProfileView
1212- */
1313-export function useProfileExtraInfoQuery(did: string) {
1414- return useQuery({
1515- staleTime: STALE.MINUTES.ONE,
1616- queryKey: RQKEY(did),
1717- async queryFn() {
1818- const [listsRes, feedsRes] = await Promise.all([
1919- getAgent().app.bsky.graph.getLists({
2020- actor: did,
2121- limit: 1,
2222- }),
2323- getAgent().app.bsky.feed.getActorFeeds({
2424- actor: did,
2525- limit: 1,
2626- }),
2727- ])
2828- return {
2929- hasLists: listsRes.data.lists.length > 0,
3030- hasFeedgens: feedsRes.data.feeds.length > 0,
3131- }
3232- },
3333- })
3434-}
···3939import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
4040import {useExternalLinkFetch} from './useExternalLinkFetch'
4141import {isWeb, isNative, isAndroid, isIOS} from 'platform/detection'
4242-import QuoteEmbed from '../util/post-embeds/QuoteEmbed'
4242+import {QuoteEmbed} from '../util/post-embeds/QuoteEmbed'
4343import {GalleryModel} from 'state/models/media/gallery'
4444import {Gallery} from './photos/Gallery'
4545import {MAX_GRAPHEME_LENGTH} from 'lib/constants'
···1515import * as ListAddUserModal from './ListAddRemoveUsers'
1616import * as AltImageModal from './AltImage'
1717import * as EditImageModal from './AltImage'
1818-import * as ReportModal from './report/Modal'
1919-import * as AppealLabelModal from './AppealLabel'
2018import * as DeleteAccountModal from './DeleteAccount'
2119import * as ChangeHandleModal from './ChangeHandle'
2220import * as InviteCodesModal from './InviteCodes'
2321import * as AddAppPassword from './AddAppPasswords'
2424-import * as ContentFilteringSettingsModal from './ContentFilteringSettings'
2522import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
2623import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
2727-import * as ModerationDetailsModal from './ModerationDetails'
2828-import * as BirthDateSettingsModal from './BirthDateSettings'
2924import * as VerifyEmailModal from './VerifyEmail'
3025import * as ChangeEmailModal from './ChangeEmail'
3126import * as ChangePasswordModal from './ChangePassword'
···6863 if (activeModal?.name === 'edit-profile') {
6964 snapPoints = EditProfileModal.snapPoints
7065 element = <EditProfileModal.Component {...activeModal} />
7171- } else if (activeModal?.name === 'report') {
7272- snapPoints = ReportModal.snapPoints
7373- element = <ReportModal.Component {...activeModal} />
7474- } else if (activeModal?.name === 'appeal-label') {
7575- snapPoints = AppealLabelModal.snapPoints
7676- element = <AppealLabelModal.Component {...activeModal} />
7766 } else if (activeModal?.name === 'create-or-edit-list') {
7867 snapPoints = CreateOrEditListModal.snapPoints
7968 element = <CreateOrEditListModal.Component {...activeModal} />
···11099 } else if (activeModal?.name === 'add-app-password') {
111100 snapPoints = AddAppPassword.snapPoints
112101 element = <AddAppPassword.Component />
113113- } else if (activeModal?.name === 'content-filtering-settings') {
114114- snapPoints = ContentFilteringSettingsModal.snapPoints
115115- element = <ContentFilteringSettingsModal.Component />
116102 } else if (activeModal?.name === 'content-languages-settings') {
117103 snapPoints = ContentLanguagesSettingsModal.snapPoints
118104 element = <ContentLanguagesSettingsModal.Component />
119105 } else if (activeModal?.name === 'post-languages-settings') {
120106 snapPoints = PostLanguagesSettingsModal.snapPoints
121107 element = <PostLanguagesSettingsModal.Component />
122122- } else if (activeModal?.name === 'moderation-details') {
123123- snapPoints = ModerationDetailsModal.snapPoints
124124- element = <ModerationDetailsModal.Component {...activeModal} />
125125- } else if (activeModal?.name === 'birth-date-settings') {
126126- snapPoints = BirthDateSettingsModal.snapPoints
127127- element = <BirthDateSettingsModal.Component />
128108 } else if (activeModal?.name === 'verify-email') {
129109 snapPoints = VerifyEmailModal.snapPoints
130110 element = <VerifyEmailModal.Component {...activeModal} />
-15
src/view/com/modals/Modal.web.tsx
···88import {useModals, useModalControls} from '#/state/modals'
99import type {Modal as ModalIface} from '#/state/modals'
1010import * as EditProfileModal from './EditProfile'
1111-import * as ReportModal from './report/Modal'
1212-import * as AppealLabelModal from './AppealLabel'
1311import * as CreateOrEditListModal from './CreateOrEditList'
1412import * as UserAddRemoveLists from './UserAddRemoveLists'
1513import * as ListAddUserModal from './ListAddRemoveUsers'
···2321import * as ChangeHandleModal from './ChangeHandle'
2422import * as InviteCodesModal from './InviteCodes'
2523import * as AddAppPassword from './AddAppPasswords'
2626-import * as ContentFilteringSettingsModal from './ContentFilteringSettings'
2724import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
2825import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
2929-import * as ModerationDetailsModal from './ModerationDetails'
3030-import * as BirthDateSettingsModal from './BirthDateSettings'
3126import * as VerifyEmailModal from './VerifyEmail'
3227import * as ChangeEmailModal from './ChangeEmail'
3328import * as ChangePasswordModal from './ChangePassword'
···7974 let element
8075 if (modal.name === 'edit-profile') {
8176 element = <EditProfileModal.Component {...modal} />
8282- } else if (modal.name === 'report') {
8383- element = <ReportModal.Component {...modal} />
8484- } else if (modal.name === 'appeal-label') {
8585- element = <AppealLabelModal.Component {...modal} />
8677 } else if (modal.name === 'create-or-edit-list') {
8778 element = <CreateOrEditListModal.Component {...modal} />
8879 } else if (modal.name === 'user-add-remove-lists') {
···10596 element = <InviteCodesModal.Component />
10697 } else if (modal.name === 'add-app-password') {
10798 element = <AddAppPassword.Component />
108108- } else if (modal.name === 'content-filtering-settings') {
109109- element = <ContentFilteringSettingsModal.Component />
11099 } else if (modal.name === 'content-languages-settings') {
111100 element = <ContentLanguagesSettingsModal.Component />
112101 } else if (modal.name === 'post-languages-settings') {
···115104 element = <AltTextImageModal.Component {...modal} />
116105 } else if (modal.name === 'edit-image') {
117106 element = <EditImageModal.Component {...modal} />
118118- } else if (modal.name === 'moderation-details') {
119119- element = <ModerationDetailsModal.Component {...modal} />
120120- } else if (modal.name === 'birth-date-settings') {
121121- element = <BirthDateSettingsModal.Component />
122107 } else if (modal.name === 'verify-email') {
123108 element = <VerifyEmailModal.Component {...modal} />
124109 } else if (modal.name === 'change-email') {
-142
src/view/com/modals/ModerationDetails.tsx
···11-import React from 'react'
22-import {StyleSheet, View} from 'react-native'
33-import {ModerationUI} from '@atproto/api'
44-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
55-import {s} from 'lib/styles'
66-import {Text} from '../util/text/Text'
77-import {TextLink} from '../util/Link'
88-import {usePalette} from 'lib/hooks/usePalette'
99-import {isWeb} from 'platform/detection'
1010-import {listUriToHref} from 'lib/strings/url-helpers'
1111-import {Button} from '../util/forms/Button'
1212-import {useModalControls} from '#/state/modals'
1313-import {useLingui} from '@lingui/react'
1414-import {Trans, msg} from '@lingui/macro'
1515-1616-export const snapPoints = [300]
1717-1818-export function Component({
1919- context,
2020- moderation,
2121-}: {
2222- context: 'account' | 'content'
2323- moderation: ModerationUI
2424-}) {
2525- const {closeModal} = useModalControls()
2626- const {isMobile} = useWebMediaQueries()
2727- const pal = usePalette('default')
2828- const {_} = useLingui()
2929-3030- let name
3131- let description
3232- if (!moderation.cause) {
3333- name = _(msg`Content Warning`)
3434- description = _(
3535- msg`Moderator has chosen to set a general warning on the content.`,
3636- )
3737- } else if (moderation.cause.type === 'blocking') {
3838- if (moderation.cause.source.type === 'list') {
3939- const list = moderation.cause.source.list
4040- name = _(msg`User Blocked by List`)
4141- description = (
4242- <Trans>
4343- This user is included in the{' '}
4444- <TextLink
4545- type="2xl"
4646- href={listUriToHref(list.uri)}
4747- text={list.name}
4848- style={pal.link}
4949- />{' '}
5050- list which you have blocked.
5151- </Trans>
5252- )
5353- } else {
5454- name = _(msg`User Blocked`)
5555- description = _(
5656- msg`You have blocked this user. You cannot view their content.`,
5757- )
5858- }
5959- } else if (moderation.cause.type === 'blocked-by') {
6060- name = _(msg`User Blocks You`)
6161- description = _(
6262- msg`This user has blocked you. You cannot view their content.`,
6363- )
6464- } else if (moderation.cause.type === 'block-other') {
6565- name = _(msg`Content Not Available`)
6666- description = _(
6767- msg`This content is not available because one of the users involved has blocked the other.`,
6868- )
6969- } else if (moderation.cause.type === 'muted') {
7070- if (moderation.cause.source.type === 'list') {
7171- const list = moderation.cause.source.list
7272- name = _(msg`Account Muted by List`)
7373- description = (
7474- <Trans>
7575- This user is included in the{' '}
7676- <TextLink
7777- type="2xl"
7878- href={listUriToHref(list.uri)}
7979- text={list.name}
8080- style={pal.link}
8181- />{' '}
8282- list which you have muted.
8383- </Trans>
8484- )
8585- } else {
8686- name = _(msg`Account Muted`)
8787- description = _(msg`You have muted this user.`)
8888- }
8989- } else {
9090- name = moderation.cause.labelDef.strings[context].en.name
9191- description = moderation.cause.labelDef.strings[context].en.description
9292- }
9393-9494- return (
9595- <View
9696- testID="moderationDetailsModal"
9797- style={[
9898- styles.container,
9999- {
100100- paddingHorizontal: isMobile ? 14 : 0,
101101- },
102102- pal.view,
103103- ]}>
104104- <Text type="title-xl" style={[pal.text, styles.title]}>
105105- {name}
106106- </Text>
107107- <Text type="2xl" style={[pal.text, styles.description]}>
108108- {description}
109109- </Text>
110110- <View style={s.flex1} />
111111- <Button
112112- type="primary"
113113- style={styles.btn}
114114- onPress={() => {
115115- closeModal()
116116- }}>
117117- <Text type="button-lg" style={[pal.textLight, s.textCenter, s.white]}>
118118- Okay
119119- </Text>
120120- </Button>
121121- </View>
122122- )
123123-}
124124-125125-const styles = StyleSheet.create({
126126- container: {
127127- flex: 1,
128128- },
129129- title: {
130130- textAlign: 'center',
131131- fontWeight: 'bold',
132132- marginBottom: 12,
133133- },
134134- description: {
135135- textAlign: 'center',
136136- },
137137- btn: {
138138- paddingVertical: 14,
139139- marginTop: isWeb ? 40 : 0,
140140- marginBottom: isWeb ? 0 : 40,
141141- },
142142-})
···11-// TODO: ATM, @atproto/api does not export ids but it does have these listed at @atproto/api/client/lexicons
22-// once we start exporting the ids from the @atproto/ap package, replace these hardcoded ones
33-export enum CollectionId {
44- FeedGenerator = 'app.bsky.feed.generator',
55- Profile = 'app.bsky.actor.profile',
66- List = 'app.bsky.graph.list',
77- Post = 'app.bsky.feed.post',
88-}