Initial commit: expo-popcore-app
This commit is contained in:
770
app/membership.tsx
Normal file
770
app/membership.tsx
Normal file
@@ -0,0 +1,770 @@
|
||||
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 (
|
||||
<Svg width="14" height="14" viewBox="0 0 14 14" fill="none" preserveAspectRatio="xMidYMid meet">
|
||||
<Defs>
|
||||
<SvgLinearGradient
|
||||
id={gradientId}
|
||||
x1="7.00033"
|
||||
y1="1.73615"
|
||||
x2="7.00033"
|
||||
y2="12.2639"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<Stop offset="0" stopColor="#FFC738" />
|
||||
<Stop offset="1" stopColor="#FFA92D" />
|
||||
</SvgLinearGradient>
|
||||
</Defs>
|
||||
<Path
|
||||
d="M10.297 6.5548H8.38602C8.21382 6.5548 8.08222 6.3994 8.11022 6.23L8.79062 2.0622C8.83542 1.7892 8.49802 1.624 8.30902 1.8256L3.49862 6.9734C3.33202 7.1526 3.45802 7.4452 3.70302 7.4452H5.61402C5.78622 7.4452 5.91782 7.6006 5.88982 7.77L5.20942 11.9378C5.16462 12.2108 5.50202 12.376 5.69102 12.1744L10.5014 7.0266C10.6694 6.8474 10.542 6.5548 10.297 6.5548Z"
|
||||
fill={`url(#${gradientId})`}
|
||||
/>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
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<PlanType>('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 (
|
||||
<SafeAreaView style={styles.container} edges={['top']}>
|
||||
<StatusBar style="light" />
|
||||
<RNStatusBar
|
||||
barStyle="light-content"
|
||||
backgroundColor="#090A0B"
|
||||
translucent={Platform.OS === 'android'}
|
||||
/>
|
||||
<View style={styles.contentWrapper}>
|
||||
{/* 顶部导航栏 - 固定在顶部 */}
|
||||
<View style={styles.header}>
|
||||
<Pressable
|
||||
style={styles.backButton}
|
||||
onPress={() => router.back()}
|
||||
>
|
||||
<LeftArrowIcon className="w-4 h-4" />
|
||||
</Pressable>
|
||||
<View style={styles.headerSpacer} />
|
||||
<View style={styles.pointsContainer}>
|
||||
<Pressable
|
||||
style={styles.pointsPill}
|
||||
onPress={() => setPointsDrawerVisible(true)}
|
||||
>
|
||||
<Text style={styles.pointsLabel}>{t('membership.myPoints')}</Text>
|
||||
<MembershipPointsIcon />
|
||||
<Text style={styles.pointsValue}>60</Text>
|
||||
</Pressable>
|
||||
<View style={styles.settingsButtonContainer}>
|
||||
<Dropdown
|
||||
options={menuOptions}
|
||||
onSelect={(value) => handleMenuSelect(value)}
|
||||
offsetTop={10}
|
||||
renderTrigger={(selectedOption, isOpen, toggle) => (
|
||||
<Pressable style={styles.settingsButton} onPress={toggle}>
|
||||
<OmitIcon />
|
||||
</Pressable>
|
||||
)}
|
||||
dropdownStyle={styles.menuDropdown}
|
||||
renderOption={(option, isSelected) => (
|
||||
<View style={styles.menuOption}>
|
||||
{option.value === 'terms' ? (
|
||||
<TermsIcon />
|
||||
) : (
|
||||
<PrivacyIcon />
|
||||
)}
|
||||
<Text style={styles.menuOptionText}>{option.label}</Text>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<ScrollView
|
||||
style={styles.scrollView}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<View style={styles.imageContainer}>
|
||||
<Carousel
|
||||
width={screenWidth}
|
||||
height={screenWidth / 1.1}
|
||||
data={carouselImages}
|
||||
renderItem={({ item }) => (
|
||||
<Image
|
||||
source={item}
|
||||
style={[styles.membershipImage, { width: screenWidth, height: screenWidth / 1.1 }]}
|
||||
contentFit="cover"
|
||||
/>
|
||||
)}
|
||||
autoPlay
|
||||
autoPlayInterval={2000}
|
||||
loop
|
||||
onSnapToItem={(index) => setCurrentImageIndex(index)}
|
||||
/>
|
||||
<View style={styles.dotsContainer}>
|
||||
{carouselImages.map((_, index) => (
|
||||
<View
|
||||
key={index}
|
||||
style={[
|
||||
styles.dot,
|
||||
index === currentImageIndex && styles.dotActive,
|
||||
]}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
<LinearGradient
|
||||
colors={['#090A0B00', '#090A0B']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 0, y: 1 }}
|
||||
style={styles.imageGradient}
|
||||
pointerEvents="none"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 订阅计划标题 */}
|
||||
<Text style={styles.sectionTitle}>{t('membership.subscriptionPlan')}</Text>
|
||||
|
||||
{/* 订阅计划卡片 */}
|
||||
<View style={styles.plansContainer}>
|
||||
{plans.map((plan, index) => {
|
||||
const isSelected = selectedPlan === plan.id
|
||||
return (
|
||||
<Pressable
|
||||
key={plan.id}
|
||||
style={[
|
||||
styles.planCardWrapper,
|
||||
index > 0 && styles.planCardSpacing,
|
||||
]}
|
||||
onPress={() => setSelectedPlan(plan.id)}
|
||||
>
|
||||
{isSelected ? (
|
||||
<LinearGradient
|
||||
colors={['#FF9966', '#FF6699', '#9966FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.planCardGradient}
|
||||
>
|
||||
<View style={styles.planCard}>
|
||||
{plan.recommended && (
|
||||
<View style={styles.recommendedBadge}>
|
||||
<Text style={styles.recommendedText}>{t('membership.mostRecommended')}</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.planName}>{plan.name}</Text>
|
||||
<View style={styles.priceContainer}>
|
||||
<GradientText
|
||||
colors={['#FF9966', '#FF6699', '#9966FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.priceSymbol}
|
||||
>
|
||||
$
|
||||
</GradientText>
|
||||
<GradientText
|
||||
colors={['#FF9966', '#FF6699', '#9966FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.priceValue}>{plan.price}</GradientText>
|
||||
<Text style={styles.priceUnit}>{t('membership.perMonth')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
) : (
|
||||
<View style={styles.planCardWrapperUnselected}>
|
||||
<View style={styles.planCard}>
|
||||
{plan.recommended && (
|
||||
<View style={styles.recommendedBadge}>
|
||||
<Text style={styles.recommendedText}>{t('membership.mostRecommended')}</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.planName}>{plan.name}</Text>
|
||||
<View style={styles.priceContainer}>
|
||||
<GradientText
|
||||
colors={['#FF9966', '#FF6699', '#9966FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.priceSymbol}
|
||||
>
|
||||
$
|
||||
</GradientText>
|
||||
<GradientText
|
||||
colors={['#FF9966', '#FF6699', '#9966FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.priceValue}>{plan.price}</GradientText>
|
||||
<Text style={styles.priceUnit}>{t('membership.perMonth')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</Pressable>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
{/* 卡片所属的信息 */}
|
||||
<View style={styles.pointsMonthlyContainer}>
|
||||
{/* 积分每月显示 */}
|
||||
<View style={styles.pointsMonthlyCard}>
|
||||
<View style={styles.pointsMonthlyHeader}>
|
||||
<MembershipPointsIcon />
|
||||
<Text style={styles.pointsMonthlyValue}>
|
||||
{currentPlan.points.toLocaleString()}
|
||||
</Text>
|
||||
<Text style={styles.pointsMonthlyLabel}>{t('membership.pointsPerMonth')}</Text>
|
||||
</View>
|
||||
<View style={styles.progressBar}>
|
||||
<LinearGradient
|
||||
colors={['#FF9966', '#FF6699', '#9966FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={[styles.progressFill, { width: `${progressPercentage}%` }]}
|
||||
/>
|
||||
</View>
|
||||
<Text style={styles.pointsMonthlyNote}>{t('membership.pointsAutoRenew')}</Text>
|
||||
</View>
|
||||
|
||||
{/* 功能列表 */}
|
||||
<View >
|
||||
{currentPlan.features.map((feature, index) => (
|
||||
<View key={index} style={styles.featureItem}>
|
||||
<CheckMarkIcon />
|
||||
<Text style={styles.featureText}>{feature}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
{/* 固定在底部的订阅容器 */}
|
||||
<View style={[styles.subscribeContainer, { paddingBottom: Math.max(insets.bottom, 3) }]}>
|
||||
{/* 立即开通按钮 */}
|
||||
<Pressable
|
||||
disabled={!agreed}
|
||||
style={styles.subscribeButtonPressable}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={currentPlan.recommended
|
||||
? ['#9966FF', '#FF6699', '#FF9966']
|
||||
: ['#FFE7F8', '#C6A7FA', '#ADBCFF', '#E6E3FF']
|
||||
}
|
||||
locations={currentPlan.recommended
|
||||
? [0.0015, 0.4985, 0.9956]
|
||||
: [0, 0.33, 0.66, 1]
|
||||
}
|
||||
start={{ x: 1, y: 0 }}
|
||||
end={{ x: 0, y: 0 }}
|
||||
style={[
|
||||
styles.subscribeButton,
|
||||
!agreed && styles.subscribeButtonDisabled,
|
||||
]}
|
||||
>
|
||||
|
||||
|
||||
<Text style={currentPlan.recommended ? styles.subscribeButtonText : styles.subscribeButtonText1}>{t('membership.subscribeNow')}</Text>
|
||||
</LinearGradient>
|
||||
</Pressable>
|
||||
{/* 协议复选框 */}
|
||||
<View style={styles.agreementContainer}>
|
||||
<Pressable
|
||||
style={styles.checkbox}
|
||||
onPress={() => setAgreed(!agreed)}
|
||||
>
|
||||
{agreed ? <CheckIcon /> : <UncheckedIcon />}
|
||||
</Pressable>
|
||||
<View style={styles.agreementTextWrapper}>
|
||||
<Text style={styles.agreementText}>
|
||||
{t('membership.agreementText')}{' '}
|
||||
<Text
|
||||
style={styles.agreementLink}
|
||||
onPress={() => router.push('/terms')}
|
||||
>
|
||||
{t('membership.terms')}
|
||||
</Text>
|
||||
<Text style={styles.agreementText}> {t('membership.agreementAnd')} </Text>
|
||||
<Text
|
||||
style={styles.agreementLink}
|
||||
onPress={() => router.push('/privacy')}
|
||||
>
|
||||
{t('membership.privacy')}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 积分抽屉 */}
|
||||
<PointsDrawer
|
||||
visible={pointsDrawerVisible}
|
||||
onClose={() => setPointsDrawerVisible(false)}
|
||||
totalPoints={60}
|
||||
subscriptionPoints={0}
|
||||
topUpPoints={0}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
)
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user