diff --git a/src/App.native.tsx b/src/App.native.tsx index 113caa7068..a3918b855e 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -16,8 +16,6 @@ import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController' -import {isIOS, isAndroid} from '#/platform/detection' -import {RC_APPLE_PUBLIC_KEY, RC_GOOGLE_PUBLIC_KEY} from '#/env' import {QueryProvider} from '#/lib/react-query' import { initialize, @@ -28,6 +26,7 @@ import {s} from '#/lib/styles' import {ThemeProvider} from '#/lib/ThemeContext' import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' +import {isAndroid,isIOS} from '#/platform/detection' import {Provider as A11yProvider} from '#/state/a11y' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as DialogStateProvider} from '#/state/dialogs' @@ -72,6 +71,7 @@ import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' import {Provider as PortalProvider} from '#/components/Portal' import {AppProfiler} from '#/AppProfiler' +import {RC_APPLE_PUBLIC_KEY, RC_GOOGLE_PUBLIC_KEY} from '#/env' import {Splash} from '#/Splash' import {BottomSheetProvider} from '../modules/bottom-sheet' import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' @@ -187,6 +187,8 @@ function App() { }, ) + Purchases.setLogLevel(Purchases.LOG_LEVEL.DEBUG) + if (isIOS) { Purchases.configure({apiKey: RC_APPLE_PUBLIC_KEY}) } else if (isAndroid) { diff --git a/src/alf/tokens.ts b/src/alf/tokens.ts index 453f2c3c02..dc0675dc1b 100644 --- a/src/alf/tokens.ts +++ b/src/alf/tokens.ts @@ -108,7 +108,7 @@ export const gradients = { nordic: { values: [ [0, '#083367'], - [0.4, '#386D84'], + // [0.4, '#386D84'], [1, '#9EE8C1'], ], hover_value: '#3A7085', diff --git a/src/components/GradientFill.tsx b/src/components/GradientFill.tsx index ef86b57044..1940571822 100644 --- a/src/components/GradientFill.tsx +++ b/src/components/GradientFill.tsx @@ -1,12 +1,13 @@ import {useMemo} from 'react' import {LinearGradient} from 'expo-linear-gradient' -import {atoms as a, tokens} from '#/alf' +import {atoms as a, tokens, ViewStyleProp} from '#/alf' export function GradientFill({ gradient, rotate = '0deg', -}: { + style, +}: ViewStyleProp & { gradient: | typeof tokens.gradients.primary | typeof tokens.gradients.sky @@ -75,7 +76,7 @@ export function GradientFill({ } start={start} end={end} - style={[a.absolute, a.inset_0]} + style={[a.absolute, a.inset_0, style]} /> ) } diff --git a/src/components/dialogs/BlueskyPlusCore/index.tsx b/src/components/dialogs/BlueskyPlusCore/index.tsx index eb6608798b..5363f238f6 100644 --- a/src/components/dialogs/BlueskyPlusCore/index.tsx +++ b/src/components/dialogs/BlueskyPlusCore/index.tsx @@ -29,6 +29,7 @@ import {CheckThick_Stroke2_Corner0_Rounded as CheckThink} from '#/components/ico import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {InlineLinkText, Link} from '#/components/Link' import {Loader} from '#/components/Loader' +import {SubduedFill} from '#/components/purchases/BlueskyPlusGradients' import {Text} from '#/components/Typography' export function BlueskyPlusCore({ @@ -151,17 +152,43 @@ function DialogInner({control}: {control: Dialog.DialogControlProps}) { a.overflow_hidden, gtMobile ? {width: '100%', maxWidth: 400, minWidth: 200} : a.w_full, ]}> - + + + + - - Let's build the social web. - + + + + Let's build the social web. + + @@ -196,10 +223,7 @@ function DialogInner({control}: {control: Dialog.DialogControlProps}) { : t.atoms.border_contrast_low, ]}> {Boolean(selected || hovered) && ( - + )} {selected ? ( <> - diff --git a/src/components/purchases/BlueskyPlusGradients.tsx b/src/components/purchases/BlueskyPlusGradients.tsx new file mode 100644 index 0000000000..c2e8e297ee --- /dev/null +++ b/src/components/purchases/BlueskyPlusGradients.tsx @@ -0,0 +1,32 @@ +import {View} from 'react-native' +import {LinearGradient} from 'expo-linear-gradient' + +import {atoms as a, tokens, useTheme, ViewStyleProp} from '#/alf' + +const dark = tokens.gradients.nordic +const light = { + values: [ + [0, '#0F62C7'], + [1, '#9EE8C1'], + ], +} as const + +export function SubduedFill({style}: ViewStyleProp) { + const t = useTheme() + const isDark = t.name !== 'light' + const gradient = isDark ? dark : light + + return ( + + c[1]) as [string, string, ...string[]]} + locations={ + gradient.values.map(c => c[0]) as [number, number, ...number[]] + } + start={{x: 0, y: 1}} + end={{x: 1, y: 1}} + style={[a.absolute, a.inset_0, {opacity: 0.3}, style]} + /> + + ) +} diff --git a/src/screens/Subscriptions/index.tsx b/src/screens/Subscriptions/index.tsx index c07393944e..c66d6cc610 100644 --- a/src/screens/Subscriptions/index.tsx +++ b/src/screens/Subscriptions/index.tsx @@ -19,7 +19,7 @@ import { APISubscription, NativePurchaseRestricted, } from '#/state/purchases/types' -import {atoms as a, tokens, useBreakpoints, useGutters,useTheme} from '#/alf' +import {atoms as a, tokens, useBreakpoints, useGutters, useTheme} from '#/alf' import {Admonition} from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useDialogControl} from '#/components/Dialog' @@ -38,6 +38,7 @@ import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus import * as Layout from '#/components/Layout' import {createStaticClick, InlineLinkText, Link} from '#/components/Link' import {Loader} from '#/components/Loader' +import {SubduedFill} from '#/components/purchases/BlueskyPlusGradients' import {Text} from '#/components/Typography' export type ScreenProps = NativeStackScreenProps< @@ -46,6 +47,8 @@ export type ScreenProps = NativeStackScreenProps< > export function Subscriptions(_props: ScreenProps) { + const t = useTheme() + const isDark = t.name !== 'light' const gutters = useGutters(['base', 'base']) const insets = useSafeAreaInsets() const purchases = usePurchases() @@ -64,12 +67,16 @@ export function Subscriptions(_props: ScreenProps) { return ( - + + - + - + @@ -114,17 +121,17 @@ function Core({ const coreSubscriptions = state.subscriptions.filter( s => s.group === SubscriptionGroupId.Core, ) - const activeCoreSubscriptions = coreSubscriptions.filter( + const activeSubscriptions = coreSubscriptions.filter( s => s.status === 'active' || s.status === 'paused', ) - const inactiveCoreSubscriptions = coreSubscriptions.filter( + const inactiveSubscriptions = coreSubscriptions.filter( s => s.status !== 'active' && s.status !== 'paused', ) - const hasActiveSubscriptions = activeCoreSubscriptions.length > 0 - const hasInactiveCoreSubscriptions = inactiveCoreSubscriptions.length > 0 + const hasActiveSubscriptions = activeSubscriptions.length > 0 + const hasInactiveSubscriptions = inactiveSubscriptions.length > 0 return ( - + {restricted === 'yes' ? ( @@ -132,45 +139,60 @@ function Core({ Please subscribe additional accounts through our web application. - ) : hasActiveSubscriptions ? null : hasInactiveCoreSubscriptions ? ( - + ) : hasActiveSubscriptions ? null : hasInactiveSubscriptions ? ( + ) : ( - + )} - + {hasActiveSubscriptions || + (hasInactiveSubscriptions && ( + <> + - {hasActiveSubscriptions && ( - - - My subscriptions - + {hasActiveSubscriptions && ( + + + My subscriptions + - - - {activeCoreSubscriptions.map(sub => ( - - ))} - - - - )} + + + {activeSubscriptions.map(sub => ( + + ))} + + + + )} - {hasInactiveCoreSubscriptions && ( - - - Past subscriptions - + {hasInactiveSubscriptions && ( + + + Past subscriptions + - - - {inactiveCoreSubscriptions.map(sub => ( - - ))} - - - - )} + + + {inactiveSubscriptions.map(sub => ( + + ))} + + + + )} + + ))} @@ -219,6 +241,9 @@ function InfoCards() { a.p_lg, a.rounded_md, a.gap_sm, + a.overflow_hidden, + a.border, + t.atoms.border_contrast_low, t.atoms.bg_contrast_25, ]}> {activeFeatures.map(f => ( - + {f.text} ))} @@ -283,14 +308,23 @@ function InfoCards() { ) } -function Repurchase() { +function PurchaseHeader() { + const t = useTheme() + const isDark = t.name !== 'light' const {_} = useLingui() const control = useDialogControl() + const {gtMobile} = useBreakpoints() + const large = gtMobile return ( - - - You're part of something bigger. + + + Building a better internet needs your support. @@ -320,81 +354,6 @@ function Repurchase() { ) } -function Purchase() { - const t = useTheme() - const {_} = useLingui() - const control = useDialogControl() - const {features} = useFeatures() - - return ( - <> - - Building a better internet needs your support. - - - - - - Subscribing to Bluesky+ helps ensure that our work to build an open, - secure, and user-first internet can continue. - - - - Plus, you'll get access to exclusive features! - - - - - {features.map(f => ( - - - - - - {f.text} - - - ))} - - - - - - ) -} - export function useSubscriptionUI({ subscription: sub, }: { @@ -464,12 +423,13 @@ export function Subscription({ const {_} = useLingui() const {mutateAsync: manageSubscription} = useManageSubscription() const ui = useSubscriptionUI({subscription: sub}) + const isExpired = sub.status !== 'active' && sub.status !== 'paused' const canManage = (isWeb && sub.platform === PlatformId.Web) || (isIOS && sub.platform === PlatformId.Ios) || (isAndroid && sub.platform === PlatformId.Android) - const showManage = canManage && sub.status !== 'expired' + const showManage = canManage && !isExpired const statusStyles = React.useMemo(() => { return { @@ -503,8 +463,13 @@ export function Subscription({ return ( - + style={[ + a.px_lg, + a.rounded_md, + a.overflow_hidden, + isExpired && [a.border, t.atoms.border_contrast_low], + ]}> + {!isExpired && } ({ async mutationFn({did, email, offering}: Params) { + console.log(offering) if (offering.platform === PlatformId.Web) { throw new Error('Unsupported platform') }