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')
}