import { useState, useEffect, useRef } from 'react'
import {
View,
Text,
StyleSheet,
ScrollView,
Pressable,
StatusBar as RNStatusBar,
Platform,
useWindowDimensions,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { LinearGradient } from 'expo-linear-gradient'
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
import { useRouter } from 'expo-router'
import { useTranslation } from 'react-i18next'
import { Image } from 'expo-image'
import Carousel from 'react-native-reanimated-carousel'
import Svg, { Path, Defs, LinearGradient as SvgLinearGradient, Stop } from 'react-native-svg'
import { CheckIcon, LeftArrowIcon, OmitIcon, UncheckedIcon, TermsIcon, PrivacyIcon } from '@/components/icon'
import { CheckMarkIcon } from '@/components/icon/checkMark'
import PointsDrawer from '@/components/drawer/PointsDrawer'
import Dropdown from '@/components/ui/dropdown'
import GradientText from '@/components/GradientText'
// 使用唯一 id 的 PointsIcon,避免与其他页面的图标 id 冲突
const MembershipPointsIcon = () => {
const gradientId = 'paint0_linear_membership'
return (
)
}
type PlanType = 'plus' | 'pro' | 'plus-premium'
interface Plan {
id: PlanType
name: string
price: number
recommended?: boolean
points: number // 每月积分
features: string[] // 功能列表
}
export default function MembershipScreen() {
const router = useRouter()
const insets = useSafeAreaInsets()
const { width: screenWidth } = useWindowDimensions()
const [selectedPlan, setSelectedPlan] = useState('pro')
const [agreed, setAgreed] = useState(false)
const [pointsDrawerVisible, setPointsDrawerVisible] = useState(false)
const { t } = useTranslation()
// 订阅计划数据(使用国际化)
const plans: Plan[] = [
{
id: 'plus',
name: 'Plus',
price: 9,
points: 750,
features: [
t('membership.features.points750'),
t('membership.features.textToVideo'),
t('membership.features.superClearImage'),
t('membership.features.superDiscount'),
]
},
{
id: 'pro',
name: 'Pro',
price: 29,
recommended: true,
points: 1080,
features: [
t('membership.features.points1080'),
t('membership.features.textToVideo'),
t('membership.features.superClearImage'),
t('membership.features.superDiscount'),
t('membership.features.sora2ProTemplate'),
t('membership.features.removeWatermark'),
t('membership.features.allTemplates'),
]
},
{
id: 'plus-premium',
name: 'Plus',
price: 49,
points: 1500,
features: [
t('membership.features.points1500'),
t('membership.features.textToVideo'),
t('membership.features.superClearImage'),
t('membership.features.superDiscount'),
t('membership.features.sora2ProTemplate'),
t('membership.features.removeWatermark'),
t('membership.features.allTemplates'),
t('membership.features.higherQuality'),
t('membership.features.prioritySupport'),
]
},
]
// 下拉菜单选项
const menuOptions = [
{ label: t('membership.terms'), value: 'terms' },
{ label: t('membership.privacy'), value: 'privacy' },
]
// 处理菜单选择
const handleMenuSelect = (value: string) => {
if (value === 'terms') {
router.push('/terms')
} else if (value === 'privacy') {
router.push('/privacy')
}
}
// 轮播图相关
const carouselImages = [
require('@/assets/images/membership.png'),
require('@/assets/images/icon.png'),
require('@/assets/images/generate.png'),
]
const [currentImageIndex, setCurrentImageIndex] = useState(0)
// 获取当前选中计划的信息
const currentPlan = plans.find(plan => plan.id === selectedPlan) || plans[1]
// 计算进度条百分比:当前计划积分 / 最高计划积分
const maxPoints = Math.max(...plans.map(plan => plan.points))
const progressPercentage = (currentPlan.points / maxPoints) * 100
return (
{/* 顶部导航栏 - 固定在顶部 */}
router.back()}
>
setPointsDrawerVisible(true)}
>
{t('membership.myPoints')}
60
handleMenuSelect(value)}
offsetTop={10}
renderTrigger={(selectedOption, isOpen, toggle) => (
)}
dropdownStyle={styles.menuDropdown}
renderOption={(option, isSelected) => (
{option.value === 'terms' ? (
) : (
)}
{option.label}
)}
/>
(
)}
autoPlay
autoPlayInterval={2000}
loop
onSnapToItem={(index) => setCurrentImageIndex(index)}
/>
{carouselImages.map((_, index) => (
))}
{/* 订阅计划标题 */}
{t('membership.subscriptionPlan')}
{/* 订阅计划卡片 */}
{plans.map((plan, index) => {
const isSelected = selectedPlan === plan.id
return (
0 && styles.planCardSpacing,
]}
onPress={() => setSelectedPlan(plan.id)}
>
{isSelected ? (
{plan.recommended && (
{t('membership.mostRecommended')}
)}
{plan.name}
$
{plan.price}
{t('membership.perMonth')}
) : (
{plan.recommended && (
{t('membership.mostRecommended')}
)}
{plan.name}
$
{plan.price}
{t('membership.perMonth')}
)}
)
})}
{/* 卡片所属的信息 */}
{/* 积分每月显示 */}
{currentPlan.points.toLocaleString()}
{t('membership.pointsPerMonth')}
{t('membership.pointsAutoRenew')}
{/* 功能列表 */}
{currentPlan.features.map((feature, index) => (
{feature}
))}
{/* 固定在底部的订阅容器 */}
{/* 立即开通按钮 */}
{t('membership.subscribeNow')}
{/* 协议复选框 */}
setAgreed(!agreed)}
>
{agreed ? : }
{t('membership.agreementText')}{' '}
router.push('/terms')}
>
{t('membership.terms')}
{t('membership.agreementAnd')}
router.push('/privacy')}
>
{t('membership.privacy')}
{/* 积分抽屉 */}
setPointsDrawerVisible(false)}
totalPoints={60}
subscriptionPoints={0}
topUpPoints={0}
/>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
contentWrapper: {
flex: 1,
},
scrollView: {
flex: 1,
backgroundColor: '#090A0B',
},
scrollContent: {
backgroundColor: '#090A0B',
flexGrow: 1,
paddingTop: 56, // 为固定的导航栏留出空间
},
header: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 12,
paddingTop: 7,
paddingBottom: 7,
zIndex: 100,
backgroundColor: 'transparent',
},
imageContainer: {
width: '100%',
overflow: 'hidden',
marginTop: -56,
position: 'relative',
},
membershipImage: {
width: '100%',
height: '100%',
},
imageGradient: {
position: 'absolute',
bottom: -20,
left: 0,
right: 0,
height: '30%',
zIndex: 10,
elevation: 10,
},
dotsContainer: {
position: 'absolute',
bottom: 40,
left: 16,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
gap: 4,
zIndex: 20,
elevation: 20,
},
dot: {
width: 4,
height: 4,
borderRadius: 100,
backgroundColor: '#FFFFFF80',
},
dotActive: {
width: 10,
height: 4,
borderRadius: 100,
backgroundColor: '#FFFFFF',
},
backButton: {
width: 32,
height: 32,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 100,
},
headerSpacer: {
flex: 1,
},
pointsPill: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 100,
backgroundColor: '#2A2A2A80',
},
pointsLabel: {
color: '#F5F5F5',
fontSize: 11,
fontWeight: '500',
},
pointsValue: {
color: '#F5F5F5',
fontSize: 12,
fontWeight: '500',
},
sectionTitle: {
textAlign: 'center',
color: '#F5F5F5',
fontSize: 24,
fontWeight: '900',
lineHeight: 32,
marginBottom: 16,
marginTop: 9,
fontStyle: 'italic',
},
plansContainer: {
flexDirection: 'row',
paddingHorizontal: 16,
marginBottom: 16,
},
planCardWrapper: {
flex: 1,
},
planCardGradient: {
flex: 1,
borderRadius: 12,
padding: 2,
},
planCardWrapperUnselected: {
flex: 1,
borderRadius: 12,
padding: 2,
backgroundColor: 'transparent',
},
planCard: {
flex: 1,
paddingTop: 12,
paddingBottom: 16,
paddingHorizontal: 12,
borderRadius: 12,
backgroundColor: '#16181B',
position: 'relative',
overflow: 'hidden',
},
planCardSpacing: {
marginLeft: 12,
},
recommendedBadge: {
position: 'absolute',
top: -3,
right: -2,
paddingHorizontal: 11,
paddingBottom: 1,
borderRadius: 4,
backgroundColor: '#6851EB',
borderTopRightRadius: 12,
borderBottomRightRadius: 0,
},
recommendedText: {
color: '#F5F5F5',
fontSize: 10,
fontWeight: '500',
},
planName: {
color: '#F5F5F5',
fontSize: 12,
fontWeight: '500',
marginBottom: 14,
},
priceContainer: {
flexDirection: 'row',
alignItems: 'baseline',
},
priceSymbol: {
color: '#F5F5F5',
fontSize: 12,
fontWeight: '500',
marginRight: 2,
},
priceValue: {
color: '#F5F5F5',
fontSize: 24,
fontWeight: '500',
marginRight: 4,
},
priceUnit: {
color: '#ABABAB',
fontSize: 12,
fontWeight: '500',
},
pointsMonthlyContainer: {
marginHorizontal: 16,
backgroundColor: '#191B1F',
paddingHorizontal: 12,
paddingVertical: 12,
borderRadius: 12,
marginBottom: 16,
},
pointsMonthlyCard: {
paddingHorizontal: 16,
paddingVertical: 10,
borderRadius: 10,
backgroundColor: '#272A30',
marginBottom: 24,
},
pointsMonthlyHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 10,
},
pointsMonthlyLabelWrapper: {
marginLeft: 8,
},
pointsMonthlyValue: {
color: '#F5F5F5',
fontSize: 13,
fontWeight: '500',
},
pointsMonthlyLabel: {
color: '#F5F5F5',
fontSize: 13,
fontWeight: '500',
},
progressBar: {
width: '100%',
height: 3,
backgroundColor: '#484F5B',
borderRadius: 10,
marginBottom: 10,
overflow: 'hidden',
},
progressFill: {
height: '100%',
borderRadius: 2,
},
pointsMonthlyNote: {
color: '#CCCCCC',
fontSize: 11,
fontWeight: '400',
},
featureItem: {
flexDirection: 'row',
alignItems: 'center',
gap: 16,
marginBottom: 12,
},
featureText: {
flex: 1,
color: '#CCCCCC',
fontSize: 12,
fontWeight: '400',
},
agreementContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginTop: 8,
},
agreementTextWrapper: {
marginLeft: 4,
},
checkbox: {
width: 12,
height: 12,
alignItems: 'center',
justifyContent: 'center',
},
agreementText: {
color: '#CCCCCC',
fontSize: 11,
fontWeight: '400',
},
agreementLink: {
color: '#CCCCCC',
},
subscribeContainer: {
paddingTop: 8,
alignItems: 'center',
paddingHorizontal: 16,
},
subscribeButtonPressable: {
width: '100%',
height: 48,
borderRadius: 12,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
subscribeButton: {
width: '100%',
paddingVertical: 14,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center',
},
subscribeButtonDisabled: {
opacity: 0.5,
},
subscribeButtonText: {
color: '#F5F5F5',
fontSize: 16,
fontWeight: '500',
},
subscribeButtonText1: {
color: '#0D0D0E',
fontSize: 16,
fontWeight: '500',
},
settingsButtonContainer: {
position: 'relative',
},
settingsButton: {
width: 32,
height: 32,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#2A2A2A80',
borderRadius: 100,
},
pointsContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
menuDropdown: {
width: 180,
minWidth: 180,
borderRadius: 12,
backgroundColor: '#2A2A2A80',
paddingVertical: 4,
right: 12,
},
menuOption: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 2,
gap: 8,
},
menuOptionText: {
color: '#F5F5F5',
fontSize: 12,
fontWeight: '400',
flex: 1,
},
})