diff --git a/src/components/Dialog/index.web.tsx b/src/components/Dialog/index.web.tsx
index 35d807b4be..aff1842f77 100644
--- a/src/components/Dialog/index.web.tsx
+++ b/src/components/Dialog/index.web.tsx
@@ -88,7 +88,10 @@ export function Outer({
if (!isOpen) return
function handler(e: KeyboardEvent) {
- if (e.key === 'Escape') close()
+ if (e.key === 'Escape') {
+ e.stopPropagation()
+ close()
+ }
}
document.addEventListener('keydown', handler)
diff --git a/src/components/NewskieDialog.tsx b/src/components/NewskieDialog.tsx
index 6743a592ba..d456bd6dab 100644
--- a/src/components/NewskieDialog.tsx
+++ b/src/components/NewskieDialog.tsx
@@ -6,10 +6,10 @@ import {useLingui} from '@lingui/react'
import {differenceInSeconds} from 'date-fns'
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
+import {isNative} from '#/platform/detection'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {HITSLOP_10} from 'lib/constants'
import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {isWeb} from 'platform/detection'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
@@ -70,19 +70,27 @@ export function NewskieDialog({
-
+
-
-
+
+
+
+
Say hello!
-
+
{profile.joinedViaStarterPack ? (
{profileName} joined Bluesky using a starter pack{' '}
@@ -116,18 +124,23 @@ export function NewskieDialog({
) : null}
-
+
+ {isNative && (
+
+ )}
+
+
diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx
index cd171a0a46..a73aae850b 100644
--- a/src/components/WhoCanReply.tsx
+++ b/src/components/WhoCanReply.tsx
@@ -17,7 +17,6 @@ import {HITSLOP_10} from '#/lib/constants'
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
import {logger} from '#/logger'
import {isNative} from '#/platform/detection'
-import {useModalControls} from '#/state/modals'
import {RQKEY_ROOT as POST_THREAD_RQKEY_ROOT} from '#/state/queries/post-thread'
import {
ThreadgateSetting,
@@ -34,6 +33,7 @@ import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe'
import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group'
import {Text} from '#/components/Typography'
import {TextLink} from '../view/com/util/Link'
+import {ThreadgateEditorDialog} from './dialogs/ThreadgateEditor'
import {PencilLine_Stroke2_Corner0_Rounded as PencilLine} from './icons/Pencil'
interface WhoCanReplyProps {
@@ -46,7 +46,15 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
const {_} = useLingui()
const t = useTheme()
const infoDialogControl = useDialogControl()
- const {settings, isRootPost, onPressEdit} = useWhoCanReply(post)
+ const editDialogControl = useDialogControl()
+ const agent = useAgent()
+ const queryClient = useQueryClient()
+
+ const settings = React.useMemo(
+ () => threadgateViewToSettings(post.threadgate),
+ [post],
+ )
+ const isRootPost = !('reply' in post.record)
if (!isRootPost) {
return null
@@ -63,6 +71,55 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
? _(msg`Replies disabled`)
: _(msg`Some people can reply`)
+ const onPressEdit = () => {
+ if (isNative && Keyboard.isVisible()) {
+ Keyboard.dismiss()
+ }
+ if (isThreadAuthor) {
+ editDialogControl.open()
+ } else {
+ infoDialogControl.open()
+ }
+ }
+
+ const onEditConfirm = async (newSettings: ThreadgateSetting[]) => {
+ if (JSON.stringify(settings) === JSON.stringify(newSettings)) {
+ return
+ }
+ try {
+ if (newSettings.length) {
+ await createThreadgate(agent, post.uri, newSettings)
+ } else {
+ await agent.api.com.atproto.repo.deleteRecord({
+ repo: agent.session!.did,
+ collection: 'app.bsky.feed.threadgate',
+ rkey: new AtUri(post.uri).rkey,
+ })
+ }
+ await whenAppViewReady(agent, post.uri, res => {
+ const thread = res.data.thread
+ if (AppBskyFeedDefs.isThreadViewPost(thread)) {
+ const fetchedSettings = threadgateViewToSettings(
+ thread.post.threadgate,
+ )
+ return JSON.stringify(fetchedSettings) === JSON.stringify(newSettings)
+ }
+ return false
+ })
+ Toast.show(_(msg`Thread settings updated`))
+ queryClient.invalidateQueries({
+ queryKey: [POST_THREAD_RQKEY_ROOT],
+ })
+ } catch (err) {
+ Toast.show(
+ _(
+ msg`There was an issue. Please check your internet connection and try again.`,
+ ),
+ )
+ logger.error('Failed to edit threadgate', {message: err})
+ }
+ }
+
return (
<>
-
+
+ {isThreadAuthor && (
+
+ )}
>
)
}
@@ -113,24 +181,31 @@ function Icon({
return
}
-export function WhoCanReplyDialog({
+function WhoCanReplyDialog({
control,
post,
+ settings,
}: {
control: Dialog.DialogControlProps
post: AppBskyFeedDefs.PostView
+ settings: ThreadgateSetting[]
}) {
return (
-
+
)
}
-function WhoCanReplyDialogInner({post}: {post: AppBskyFeedDefs.PostView}) {
+function WhoCanReplyDialogInner({
+ post,
+ settings,
+}: {
+ post: AppBskyFeedDefs.PostView
+ settings: ThreadgateSetting[]
+}) {
const {_} = useLingui()
- const {settings} = useWhoCanReply(post)
return (
, >
}
-function useWhoCanReply(post: AppBskyFeedDefs.PostView) {
- const agent = useAgent()
- const queryClient = useQueryClient()
- const {openModal} = useModalControls()
-
- const settings = React.useMemo(
- () => threadgateViewToSettings(post.threadgate),
- [post],
- )
- const isRootPost = !('reply' in post.record)
-
- const onPressEdit = () => {
- if (isNative && Keyboard.isVisible()) {
- Keyboard.dismiss()
- }
- openModal({
- name: 'threadgate',
- settings,
- async onConfirm(newSettings: ThreadgateSetting[]) {
- if (JSON.stringify(settings) === JSON.stringify(newSettings)) {
- return
- }
- try {
- if (newSettings.length) {
- await createThreadgate(agent, post.uri, newSettings)
- } else {
- await agent.api.com.atproto.repo.deleteRecord({
- repo: agent.session!.did,
- collection: 'app.bsky.feed.threadgate',
- rkey: new AtUri(post.uri).rkey,
- })
- }
- await whenAppViewReady(agent, post.uri, res => {
- const thread = res.data.thread
- if (AppBskyFeedDefs.isThreadViewPost(thread)) {
- const fetchedSettings = threadgateViewToSettings(
- thread.post.threadgate,
- )
- return (
- JSON.stringify(fetchedSettings) === JSON.stringify(newSettings)
- )
- }
- return false
- })
- Toast.show('Thread settings updated')
- queryClient.invalidateQueries({
- queryKey: [POST_THREAD_RQKEY_ROOT],
- })
- } catch (err) {
- Toast.show(
- 'There was an issue. Please check your internet connection and try again.',
- )
- logger.error('Failed to edit threadgate', {message: err})
- }
- },
- })
- }
-
- return {settings, isRootPost, onPressEdit}
-}
-
async function whenAppViewReady(
agent: BskyAgent,
uri: string,
diff --git a/src/components/dialogs/EmbedConsent.tsx b/src/components/dialogs/EmbedConsent.tsx
index c3fefd9f09..f7e6145975 100644
--- a/src/components/dialogs/EmbedConsent.tsx
+++ b/src/components/dialogs/EmbedConsent.tsx
@@ -113,6 +113,7 @@ export function EmbedConsentDialog({
+
)
diff --git a/src/components/dialogs/ThreadgateEditor.tsx b/src/components/dialogs/ThreadgateEditor.tsx
new file mode 100644
index 0000000000..75383764fc
--- /dev/null
+++ b/src/components/dialogs/ThreadgateEditor.tsx
@@ -0,0 +1,218 @@
+import React from 'react'
+import {StyleProp, View, ViewStyle} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import isEqual from 'lodash.isequal'
+
+import {useMyListsQuery} from '#/state/queries/my-lists'
+import {ThreadgateSetting} from '#/state/queries/threadgate'
+import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
+import * as Dialog from '#/components/Dialog'
+import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
+import {Text} from '#/components/Typography'
+
+interface ThreadgateEditorDialogProps {
+ control: Dialog.DialogControlProps
+ threadgate: ThreadgateSetting[]
+ onChange?: (v: ThreadgateSetting[]) => void
+ onConfirm?: (v: ThreadgateSetting[]) => void
+}
+
+export function ThreadgateEditorDialog({
+ control,
+ threadgate,
+ onChange,
+ onConfirm,
+}: ThreadgateEditorDialogProps) {
+ return (
+
+
+
+
+ )
+}
+
+function DialogContent({
+ seedThreadgate,
+ onChange,
+ onConfirm,
+}: {
+ seedThreadgate: ThreadgateSetting[]
+ onChange?: (v: ThreadgateSetting[]) => void
+ onConfirm?: (v: ThreadgateSetting[]) => void
+}) {
+ const {_} = useLingui()
+ const control = Dialog.useDialogContext()
+ const {data: lists} = useMyListsQuery('curate')
+ const [draft, setDraft] = React.useState(seedThreadgate)
+
+ const [prevSeedThreadgate, setPrevSeedThreadgate] =
+ React.useState(seedThreadgate)
+ if (seedThreadgate !== prevSeedThreadgate) {
+ // New data flowed from above (e.g. due to update coming through).
+ setPrevSeedThreadgate(seedThreadgate)
+ setDraft(seedThreadgate) // Reset draft.
+ }
+
+ function updateThreadgate(nextThreadgate: ThreadgateSetting[]) {
+ setDraft(nextThreadgate)
+ onChange?.(nextThreadgate)
+ }
+
+ const onPressEverybody = () => {
+ updateThreadgate([])
+ }
+
+ const onPressNobody = () => {
+ updateThreadgate([{type: 'nobody'}])
+ }
+
+ const onPressAudience = (setting: ThreadgateSetting) => {
+ // remove nobody
+ let newSelected = draft.filter(v => v.type !== 'nobody')
+ // toggle
+ const i = newSelected.findIndex(v => isEqual(v, setting))
+ if (i === -1) {
+ newSelected.push(setting)
+ } else {
+ newSelected.splice(i, 1)
+ }
+ updateThreadgate(newSelected)
+ }
+
+ const doneLabel = onConfirm ? _(msg`Save`) : _(msg`Done`)
+ return (
+
+
+
+ Chose who can reply
+
+
+ Either choose "Everybody" or "Nobody"
+
+
+
+ v.type === 'nobody')}
+ onPress={onPressNobody}
+ style={{flex: 1}}
+ />
+
+
+ Or combine these options:
+
+
+ v.type === 'mention')}
+ onPress={() => onPressAudience({type: 'mention'})}
+ />
+ v.type === 'following')}
+ onPress={() => onPressAudience({type: 'following'})}
+ />
+ {lists && lists.length > 0
+ ? lists.map(list => (
+ v.type === 'list' && v.list === list.uri)
+ }
+ onPress={() =>
+ onPressAudience({type: 'list', list: list.uri})
+ }
+ />
+ ))
+ : // No loading states to avoid jumps for the common case (no lists)
+ null}
+
+
+
+
+
+ )
+}
+
+function Selectable({
+ label,
+ isSelected,
+ onPress,
+ style,
+}: {
+ label: string
+ isSelected: boolean
+ onPress: () => void
+ style?: StyleProp
+}) {
+ const t = useTheme()
+ return (
+
+ )
+}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index e0b8998007..0efaed44dd 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -13,6 +13,15 @@ export const EMBED_SERVICE = 'https://embed.bsky.app'
export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download'
+// HACK
+// Yes, this is exactly what it looks like. It's a hard-coded constant
+// reflecting the number of new users in the last week. We don't have
+// time to add a route to the servers for this so we're just going to hard
+// code and update this number with each release until we can get the
+// server route done.
+// -prf
+export const JOINED_THIS_WEEK = 37115 // as of June24 2024
+
const BASE_FEEDBACK_FORM_URL = `${HELP_DESK_URL}/requests/new`
export function FEEDBACK_FORM_URL({
email,
diff --git a/src/locale/locales/ca/messages.po b/src/locale/locales/ca/messages.po
index 93d004f00c..6ec1268338 100644
--- a/src/locale/locales/ca/messages.po
+++ b/src/locale/locales/ca/messages.po
@@ -18,7 +18,7 @@ msgstr ""
#: src/screens/Messages/List/ChatListItem.tsx:120
msgid "(contains embedded content)"
-msgstr ""
+msgstr "(té contingut incrustat)"
#: src/view/com/modals/VerifyEmail.tsx:150
msgid "(no email)"
@@ -113,7 +113,7 @@ msgstr ""
#: src/view/com/util/UserAvatar.tsx:419
msgid "{0}'s avatar"
-msgstr ""
+msgstr "Avatar de {0}"
#: src/screens/StarterPack/Wizard/StepDetails.tsx:68
msgid "{0}'s favorite feeds and people - join me!"
@@ -505,7 +505,7 @@ msgstr "Tots els canals que has desat, en un sol lloc."
#: src/view/com/modals/AddAppPasswords.tsx:187
#: src/view/com/modals/AddAppPasswords.tsx:194
msgid "Allow access to your direct messages"
-msgstr ""
+msgstr "Permet l'accés als teus missatges directes"
#: src/screens/Messages/Settings.tsx:61
#: src/screens/Messages/Settings.tsx:64
@@ -515,7 +515,7 @@ msgstr ""
#: src/screens/Messages/Settings.tsx:62
#: src/screens/Messages/Settings.tsx:65
msgid "Allow new messages from"
-msgstr ""
+msgstr "Permet missatges nou de"
#: src/screens/Login/ForgotPasswordForm.tsx:178
#: src/view/com/modals/ChangePassword.tsx:171
@@ -1039,7 +1039,7 @@ msgstr "Cancel·la la citació de la publicació"
#: src/screens/Deactivated.tsx:155
msgid "Cancel reactivation and log out"
-msgstr ""
+msgstr "Cancel·la la reactivació i surt"
#: src/view/com/modals/ListAddRemoveUsers.tsx:87
#: src/view/shell/desktop/Search.tsx:214
@@ -1118,7 +1118,7 @@ msgstr "Configuració del xat"
#: src/screens/Messages/Settings.tsx:59
#: src/view/screens/Settings/index.tsx:647
msgid "Chat Settings"
-msgstr ""
+msgstr "Configuració del xat"
#: src/components/dms/ConvoMenu.tsx:84
msgid "Chat unmuted"
@@ -1221,11 +1221,11 @@ msgstr "clica aquí"
#: src/view/com/modals/DeleteAccount.tsx:208
msgid "Click here for more information on deactivating your account"
-msgstr ""
+msgstr "Clica aquí per a més informació sobre desactivar el teu compte"
#: src/view/com/modals/DeleteAccount.tsx:216
msgid "Click here for more information."
-msgstr ""
+msgstr "Clica aquí per a més informació."
#: src/screens/Feeds/NoFollowingFeed.tsx:46
#~ msgid "Click here to add one."
@@ -1325,7 +1325,7 @@ msgstr "Tanca la visualització de la imatge de la capçalera"
#: src/view/com/notifications/FeedItem.tsx:226
msgid "Collapse list of users"
-msgstr ""
+msgstr "Plega la llista d'usuaris"
#: src/view/com/notifications/FeedItem.tsx:426
msgid "Collapses list of users for a given notification"
@@ -1744,11 +1744,11 @@ msgstr "Data de naixement"
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:73
#: src/view/screens/Settings/index.tsx:806
msgid "Deactivate account"
-msgstr ""
+msgstr "Desactiva el compte"
#: src/view/screens/Settings/index.tsx:818
msgid "Deactivate my account"
-msgstr ""
+msgstr "Desactiva el meu compte"
#: src/view/screens/Settings/index.tsx:873
msgid "Debug Moderation"
@@ -2402,7 +2402,7 @@ msgstr "Expandeix el text alternatiu"
#: src/view/com/notifications/FeedItem.tsx:227
msgid "Expand list of users"
-msgstr ""
+msgstr "Expandeix la llista d'usuaris"
#: src/view/com/composer/ComposerReplyTo.tsx:82
#: src/view/com/composer/ComposerReplyTo.tsx:85
@@ -2679,7 +2679,7 @@ msgstr "Segueix {0}"
#: src/view/com/posts/AviFollowButton.tsx:71
msgid "Follow {name}"
-msgstr ""
+msgstr "Segueix a {name}"
#: src/view/com/profile/ProfileMenu.tsx:246
#: src/view/com/profile/ProfileMenu.tsx:257
@@ -2782,7 +2782,7 @@ msgstr "Seguint {0}"
#: src/view/com/posts/AviFollowButton.tsx:53
msgid "Following {name}"
-msgstr ""
+msgstr "Seguint a {name}"
#: src/view/screens/Settings/index.tsx:573
msgid "Following feed preferences"
@@ -3145,7 +3145,7 @@ msgstr "Si vols canviar la contrasenya t'enviarem un codi per a verificar que aq
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:92
msgid "If you're trying to change your handle or email, do so before you deactivate."
-msgstr ""
+msgstr "Si vols canviar el teu identificador o el correu fes-ho abans de desactivar el compte."
#: src/lib/moderation/useReportOptions.ts:38
msgid "Illegal and Urgent"
@@ -3622,7 +3622,7 @@ msgstr "Registre"
#: src/screens/Deactivated.tsx:214
#: src/screens/Deactivated.tsx:220
msgid "Log in or sign up"
-msgstr ""
+msgstr "Inicia sessió o registra't"
#: src/screens/SignupQueued.tsx:155
#: src/screens/SignupQueued.tsx:158
@@ -4380,7 +4380,7 @@ msgstr "Obre"
#: src/view/com/posts/AviFollowButton.tsx:89
msgid "Open {name} profile shortcut menu"
-msgstr ""
+msgstr "Obre el menú de drecera del perfil {name}"
#: src/screens/Onboarding/StepProfile/index.tsx:277
msgid "Open avatar creator"
@@ -4463,7 +4463,7 @@ msgstr "Obre la càmera del dispositiu"
#: src/view/screens/Settings/index.tsx:639
msgid "Opens chat settings"
-msgstr ""
+msgstr "Obre la configuració del xat"
#: src/view/com/composer/Prompt.tsx:27
msgid "Opens composer"
@@ -4517,7 +4517,7 @@ msgstr "Obre la llista de codis d'invitació"
#: src/view/screens/Settings/index.tsx:808
msgid "Opens modal for account deactivation confirmation"
-msgstr ""
+msgstr "Obre el modal per a la confirmació de la desactivació del compte"
#: src/view/screens/Settings/index.tsx:830
msgid "Opens modal for account deletion confirmation. Requires email code"
@@ -4604,7 +4604,7 @@ msgstr "Obre les preferències dels fils de debat"
#: src/view/com/notifications/FeedItem.tsx:513
#: src/view/com/util/UserAvatar.tsx:422
msgid "Opens this profile"
-msgstr ""
+msgstr "Obre aquest perfil"
#: src/view/com/util/forms/DropdownButton.tsx:293
msgid "Option {0} of {numItems}"
@@ -4621,11 +4621,11 @@ msgstr "O combina aquestes opcions:"
#: src/screens/Deactivated.tsx:211
msgid "Or, continue with another account."
-msgstr ""
+msgstr "O continua amb un altre compte."
#: src/screens/Deactivated.tsx:194
msgid "Or, log into one of your other accounts."
-msgstr ""
+msgstr "O inicia sessió en un altre dels teus comptes."
#: src/lib/moderation/useReportOptions.ts:27
msgid "Other"
@@ -5067,7 +5067,7 @@ msgstr "Proporcions"
#: src/screens/Deactivated.tsx:144
msgid "Reactivate your account"
-msgstr ""
+msgstr "Torna a activar el teu compte"
#: src/components/dms/ReportDialog.tsx:174
msgid "Reason:"
@@ -5129,7 +5129,7 @@ msgstr "Elimina el bàner"
#: src/screens/Messages/Conversation/MessageInputEmbed.tsx:218
msgid "Remove embed"
-msgstr ""
+msgstr "Elimina l'incrustat"
#: src/view/com/posts/FeedErrorMessage.tsx:168
#: src/view/com/posts/FeedShutdownMsg.tsx:113
@@ -5168,11 +5168,11 @@ msgstr "Elimina la paraula silenciada de la teva llista"
#: src/view/screens/Search/Search.tsx:974
msgid "Remove profile"
-msgstr ""
+msgstr "Elimina el perfil"
#: src/view/screens/Search/Search.tsx:976
msgid "Remove profile from search history"
-msgstr ""
+msgstr "Elimina el perfil de l'historial de cerca"
#: src/view/com/util/post-embeds/QuoteEmbed.tsx:238
msgid "Remove quote"
@@ -5868,7 +5868,7 @@ msgstr "Envia el missatge"
#: src/components/dms/dialogs/ShareViaChatDialog.tsx:59
msgid "Send post to..."
-msgstr ""
+msgstr "Envia el missatge a..."
#: src/components/dms/ReportDialog.tsx:234
#: src/components/dms/ReportDialog.tsx:237
@@ -5893,7 +5893,7 @@ msgstr "Envia un correu de verificació"
#: src/view/com/util/forms/PostDropdownBtn.tsx:296
#: src/view/com/util/forms/PostDropdownBtn.tsx:299
msgid "Send via direct message"
-msgstr ""
+msgstr "Envia per missatge directe"
#: src/view/com/modals/DeleteAccount.tsx:151
msgid "Sends email with confirmation code for account deletion"
@@ -6143,7 +6143,7 @@ msgstr "Mostra seguidors semblants a {0}"
#: src/view/com/post-thread/PostThreadShowHiddenReplies.tsx:23
msgid "Show hidden replies"
-msgstr ""
+msgstr "Mostra les respostes ocultes"
#: src/view/com/util/forms/PostDropdownBtn.tsx:346
#: src/view/com/util/forms/PostDropdownBtn.tsx:348
@@ -6163,7 +6163,7 @@ msgstr "Mostra'n més com aquest"
#: src/view/com/post-thread/PostThreadShowHiddenReplies.tsx:23
msgid "Show muted replies"
-msgstr ""
+msgstr "Mostra les respostes silenciades"
#: src/view/screens/PreferencesFollowingFeed.tsx:257
msgid "Show Posts from My Feeds"
@@ -6371,7 +6371,7 @@ msgstr "Alguna cosa ha fallat"
#: src/screens/Deactivated.tsx:94
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:59
msgid "Something went wrong, please try again"
-msgstr ""
+msgstr "Alguna cosa ha fallat, torna-ho a provar"
#: src/components/ReportDialog/index.tsx:59
#: src/screens/Moderation/index.tsx:114
@@ -6715,7 +6715,7 @@ msgstr "Les condicions del servei han estat traslladades a"
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:86
msgid "There is no time limit for account deactivation, come back any time."
-msgstr ""
+msgstr "No hi ha límit de temps per a la desactivació del compte, torna quan vulguis."
#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:115
#: src/view/screens/ProfileFeed.tsx:542
@@ -7517,7 +7517,7 @@ msgstr "Veure l'avatar de {0}"
#: src/view/com/notifications/FeedItem.tsx:234
msgid "View {0}'s profile"
-msgstr ""
+msgstr "Veure el perfil de {0}"
#: src/components/ProfileHoverCard/index.web.tsx:430
msgid "View blocked user's profile"
@@ -7682,7 +7682,7 @@ msgstr ""
#: src/screens/Deactivated.tsx:128
msgid "Welcome back!"
-msgstr ""
+msgstr "Bentornat!"
#: src/view/com/auth/onboarding/WelcomeMobile.tsx:48
#~ msgid "Welcome to <0>Bluesky0>"
@@ -7808,7 +7808,7 @@ msgstr "Sí"
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:106
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:108
msgid "Yes, deactivate"
-msgstr ""
+msgstr "Sí, desactiva'l"
#: src/screens/StarterPack/StarterPackScreen.tsx:525
msgid "Yes, delete this starter pack"
@@ -7816,7 +7816,7 @@ msgstr ""
#: src/screens/Deactivated.tsx:150
msgid "Yes, reactivate my account"
-msgstr ""
+msgstr "Sí, torna a activar el meu compte"
#: src/components/dms/MessageItem.tsx:188
msgid "Yesterday, {time}"
@@ -7841,7 +7841,7 @@ msgstr "També pots descobrir nous canals personalitzats per a seguir."
#: src/view/com/modals/DeleteAccount.tsx:202
msgid "You can also temporarily deactivate your account instead, and reactivate it at any time."
-msgstr ""
+msgstr "També pots desactivar el teu compte temporalment i reactivar-lo en qualsevol moment."
#: src/view/com/auth/create/Step1.tsx:106
#~ msgid "You can change hosting providers at any time."
@@ -7857,7 +7857,7 @@ msgstr "Pots canviar-ho quan vulguis."
#: src/screens/Messages/Settings.tsx:111
msgid "You can continue ongoing conversations regardless of which setting you choose."
-msgstr ""
+msgstr "Pots continuar les converses en curs independentment de la configuració que triïs."
#: src/screens/Login/index.tsx:158
#: src/screens/Login/PasswordUpdatedForm.tsx:33
@@ -7866,7 +7866,7 @@ msgstr "Ara pots iniciar sessió amb la nova contrasenya."
#: src/screens/Deactivated.tsx:136
msgid "You can reactivate your account to continue logging in. Your profile and posts will be visible to other users."
-msgstr ""
+msgstr "Pots reactivar el teu compte per continuar iniciant la sessió. El teu perfil i les publicacions seran visibles per a altres usuaris."
#: src/view/com/profile/ProfileFollowers.tsx:86
msgid "You do not have any followers."
@@ -8025,7 +8025,7 @@ msgstr "Has d'escollir almenys un etiquetador per a un informe"
#: src/screens/Deactivated.tsx:131
msgid "You previously deactivated @{0}."
-msgstr ""
+msgstr "Abans has desactivat @{0}."
#: src/view/com/util/forms/PostDropdownBtn.tsx:174
msgid "You will no longer receive notifications for this thread"
@@ -8045,11 +8045,11 @@ msgstr "Tu: {0}"
#: src/screens/Messages/List/ChatListItem.tsx:143
msgid "You: {defaultEmbeddedContentMessage}"
-msgstr ""
+msgstr "Tu: {defaultEmbeddedContentMessage}"
#: src/screens/Messages/List/ChatListItem.tsx:136
msgid "You: {short}"
-msgstr ""
+msgstr "Tu: {short}"
#: src/screens/Signup/index.tsx:169
msgid "You'll follow the suggested users and feeds once you finish creating your account!"
@@ -8084,7 +8084,7 @@ msgstr "Estàs a la cua"
#: src/screens/Deactivated.tsx:89
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:54
msgid "You're logged in with an App Password. Please log in with your main password to continue deactivating your account."
-msgstr ""
+msgstr "Has iniciat sessió amb una contrasenya d'aplicació. Inicia sessió amb la teva contrasenya principal per continuar la desactivació del teu compte."
#: src/screens/Onboarding/StepFinished.tsx:228
msgid "You're ready to go!"
@@ -8189,7 +8189,7 @@ msgstr "El teu perfil"
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:75
msgid "Your profile, posts, feeds, and lists will no longer be visible to other Bluesky users. You can reactivate your account at any time by logging in."
-msgstr ""
+msgstr "El teu perfil, publicacions, fonts i llistes ja no seran visibles per a altres usuaris de Bluesky. Pots reactivar el teu compte en qualsevol moment iniciant sessió."
#: src/view/com/composer/Composer.tsx:365
msgid "Your reply has been published"
diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx
index c7a459659f..9613ce660d 100644
--- a/src/screens/Onboarding/StepFinished.tsx
+++ b/src/screens/Onboarding/StepFinished.tsx
@@ -110,8 +110,8 @@ export function StepFinished() {
// Any starter pack feeds will be pinned _after_ the defaults
if (starterPack && starterPack.feeds?.length) {
- feedsToSave.concat(
- starterPack.feeds.map(f => ({
+ feedsToSave.push(
+ ...starterPack.feeds.map(f => ({
type: 'feed',
value: f.uri,
pinned: true,
diff --git a/src/screens/Profile/Header/Handle.tsx b/src/screens/Profile/Header/Handle.tsx
index 268b7350f8..0344f1a234 100644
--- a/src/screens/Profile/Header/Handle.tsx
+++ b/src/screens/Profile/Header/Handle.tsx
@@ -5,7 +5,7 @@ import {Trans} from '@lingui/macro'
import {Shadow} from '#/state/cache/types'
import {isInvalidHandle} from 'lib/strings/handles'
-import {isAndroid} from 'platform/detection'
+import {isIOS} from 'platform/detection'
import {atoms as a, useTheme, web} from '#/alf'
import {NewskieDialog} from '#/components/NewskieDialog'
import {Text} from '#/components/Typography'
@@ -23,7 +23,7 @@ export function ProfileHeaderHandle({
return (
+ pointerEvents={disableTaps ? 'none' : isIOS ? 'auto' : 'box-none'}>
{profile.viewer?.followedBy && !blockHide ? (
diff --git a/src/screens/StarterPack/StarterPackLandingScreen.tsx b/src/screens/StarterPack/StarterPackLandingScreen.tsx
index 6e240d06f6..2b450494b8 100644
--- a/src/screens/StarterPack/StarterPackLandingScreen.tsx
+++ b/src/screens/StarterPack/StarterPackLandingScreen.tsx
@@ -11,6 +11,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {JOINED_THIS_WEEK} from '#/lib/constants'
import {isAndroidWeb} from 'lib/browser'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {createStarterPackGooglePlayUri} from 'lib/strings/starter-pack'
@@ -21,6 +22,7 @@ import {
useActiveStarterPack,
useSetActiveStarterPack,
} from 'state/shell/starter-pack'
+import {formatCount} from '#/view/com/util/numeric/format'
import {LoggedOutScreenState} from 'view/com/auth/LoggedOut'
import {CenteredView} from 'view/com/util/Views'
import {Logo} from 'view/icons/Logo'
@@ -95,7 +97,7 @@ function LandingScreenLoaded({
setScreenState: (state: LoggedOutScreenState) => void
moderationOpts: ModerationOpts
}) {
- const {record, creator, listItemsSample, feeds, joinedWeekCount} = starterPack
+ const {record, creator, listItemsSample, feeds} = starterPack
const {_} = useLingui()
const t = useTheme()
const activeStarterPack = useActiveStarterPack()
@@ -200,24 +202,22 @@ function LandingScreenLoaded({
Join Bluesky
- {joinedWeekCount && joinedWeekCount >= 25 ? (
-
-
-
- 123,659 joined this week
-
-
- ) : null}
+
+
+
+ {formatCount(JOINED_THIS_WEEK)} joined this week
+
+
{Boolean(listItemsSample?.length) && (
@@ -231,18 +231,26 @@ function LandingScreenLoaded({
)}
-
+
{starterPack.listItemsSample
?.filter(p => !p.subject.associated?.labeler)
.slice(0, 8)
- .map(item => (
+ .map((item, i) => (
You'll stay updated with these feeds
-
- {feeds?.map(feed => (
+
+ {feeds?.map((feed, i) => (
diff --git a/src/screens/StarterPack/StarterPackScreen.tsx b/src/screens/StarterPack/StarterPackScreen.tsx
index 46ce252364..d89bda1371 100644
--- a/src/screens/StarterPack/StarterPackScreen.tsx
+++ b/src/screens/StarterPack/StarterPackScreen.tsx
@@ -7,6 +7,7 @@ import {
AppBskyGraphStarterpack,
AtUri,
ModerationOpts,
+ RichText as RichTextAPI,
} from '@atproto/api'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
@@ -52,6 +53,7 @@ import {Loader} from '#/components/Loader'
import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
+import {RichText} from '#/components/RichText'
import {FeedsList} from '#/components/StarterPack/Main/FeedsList'
import {ProfilesList} from '#/components/StarterPack/Main/ProfilesList'
import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog'
@@ -280,6 +282,13 @@ function Header({
return null
}
+ const richText = record.description
+ ? new RichTextAPI({
+ text: record.description,
+ facets: record.descriptionFacets,
+ })
+ : undefined
+
return (
<>
- {record.description || joinedAllTimeCount >= 25 ? (
+ {richText || joinedAllTimeCount >= 25 ? (
- {record.description ? (
-
- {record.description}
-
+ {richText ? (
+
) : null}
{joinedAllTimeCount >= 25 ? (
diff --git a/src/screens/StarterPack/Wizard/StepFeeds.tsx b/src/screens/StarterPack/Wizard/StepFeeds.tsx
index 5170edc6ef..878d17ce01 100644
--- a/src/screens/StarterPack/Wizard/StepFeeds.tsx
+++ b/src/screens/StarterPack/Wizard/StepFeeds.tsx
@@ -32,7 +32,7 @@ export function StepFeeds({moderationOpts}: {moderationOpts: ModerationOpts}) {
const throttledQuery = useThrottledValue(query, 500)
const {screenReaderEnabled} = useA11y()
- const {data: savedFeedsAndLists, isLoading: isLoadingSavedFeeds} =
+ const {data: savedFeedsAndLists, isFetchedAfterMount: isFetchedSavedFeeds} =
useSavedFeeds()
const savedFeeds = savedFeedsAndLists?.feeds
.filter(f => f.type === 'feed' && f.view.uri !== DISCOVER_FEED_URI)
@@ -46,15 +46,23 @@ export function StepFeeds({moderationOpts}: {moderationOpts: ModerationOpts}) {
limit: 30,
})
const popularFeeds = popularFeedsPages?.pages.flatMap(p => p.feeds) ?? []
- const suggestedFeeds = savedFeeds.concat(
- popularFeeds.filter(f => !savedFeeds.some(sf => sf.uri === f.uri)),
- )
+
+ // If we have saved feeds already loaded, display them immediately
+ // Then, when popular feeds have loaded we can concat them to the saved feeds
+ const suggestedFeeds =
+ savedFeeds || isFetchedSavedFeeds
+ ? popularFeeds
+ ? savedFeeds.concat(
+ popularFeeds.filter(f => !savedFeeds.some(sf => sf.uri === f.uri)),
+ )
+ : savedFeeds
+ : undefined
const {data: searchedFeeds, isFetching: isFetchingSearchedFeeds} =
useSearchPopularFeedsQuery({q: throttledQuery})
const isLoading =
- isLoadingSavedFeeds || isLoadingPopularFeeds || isFetchingSearchedFeeds
+ !isFetchedSavedFeeds || isLoadingPopularFeeds || isFetchingSearchedFeeds
const renderItem = ({
item,
diff --git a/src/screens/StarterPack/Wizard/index.tsx b/src/screens/StarterPack/Wizard/index.tsx
index fd16fd20ae..b231e317e3 100644
--- a/src/screens/StarterPack/Wizard/index.tsx
+++ b/src/screens/StarterPack/Wizard/index.tsx
@@ -245,7 +245,6 @@ function WizardInner({
editStarterPack({
name: state.name?.trim() || getDefaultName(),
description: state.description?.trim(),
- descriptionFacets: [],
profiles: state.profiles,
feeds: state.feeds,
currentStarterPack: currentStarterPack,
@@ -255,7 +254,6 @@ function WizardInner({
createStarterPack({
name: state.name?.trim() || getDefaultName(),
description: state.description?.trim(),
- descriptionFacets: [],
profiles: state.profiles,
feeds: state.feeds,
})
diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx
index 685b10bd85..529dc55907 100644
--- a/src/state/modals/index.tsx
+++ b/src/state/modals/index.tsx
@@ -5,7 +5,6 @@ import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {GalleryModel} from '#/state/models/media/gallery'
import {ImageModel} from '#/state/models/media/image'
-import {ThreadgateSetting} from '../queries/threadgate'
export interface EditProfileModal {
name: 'edit-profile'
@@ -67,13 +66,6 @@ export interface SelfLabelModal {
onChange: (labels: string[]) => void
}
-export interface ThreadgateModal {
- name: 'threadgate'
- settings: ThreadgateSetting[]
- onChange?: (settings: ThreadgateSetting[]) => void
- onConfirm?: (settings: ThreadgateSetting[]) => void
-}
-
export interface ChangeHandleModal {
name: 'change-handle'
onChanged: () => void
@@ -149,7 +141,6 @@ export type Modal =
| CropImageModal
| EditImageModal
| SelfLabelModal
- | ThreadgateModal
// Bluesky access
| WaitlistModal
diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts
index 241bc6419c..ca7fa2d0ce 100644
--- a/src/state/queries/starter-packs.ts
+++ b/src/state/queries/starter-packs.ts
@@ -4,8 +4,10 @@ import {
AppBskyGraphDefs,
AppBskyGraphGetStarterPack,
AppBskyGraphStarterpack,
+ AppBskyRichtextFacet,
AtUri,
BskyAgent,
+ RichText,
} from '@atproto/api'
import {StarterPackView} from '@atproto/api/dist/client/types/app/bsky/graph/defs'
import {
@@ -80,7 +82,6 @@ export async function invalidateStarterPack({
interface UseCreateStarterPackMutationParams {
name: string
description?: string
- descriptionFacets: []
profiles: AppBskyActorDefs.ProfileViewBasic[]
feeds?: AppBskyFeedDefs.GeneratorView[]
}
@@ -100,16 +101,33 @@ export function useCreateStarterPackMutation({
Error,
UseCreateStarterPackMutationParams
>({
- mutationFn: async params => {
+ mutationFn: async ({name, description, feeds, profiles}) => {
+ let descriptionFacets: AppBskyRichtextFacet.Main[] | undefined
+ if (description) {
+ const rt = new RichText({text: description})
+ await rt.detectFacets(agent)
+ descriptionFacets = rt.facets
+ }
+
let listRes
- listRes = await createStarterPackList({...params, agent})
+ listRes = await createStarterPackList({
+ name,
+ description,
+ profiles,
+ descriptionFacets,
+ agent,
+ })
+
return await agent.app.bsky.graph.starterpack.create(
{
repo: agent.session?.did,
},
{
- ...params,
+ name,
+ description,
+ descriptionFacets,
list: listRes?.uri,
+ feeds,
createdAt: new Date().toISOString(),
},
)
@@ -148,16 +166,20 @@ export function useEditStarterPackMutation({
currentListItems: AppBskyGraphDefs.ListItemView[]
}
>({
- mutationFn: async params => {
- const {
- name,
- description,
- descriptionFacets,
- feeds,
- profiles,
- currentStarterPack,
- currentListItems,
- } = params
+ mutationFn: async ({
+ name,
+ description,
+ feeds,
+ profiles,
+ currentStarterPack,
+ currentListItems,
+ }) => {
+ let descriptionFacets: AppBskyRichtextFacet.Main[] | undefined
+ if (description) {
+ const rt = new RichText({text: description})
+ await rt.detectFacets(agent)
+ descriptionFacets = rt.facets
+ }
if (!AppBskyGraphStarterpack.isRecord(currentStarterPack.record)) {
throw new Error('Invalid starter pack')
diff --git a/src/view/com/composer/threadgate/ThreadgateBtn.tsx b/src/view/com/composer/threadgate/ThreadgateBtn.tsx
index 2aefdfbbf3..6cf2eea2c4 100644
--- a/src/view/com/composer/threadgate/ThreadgateBtn.tsx
+++ b/src/view/com/composer/threadgate/ThreadgateBtn.tsx
@@ -5,11 +5,12 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isNative} from '#/platform/detection'
-import {useModalControls} from '#/state/modals'
import {ThreadgateSetting} from '#/state/queries/threadgate'
import {useAnalytics} from 'lib/analytics/analytics'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import * as Dialog from '#/components/Dialog'
+import {ThreadgateEditorDialog} from '#/components/dialogs/ThreadgateEditor'
import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign'
import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe'
import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group'
@@ -26,18 +27,15 @@ export function ThreadgateBtn({
const {track} = useAnalytics()
const {_} = useLingui()
const t = useTheme()
- const {openModal} = useModalControls()
+ const control = Dialog.useDialogControl()
const onPress = () => {
track('Composer:ThreadgateOpened')
if (isNative && Keyboard.isVisible()) {
Keyboard.dismiss()
}
- openModal({
- name: 'threadgate',
- settings: threadgate,
- onChange,
- })
+
+ control.open()
}
const isEverybody = threadgate.length === 0
@@ -49,19 +47,29 @@ export function ThreadgateBtn({
: _(msg`Some people can reply`)
return (
-
-
-
+ <>
+
+
+
+
+ >
)
}
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index ecfe5806ef..3455e1cdf8 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -23,7 +23,6 @@ import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettin
import * as LinkWarningModal from './LinkWarning'
import * as ListAddUserModal from './ListAddRemoveUsers'
import * as SelfLabelModal from './SelfLabel'
-import * as ThreadgateModal from './Threadgate'
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
import * as VerifyEmailModal from './VerifyEmail'
@@ -76,9 +75,6 @@ export function ModalsContainer() {
} else if (activeModal?.name === 'self-label') {
snapPoints = SelfLabelModal.snapPoints
element =
- } else if (activeModal?.name === 'threadgate') {
- snapPoints = ThreadgateModal.snapPoints
- element =
} else if (activeModal?.name === 'alt-text-image') {
snapPoints = AltImageModal.snapPoints
element =
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 14ee99e576..c4bab6fb18 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -23,7 +23,6 @@ import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettin
import * as LinkWarningModal from './LinkWarning'
import * as ListAddUserModal from './ListAddRemoveUsers'
import * as SelfLabelModal from './SelfLabel'
-import * as ThreadgateModal from './Threadgate'
import * as UserAddRemoveLists from './UserAddRemoveLists'
import * as VerifyEmailModal from './VerifyEmail'
@@ -84,8 +83,6 @@ function Modal({modal}: {modal: ModalIface}) {
element =
} else if (modal.name === 'self-label') {
element =
- } else if (modal.name === 'threadgate') {
- element =
} else if (modal.name === 'change-handle') {
element =
} else if (modal.name === 'invite-codes') {
diff --git a/src/view/com/modals/Threadgate.tsx b/src/view/com/modals/Threadgate.tsx
deleted file mode 100644
index 4a9a9e2ab5..0000000000
--- a/src/view/com/modals/Threadgate.tsx
+++ /dev/null
@@ -1,208 +0,0 @@
-import React, {useState} from 'react'
-import {
- Pressable,
- StyleProp,
- StyleSheet,
- TouchableOpacity,
- View,
- ViewStyle,
-} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import isEqual from 'lodash.isequal'
-
-import {useModalControls} from '#/state/modals'
-import {useMyListsQuery} from '#/state/queries/my-lists'
-import {ThreadgateSetting} from '#/state/queries/threadgate'
-import {usePalette} from 'lib/hooks/usePalette'
-import {colors, s} from 'lib/styles'
-import {isWeb} from 'platform/detection'
-import {ScrollView} from 'view/com/modals/util'
-import {Text} from '../util/text/Text'
-
-export const snapPoints = ['60%']
-
-export function Component({
- settings,
- onChange,
- onConfirm,
-}: {
- settings: ThreadgateSetting[]
- onChange?: (settings: ThreadgateSetting[]) => void
- onConfirm?: (settings: ThreadgateSetting[]) => void
-}) {
- const pal = usePalette('default')
- const {closeModal} = useModalControls()
- const [selected, setSelected] = useState(settings)
- const {_} = useLingui()
- const {data: lists} = useMyListsQuery('curate')
-
- const onPressEverybody = () => {
- setSelected([])
- onChange?.([])
- }
-
- const onPressNobody = () => {
- setSelected([{type: 'nobody'}])
- onChange?.([{type: 'nobody'}])
- }
-
- const onPressAudience = (setting: ThreadgateSetting) => {
- // remove nobody
- let newSelected = selected.filter(v => v.type !== 'nobody')
- // toggle
- const i = newSelected.findIndex(v => isEqual(v, setting))
- if (i === -1) {
- newSelected.push(setting)
- } else {
- newSelected.splice(i, 1)
- }
- setSelected(newSelected)
- onChange?.(newSelected)
- }
-
- return (
-
-
-
- Who can reply
-
-
-
-
-
- Choose "Everybody" or "Nobody"
-
-
-
- v.type === 'nobody')}
- onPress={onPressNobody}
- style={{flex: 1}}
- />
-
-
- Or combine these options:
-
-
- v.type === 'mention')}
- onPress={() => onPressAudience({type: 'mention'})}
- />
- v.type === 'following')}
- onPress={() => onPressAudience({type: 'following'})}
- />
- {lists?.length
- ? lists.map(list => (
- v.type === 'list' && v.list === list.uri,
- )
- }
- onPress={() =>
- onPressAudience({type: 'list', list: list.uri})
- }
- />
- ))
- : null}
-
-
-
-
- {
- closeModal()
- onConfirm?.(selected)
- }}
- style={styles.btn}
- accessibilityRole="button"
- accessibilityLabel={_(msg({message: `Done`, context: 'action'}))}
- accessibilityHint="">
-
- Done
-
-
-
-
- )
-}
-
-function Selectable({
- label,
- isSelected,
- onPress,
- style,
-}: {
- label: string
- isSelected: boolean
- onPress: () => void
- style?: StyleProp
-}) {
- const pal = usePalette(isSelected ? 'inverted' : 'default')
- return (
-
-
- {label}
-
- {isSelected ? (
-
- ) : null}
-
- )
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- paddingBottom: isWeb ? 0 : 40,
- },
- titleSection: {
- paddingTop: isWeb ? 0 : 4,
- },
- title: {
- textAlign: 'center',
- fontWeight: '600',
- },
- description: {
- textAlign: 'center',
- paddingVertical: 16,
- },
- selectable: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- paddingHorizontal: 18,
- paddingVertical: 16,
- borderWidth: 1,
- borderRadius: 6,
- },
- btn: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- borderRadius: 32,
- padding: 14,
- backgroundColor: colors.blue3,
- },
- btnContainer: {
- paddingTop: 20,
- paddingHorizontal: 20,
- },
-})