feat: 优化

This commit is contained in:
jinyaqiu 2025-07-24 20:39:57 +08:00
parent 12fce0021a
commit a0c1f0e8b6
9 changed files with 95 additions and 40 deletions

View File

@ -9,12 +9,14 @@ import { ThemedText } from '@/components/ThemedText';
import { fetchApi } from '@/lib/server-api-util';
import { useLocalSearchParams, useRouter } from "expo-router";
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Image, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from "react-native-safe-area-context";
export default function Rights() {
const insets = useSafeAreaInsets();
const router = useRouter();
const { t } = useTranslation();
// 获取路由参数
const { credit } = useLocalSearchParams<{
credit: string;
@ -53,7 +55,7 @@ export default function Rights() {
<ReturnArrowSvg />
</TouchableOpacity>
<ThemedText style={styles.headerTitle}>
Subscription
{t('rights.title', { ns: 'personal' })}
</ThemedText>
<ThemedText className='opacity-0'>123</ThemedText>
</View>
@ -67,7 +69,7 @@ export default function Rights() {
<View style={styles.cardContent}>
<View style={styles.cardinfo}>
<ThemedText style={styles.cardTitle}>
Purchase
{t('rights.purchase', { ns: 'personal' })}
</ThemedText>
<View style={styles.cardPoints}>
<StarSvg />
@ -85,13 +87,13 @@ export default function Rights() {
onPress={() => { setUserType("normal") }}
style={[styles.switchButtonItem, { backgroundColor: userType === 'normal' ? "#FFB645" : "#fff", borderColor: userType === 'normal' ? "#FFB645" : "#E2793F" }]}
>
<ThemedText style={{ color: userType === 'normal' ? "#fff" : "#E2793F" }}>Free</ThemedText>
<ThemedText style={{ color: userType === 'normal' ? "#fff" : "#E2793F" }}> {t('rights.free', { ns: 'personal' })}</ThemedText>
</TouchableOpacity>
<TouchableOpacity
onPress={() => { setUserType("premium") }}
style={[styles.switchButtonItem, { backgroundColor: userType === 'premium' ? "#E2793F" : "#fff", borderColor: userType === 'premium' ? "#E2793F" : "#E2793F" }]}
>
<ThemedText style={{ color: userType === 'premium' ? "#fff" : "#E2793F" }}>Pro</ThemedText>
<ThemedText style={{ color: userType === 'premium' ? "#fff" : "#E2793F" }}>{t('rights.premium', { ns: 'personal' })}</ThemedText>
</TouchableOpacity>
</View>
{/* 普通权益 */}
@ -124,7 +126,7 @@ export default function Rights() {
activeOpacity={0.8}
>
<ThemedText style={{ color: '#fff', fontWeight: '700', fontSize: 14 }}>
Subscribe Yearly
{t('rights.subscribe', { ns: 'personal' })}
</ThemedText>
</TouchableOpacity>
<TouchableOpacity
@ -134,7 +136,7 @@ export default function Rights() {
activeOpacity={0.8}
>
<ThemedText style={{ color: '#AC7E35', fontWeight: '400', fontSize: 11, textDecorationLine: 'underline', textAlign: 'center' }}>
Terms Privacy
{t('rights.terms', { ns: 'personal' })}
</ThemedText>
</TouchableOpacity>
</View>

View File

@ -16,7 +16,7 @@ import * as Location from 'expo-location';
import { useRouter } from 'expo-router';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Linking, Pressable, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Linking, Platform, Pressable, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from "react-native-safe-area-context";
const Setting = (props: { modalVisible: boolean, setModalVisible: (visible: boolean) => void, userInfo: User }) => {
@ -98,11 +98,9 @@ const Setting = (props: { modalVisible: boolean, setModalVisible: (visible: bool
try {
// 1. 首先检查当前权限状态 -- 获取当前的位置权限
let currentStatus = await getLocationPermission();
console.log('当前权限状态:', currentStatus);
// 2. 如果没有权限,则跳过获取位置
if (!currentStatus) {
console.log('没有权限,跳过获取位置')
return;
// const newStatus = await requestLocationPermission();
// setLocationEnabled(newStatus);
@ -117,16 +115,14 @@ const Setting = (props: { modalVisible: boolean, setModalVisible: (visible: bool
// 3. 确保位置服务已启用
const isEnabled = await Location.hasServicesEnabledAsync();
if (!isEnabled) {
alert('请先启用位置服务');
alert(t('permission.locationPermissionRequired', { ns: 'common' }));
return;
}
console.log('位置服务已启用');
// 4. 获取当前位置
const location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.High, // 使用高精度
timeInterval: 10000, // 可选:最大等待时间(毫秒)
});
console.log('位置:', location);
// 地理位置逆编码
const address = await reverseGeocode(location.coords.latitude, location.coords.longitude);
@ -137,12 +133,10 @@ const Setting = (props: { modalVisible: boolean, setModalVisible: (visible: bool
return location;
} catch (error: any) {
if (error.code === 'PERMISSION_DENIED' || error.code === 'PERMISSION_DENIED_ERROR') {
alert('位置权限被拒绝,请在设置中启用位置服务');
} else if (error.code === 'TIMEOUT') {
alert('获取位置超时,请检查网络和位置服务');
if (error.code === 'TIMEOUT') {
alert(t('permission.timeout', { ns: 'common' }));
} else {
alert(`无法获取您的位置: ${error.message || '未知错误'}`);
alert(t('permission.notLocation', { ns: 'common' }) + error.message || t('permission.notError', { ns: 'common' }));
}
throw error; // 重新抛出错误以便上层处理
} finally {
@ -173,17 +167,14 @@ const Setting = (props: { modalVisible: boolean, setModalVisible: (visible: bool
if (modalVisible) {
// 位置权限
getLocationPermission().then((res: boolean | ((prevState: boolean) => boolean)) => {
console.log('位置权限:', res);
setLocationEnabled(res);
})
// 媒体库权限
getPermissions().then((res: boolean | ((prevState: boolean) => boolean)) => {
console.log('媒体库权限:', res);
setAlbumEnabled(res);
})
// 通知权限
checkNotificationPermission().then((res: boolean | ((prevState: boolean) => boolean)) => {
console.log('通知权限:', res);
setNotificationsEnabled(res);
})
}
@ -344,8 +335,8 @@ const Setting = (props: { modalVisible: boolean, setModalVisible: (visible: bool
<RightArrowSvg />
</TouchableOpacity>
<Divider />
<TouchableOpacity style={styles.item} onPress={() => Linking.openURL("https://beian.miit.gov.cn/")} >
<ThemedText style={styles.itemText}>{t('lcenses.ICP', { ns: 'personal' })}ICP备2023032876号-4</ThemedText>
<TouchableOpacity style={[styles.item, { display: Platform.OS === 'ios' ? 'none' : 'flex' }]} onPress={() => Linking.openURL("https://beian.miit.gov.cn/")} >
<ThemedText style={styles.itemText}>{t('lcenses.ICP', { ns: 'personal' })}ICP备2025133004号-2A</ThemedText>
<RightArrowSvg />
</TouchableOpacity>
</View>

View File

@ -1,5 +1,6 @@
import GetSvg from "@/assets/icons/svg/get.svg";
import { ThemedText } from "@/components/ThemedText";
import { useTranslation } from "react-i18next";
import { StyleProp, StyleSheet, TouchableOpacity, View, ViewStyle } from "react-native";
interface Props {
@ -9,6 +10,7 @@ interface Props {
const Normal = (props: Props) => {
const { setUserType } = props;
const { t } = useTranslation();
return (
<View style={[styles.normalInfo, props.style]}>
@ -16,16 +18,16 @@ const Normal = (props: Props) => {
<View style={styles.normalItemContent}>
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
<GetSvg style={{ marginTop: 8 }} />
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>Enjoy 100 Bonus Credits Every Month</ThemedText>
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>{t('rights.100Bonus', { ns: 'personal' })}</ThemedText>
</View>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>Generate more memory pictures & videos and explore your past.</ThemedText>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>{t('rights.100BonusText', { ns: 'personal' })}</ThemedText>
</View>
<View style={styles.normalItemContent}>
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
<GetSvg style={{ marginTop: 8 }} />
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>10GB of Cloud Storage</ThemedText>
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>{t('rights.10G', { ns: 'personal' })}</ThemedText>
</View>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>Safely store your cherished photos, videos, and generated memories.</ThemedText>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>{t('rights.10GText', { ns: 'personal' })}</ThemedText>
</View>
</View>
<TouchableOpacity
@ -36,7 +38,7 @@ const Normal = (props: Props) => {
activeOpacity={0.8}
>
<ThemedText style={{ color: '#fff', fontWeight: '700', fontSize: 14 }}>
Go Premium
{t('rights.purchase', { ns: 'personal' })}
</ThemedText>
</TouchableOpacity>
</View>

View File

@ -1,5 +1,6 @@
import BlackStarSvg from '@/assets/icons/svg/blackStar.svg';
import { ThemedText } from "@/components/ThemedText";
import { useTranslation } from 'react-i18next';
import { ScrollView, StyleProp, StyleSheet, TouchableOpacity, View, ViewStyle } from "react-native";
import { maxDiscountProduct } from './utils';
@ -31,6 +32,7 @@ export interface PayItem {
const Premium = (props: Props) => {
const { style, payType, setPayType, premiumPay, loading, setShowTerms } = props;
const bestValue = maxDiscountProduct(premiumPay)?.product_code
const { t } = useTranslation();
return (
<View style={[styles.proInfo, style]}>
@ -43,7 +45,7 @@ const Premium = (props: Props) => {
{loading
?
<ThemedText style={{ fontSize: 12, color: "#4C320C", fontWeight: "700", width: "100%", textAlign: "center" }}>
Loading...
{t('loading', { ns: 'common' })}
</ThemedText>
:
premiumPay?.map((item: PayItem) => {
@ -57,7 +59,7 @@ const Premium = (props: Props) => {
<View style={[styles.title, { opacity: item?.product_code === bestValue ? 1 : 0 }]}>
<BlackStarSvg />
<ThemedText style={[styles.titleText, { fontSize: 14 }]}>
Best Value
{t('rights.bestValue', { ns: 'personal' })}
</ThemedText>
<BlackStarSvg />
</View>
@ -78,10 +80,10 @@ const Premium = (props: Props) => {
</ScrollView>
<View style={{ flexDirection: 'row', gap: 8, marginLeft: 4 }}>
<ThemedText style={{ color: '#AC7E35', fontSize: 10 }}>
Cancel anytime before renewal. Learn more
{t('rights.cancelAnytimeBeforeRenewal', { ns: 'personal' })}
</ThemedText>
<ThemedText style={{ color: '#E2793F', fontSize: 10, textDecorationLine: 'underline' }} onPress={() => setShowTerms(true)}>
Terms & Conditions
{t('rights.terms', { ns: 'personal' })}
</ThemedText>
</View>
</View>

View File

@ -1,33 +1,35 @@
import GetSvg from "@/assets/icons/svg/get.svg";
import { ThemedText } from "@/components/ThemedText";
import { useTranslation } from "react-i18next";
import { StyleProp, StyleSheet, View, ViewStyle } from "react-native";
const ProRights = (props: { style?: StyleProp<ViewStyle> }) => {
const { style } = props;
const { t } = useTranslation();
return (
<View style={[styles.proRights, style]}>
<ThemedText style={{ fontSize: 12, color: "#4C320C", fontWeight: "700", width: "100%", textAlign: "center" }}>
Enjoy MemoWake Pro Benefits
{t('rights.proTitle', { ns: 'personal' })}
</ThemedText>
<View style={{ display: "flex", flexDirection: "column", }}>
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
<GetSvg style={{ marginTop: 8 }} />
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>no advertisement</ThemedText>
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>{t('rights.noAd', { ns: 'personal' })}</ThemedText>
</View>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>There are no advertisements, so you can use the product with peace of mind.</ThemedText>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>{t('rights.noAdText', { ns: 'personal' })}</ThemedText>
</View>
<View style={styles.itemContent}>
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
<GetSvg style={{ marginTop: 8 }} />
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>Enjoy 1000 Bonus Credits Every Month</ThemedText>
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>{t('rights.bonus', { ns: 'personal' })}</ThemedText>
</View>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>Generate more memory pictures & videos and explore your past.</ThemedText>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>{t('rights.bonusText', { ns: 'personal' })}</ThemedText>
</View>
<View style={styles.itemContent}>
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
<GetSvg style={{ marginTop: 8 }} />
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>100GB of Cloud Storage</ThemedText>
<ThemedText style={{ fontSize: 12, fontWeight: '500', color: "#4C320C" }}>{t('rights.storage', { ns: 'personal' })}</ThemedText>
</View>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>Safely store your cherished photos, videos, and generated memories.</ThemedText>
<ThemedText style={{ fontSize: 10, color: "#AC7E35", marginLeft: 20 }}>{t('rights.storageText', { ns: 'personal' })}</ThemedText>
</View>
</View>
);

View File

@ -111,5 +111,11 @@
"required": "You must agree to the Terms and Privacy Policy"
}
},
"loading": "Loading..."
"loading": "Loading...",
"permission": {
"locationPermissionRequired": "Location permission is required, please enable location service in settings",
"timeout": "Location timeout, please check network and location service",
"notLocation": "Unable to get your location: ",
"notError": "Unknown error"
}
}

View File

@ -88,5 +88,27 @@
"unlock": "Unlock more memory magic",
"delete": "Are you sure you want to delete your account?",
"cancel": "Cancel"
},
"rights": {
"title": "Subscription",
"premium": "Pro",
"purchase": "Purchase",
"free": "Free",
"subscribe": "Subscribe",
"terms": "Terms",
"100Bonus": "Enjoy 100 Bonus Credits Every Month",
"100BonusText": "Generate more memory pictures & videos and explore your past.",
"10G": "10GB of Cloud Storage",
"10GText": "Safely store your cherished photos, videos, and generated memories.",
"goPremium": "Go Premium",
"bestValue": "Best Value",
"cancelAnytimeBeforeRenewal": "Cancel anytime before renewal. Learn more",
"proTitle": "Enjoy MemoWake Pro Benefits",
"noAd": "No advertisements",
"noAdText": "There are no advertisements, so you can use the product with peace of mind.",
"bonus": "Enjoy 100 Bonus Credits Every Month",
"bonusText": "Generate more memory pictures & videos and explore your past.",
"storage": "10GB of Cloud Storage",
"storageText": "Safely store your cherished photos, videos, and generated memories."
}
}

View File

@ -110,5 +110,11 @@
"required": "您必须同意服务条款和隐私政策"
}
},
"loading": "加载中..."
"loading": "加载中...",
"permission": {
"locationPermissionRequired": "位置权限被拒绝,请在设置中启用位置服务",
"timeout": "获取位置超时,请检查网络和位置服务",
"notLocation": "无法获取您的位置: ",
"notError": "未知错误"
}
}

View File

@ -88,5 +88,27 @@
"unlock": "解锁更多记忆魔法",
"delete": "确定要注销账号吗?",
"cancel": "取消"
},
"rights": {
"title": "权益",
"purchase": "购买",
"free": "免费用户",
"premium": "会员",
"subscribe": "订阅",
"terms": "用户协议",
"100Bonus": "每月享受100积分",
"100BonusText": "生成更多记忆照片和视频,探索你的过去。",
"10G": "10GB的云存储",
"10GText": "安全存储你的珍贵照片、视频和生成的记忆。",
"goPremium": "升级至会员",
"bestValue": "最佳值",
"cancelAnytimeBeforeRenewal": "在续订前随时取消。了解更多",
"proTitle": "享受MemoWake Pro权益",
"noAd": "无广告",
"noAdText": "没有广告,所以你可以安心使用产品。",
"bonus": "每月享受100积分",
"bonusText": "生成更多记忆照片和视频,探索你的过去。",
"storage": "10GB的云存储",
"storageText": "安全存储你的珍贵照片、视频和生成的记忆。"
}
}