import DeleteSvg from '@/assets/icons/svg/delete.svg'; import LogoutSvg from '@/assets/icons/svg/logout.svg'; import RightArrowSvg from '@/assets/icons/svg/rightArrow.svg'; import { useAuth } from '@/contexts/auth-context'; import { fetchApi } from '@/lib/server-api-util'; import { Address, User } from '@/types/user'; import * as Location from 'expo-location'; import { useRouter } from 'expo-router'; import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Linking, Modal, Pressable, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { ThemedText } from '../ThemedText'; import DeleteModal from './delete'; import LcensesModal from './qualification/lcenses'; import PrivacyModal from './qualification/privacy'; import CustomSwitch from './switch'; import UserInfo from './userInfo'; import { checkNotificationPermission, getLocationPermission, getPermissions, requestLocationPermission, requestMediaLibraryPermission, requestNotificationPermission, reverseGeocode } from './utils'; const SettingModal = (props: { modalVisible: boolean, setModalVisible: (visible: boolean) => void, userInfo: User }) => { const { modalVisible, setModalVisible, userInfo } = props; const { t } = useTranslation(); const [modalType, setModalType] = useState<'ai' | 'terms' | 'privacy' | 'user'>('ai'); // 协议弹窗 const [privacyModalVisible, setPrivacyModalVisible] = useState(false); // 许可证弹窗 const [lcensesModalVisible, setLcensesModalVisible] = useState(false); // 删除弹窗 const [deleteModalVisible, setDeleteModalVisible] = useState(false); const { logout } = useAuth(); const router = useRouter(); // 打开设置 const openAppSettings = () => { Linking.openSettings(); }; // 通知消息权限开关 const [notificationsEnabled, setNotificationsEnabled] = useState(false); const toggleNotifications = async () => { if (notificationsEnabled) { // 引导去设置关闭权限 openAppSettings() } else { requestNotificationPermission() .then((granted) => { setNotificationsEnabled(granted); }); setModalVisible(false); } }; // 相册权限 const [albumEnabled, setAlbumEnabled] = useState(false); const toggleAlbum = async () => { if (albumEnabled) { // 引导去设置关闭权限 openAppSettings() } else { requestMediaLibraryPermission() .then((granted) => { setAlbumEnabled(granted); }); setModalVisible(false); } } // 位置权限 const [locationEnabled, setLocationEnabled] = useState(false); // 位置权限更改 const toggleLocation = async () => { if (locationEnabled) { // 如果权限已开启,点击则引导用户去设置关闭 openAppSettings(); } else { requestLocationPermission() .then((granted) => { setLocationEnabled(granted); }); setModalVisible(false); } }; // 正在获取位置信息 const [isLoading, setIsLoading] = useState(false); // 动画开启 const [isRefreshing, setIsRefreshing] = useState(false); // 当前位置状态 const [currentLocation, setCurrentLocation] = useState
({} as Address); // 获取当前位置 const getCurrentLocation = async () => { setIsLoading(true); setIsRefreshing(true); try { // 1. 首先检查当前权限状态 -- 获取当前的位置权限 let currentStatus = await getLocationPermission(); console.log('当前权限状态:', currentStatus); // 2. 如果没有权限,则跳过获取位置 if (!currentStatus) { console.log('没有权限,跳过获取位置') return; // const newStatus = await requestLocationPermission(); // setLocationEnabled(newStatus); // currentStatus = newStatus; // if (!currentStatus) { // // alert('需要位置权限才能继续'); // return; // } } // 3. 确保位置服务已启用 const isEnabled = await Location.hasServicesEnabledAsync(); if (!isEnabled) { alert('请先启用位置服务'); 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); // 5. 更新位置状态 if (address) { setCurrentLocation(address); } return location; } catch (error: any) { if (error.code === 'PERMISSION_DENIED' || error.code === 'PERMISSION_DENIED_ERROR') { alert('位置权限被拒绝,请在设置中启用位置服务'); } else if (error.code === 'TIMEOUT') { alert('获取位置超时,请检查网络和位置服务'); } else { alert(`无法获取您的位置: ${error.message || '未知错误'}`); } throw error; // 重新抛出错误以便上层处理 } finally { setIsLoading(false); setIsRefreshing(false); } }; // 退出登录 const handleLogout = () => { fetchApi("/iam/logout", { method: "POST", headers: { "Content-Type": "application/json", }, }) .then(async (res) => { await logout(); setModalVisible(false); router.replace('/login'); }) .catch(() => { console.error("jwt has expired."); }); }; // 检查是否有权限 useEffect(() => { if (modalVisible) { // 位置权限 getLocationPermission().then((res) => { console.log('位置权限:', res); setLocationEnabled(res); }) // 媒体库权限 getPermissions().then((res) => { console.log('媒体库权限:', res); setAlbumEnabled(res); }) // 通知权限 checkNotificationPermission().then((res) => { console.log('通知权限:', res); setNotificationsEnabled(res); }) } }, [modalVisible]) return ( <> { setModalVisible(false); }}> setModalVisible(false)}> e.stopPropagation()}> Settings {t('generalSetting.allTitle', { ns: 'personal' })} setModalVisible(false)}> × {/* 用户信息 */} {/* 升级版本 */} {/* {t('generalSetting.subscription', { ns: 'personal' })} {t('generalSetting.subscriptionTitle', { ns: 'personal' })} {t('generalSetting.subscriptionText', { ns: 'personal' })} { }} > {t('generalSetting.upgrade', { ns: 'personal' })} */} {/* 消息通知 */} {/* {t('permission.pushNotification', { ns: 'personal' })} {t('permission.pushNotification', { ns: 'personal' })} */} {/* 权限信息 */} {t('permission.permissionManagement', { ns: 'personal' })} {/* 相册权限 */} {t('permission.galleryAccess', { ns: 'personal' })} {/* 分割线 */} {/* 位置权限 */} {t('permission.locationPermission', { ns: 'personal' })} {t('permission.pushNotification', { ns: 'personal' })} {/* 相册成片权限 */} {/* Opus Permission */} {/* 账号 */} {/* Account Notifications Delete Account */} {/* 协议 */} {t('lcenses.title', { ns: 'personal' })} { setModalType('privacy'); setPrivacyModalVisible(true) }} > {t('lcenses.privacyPolicy', { ns: 'personal' })} { setModalType('terms'); setPrivacyModalVisible(true) }} > {t('lcenses.applyPermission', { ns: 'personal' })} { setModalType('user'); setPrivacyModalVisible(true) }} > {t('lcenses.userAgreement', { ns: 'personal' })} { setModalType('ai'); setPrivacyModalVisible(true) }} > {t('lcenses.aiPolicy', { ns: 'personal' })} { setLcensesModalVisible(true) }} > {t('lcenses.qualification', { ns: 'personal' })} Linking.openURL("https://beian.miit.gov.cn/")} > {t('lcenses.ICP', { ns: 'personal' })}沪ICP备2023032876号-4 {/* 其他信息 */} {t('generalSetting.otherInformation', { ns: 'personal' })} Linking.openURL("https://work.weixin.qq.com/kfid/kfca0ac87f4e05e8bfd")} > {t('generalSetting.contactUs', { ns: 'personal' })} {/* */} {t('generalSetting.version', { ns: 'personal' })} {"0.5.0"} {/* 退出 */} {t('generalSetting.logout', { ns: 'personal' })} {/* 注销账号 */} setDeleteModalVisible(true)}> {t('generalSetting.deleteAccount', { ns: 'personal' })} ); }; const styles = StyleSheet.create({ centeredView: { flex: 1, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0.5)', }, modalView: { width: '100%', height: '80%', backgroundColor: 'white', borderTopLeftRadius: 20, borderTopRightRadius: 20, paddingHorizontal: 16, }, modalHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20, }, modalTitle: { fontSize: 20, fontWeight: 'bold', color: '#4C320C', }, closeButton: { fontSize: 28, color: '#4C320C', padding: 10, }, modalContent: { flex: 1, }, modalText: { fontSize: 16, color: '#4C320C', }, premium: { backgroundColor: "#FAF9F6", padding: 16, borderRadius: 24, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, content: { flex: 1, flexDirection: 'column', gap: 4, backgroundColor: '#FAF9F6', borderRadius: 24, paddingVertical: 8 }, item: { paddingHorizontal: 16, paddingVertical: 8, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, itemText: { fontSize: 14, fontWeight: '600', color: '#4C320C', }, upgradeButton: { backgroundColor: '#E2793F', borderRadius: 20, paddingHorizontal: 16, paddingVertical: 8, }, upgradeButtonText: { color: '#fff', fontSize: 14, fontWeight: "600" }, switchContainer: { width: 50, height: 30, borderRadius: 15, justifyContent: 'center', paddingHorizontal: 2, }, switchOn: { backgroundColor: '#E2793F', alignItems: 'flex-end', }, switchOff: { backgroundColor: '#E5E5E5', alignItems: 'flex-start', }, switchCircle: { width: 26, height: 26, borderRadius: 13, }, switchCircleOn: { backgroundColor: 'white', }, switchCircleOff: { backgroundColor: '#A5A5A5', }, }); const Divider = () => { return ( ) } export default SettingModal;