Files
pwap/mobile/src/screens/SettingsScreen.tsx
T
pezkuwichain 1a47363938 Fix all ESLint errors in mobile app (157 errors -> 0)
Major fixes:
- Replace `any` types with proper TypeScript types across all files
- Convert require() imports to ES module imports
- Add __DEV__ guards to console statements
- Escape special characters in JSX (' and ")
- Fix unused variables (prefix with _ or remove)
- Fix React hooks violations (useCallback, useMemo patterns)
- Convert wasm-crypto-shim.js to TypeScript
- Add eslint-disable comments for valid setState patterns

Files affected: 50+ screens, components, contexts, and services

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 02:55:03 +03:00

942 lines
29 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect, useCallback } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
SafeAreaView,
ScrollView,
StatusBar,
Alert,
Switch,
Linking,
ActivityIndicator,
Modal,
TextInput,
Platform
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as SecureStore from 'expo-secure-store';
import { Clipboard } from 'react-native';
import { useNavigation, NavigationProp } from '@react-navigation/native';
import type { AlertButton } from 'react-native';
import { RootStackParamList } from '../navigation/AppNavigator';
import { KurdistanColors } from '../theme/colors';
// Profile type for Supabase
interface UserProfile {
id?: string;
full_name: string;
username: string;
bio?: string;
notifications_push: boolean;
notifications_email: boolean;
updated_at?: string;
}
import { useTheme } from '../contexts/ThemeContext';
import { useBiometricAuth } from '../contexts/BiometricAuthContext';
import { useAuth } from '../contexts/AuthContext';
import { usePezkuwi, NETWORKS } from '../contexts/PezkuwiContext';
import { supabase } from '../lib/supabase';
// Cross-platform alert helper
const showAlert = (title: string, message: string, buttons?: AlertButton[]) => {
if (Platform.OS === 'web') {
if (buttons && buttons.length > 1) {
// For confirm dialogs
const result = window.confirm(`${title}\n\n${message}`);
if (result && buttons[1]?.onPress) {
buttons[1].onPress();
}
} else {
window.alert(`${title}\n\n${message}`);
}
} else {
Alert.alert(title, message, buttons);
}
};
// Font size options
type FontSize = 'small' | 'medium' | 'large';
const FONT_SIZE_OPTIONS: { value: FontSize; label: string; description: string }[] = [
{ value: 'small', label: 'Small', description: '87.5% - Compact text' },
{ value: 'medium', label: 'Medium', description: '100% - Default size' },
{ value: 'large', label: 'Large', description: '112.5% - Easier to read' },
];
// Auto-lock timer options (in minutes)
const AUTO_LOCK_OPTIONS: { value: number; label: string }[] = [
{ value: 1, label: '1 minute' },
{ value: 5, label: '5 minutes' },
{ value: 15, label: '15 minutes' },
{ value: 30, label: '30 minutes' },
{ value: 60, label: '1 hour' },
];
// --- COMPONENTS (Internal for simplicity) ---
const SectionHeader = ({ title }: { title: string }) => {
const { colors } = useTheme();
return (
<View style={styles.sectionHeader}>
<Text style={[styles.sectionTitle, { color: colors.textSecondary }]}>{title}</Text>
</View>
);
};
const SettingItem = ({
icon,
title,
subtitle,
onPress,
showArrow = true,
textColor,
testID
}: {
icon: string;
title: string;
subtitle?: string;
onPress: () => void;
showArrow?: boolean;
textColor?: string;
testID?: string;
}) => {
const { colors } = useTheme();
return (
<TouchableOpacity
style={[styles.settingItem, { borderBottomColor: colors.border }]}
onPress={onPress}
testID={testID}
>
<View style={[styles.settingIcon, { backgroundColor: colors.background }]}>
<Text style={styles.settingIconText}>{icon}</Text>
</View>
<View style={styles.settingContent}>
<Text style={[styles.settingTitle, { color: textColor || colors.text }]}>{title}</Text>
{subtitle && <Text style={[styles.settingSubtitle, { color: colors.textSecondary }]}>{subtitle}</Text>}
</View>
{showArrow && <Text style={[styles.arrow, { color: colors.textSecondary }]}></Text>}
</TouchableOpacity>
);
};
const SettingToggle = ({
icon,
title,
subtitle,
value,
onToggle,
loading = false,
testID
}: {
icon: string;
title: string;
subtitle?: string;
value: boolean;
onToggle: (value: boolean) => void;
loading?: boolean;
testID?: string;
}) => {
const { colors } = useTheme();
return (
<View style={[styles.settingItem, { borderBottomColor: colors.border }]} testID={testID}>
<View style={[styles.settingIcon, { backgroundColor: colors.background }]}>
<Text style={styles.settingIconText}>{icon}</Text>
</View>
<View style={styles.settingContent}>
<Text style={[styles.settingTitle, { color: colors.text }]}>{title}</Text>
{subtitle && <Text style={[styles.settingSubtitle, { color: colors.textSecondary }]}>{subtitle}</Text>}
</View>
{loading ? (
<ActivityIndicator size="small" color={KurdistanColors.kesk} />
) : (
<Switch
value={value}
onValueChange={onToggle}
trackColor={{ false: '#E0E0E0', true: KurdistanColors.kesk }}
thumbColor={value ? KurdistanColors.spi : '#f4f3f4'}
testID={testID ? `${testID}-switch` : undefined}
/>
)}
</View>
);
};
// --- MAIN SCREEN ---
const SettingsScreen: React.FC = () => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
const { isDarkMode, toggleDarkMode, colors, fontSize, setFontSize } = useTheme();
const { isBiometricEnabled, enableBiometric, disableBiometric, biometricType, autoLockTimer, setAutoLockTimer } = useBiometricAuth();
const { signOut, user } = useAuth();
const { currentNetwork, switchNetwork, selectedAccount } = usePezkuwi();
// Profile State (Supabase)
const [profile, setProfile] = useState<UserProfile>({
full_name: '',
username: '',
notifications_push: false,
notifications_email: true,
});
const [_loadingProfile, setLoadingProfile] = useState(false);
const [savingSettings, setSavingSettings] = useState(false);
// Modals
const [showNetworkModal, setShowNetworkModal] = useState(false);
const [showProfileEdit, setShowProfileEdit] = useState(false);
const [showFontSizeModal, setShowFontSizeModal] = useState(false);
const [showAutoLockModal, setShowAutoLockModal] = useState(false);
const [showBackupModal, setShowBackupModal] = useState(false);
const [backupMnemonic, setBackupMnemonic] = useState('');
const [editName, setEditName] = useState('');
const [editBio, setEditBio] = useState('');
// 1. Fetch Profile from Supabase
const fetchProfile = useCallback(async () => {
if (!user) return;
setLoadingProfile(true);
try {
const { data, error } = await supabase
.from('profiles')
.select('*')
.eq('id', user.id)
.maybeSingle();
if (error) throw error;
if (data) {
setProfile(data);
setEditName(data.full_name || '');
setEditBio(data.bio || '');
}
} catch (_err) {
console.log('Error fetching profile:', _err);
} finally {
setLoadingProfile(false);
}
}, [user]);
useEffect(() => {
fetchProfile();
}, [fetchProfile]);
// 2. Update Settings in Supabase
const updateSetting = async (key: string, value: boolean) => {
if (!user) return;
setSavingSettings(true);
// Optimistic update
setProfile((prev) => ({ ...prev, [key]: value }));
try {
const { error } = await supabase
.from('profiles')
.update({ [key]: value, updated_at: new Date().toISOString() })
.eq('id', user.id);
if (error) throw error;
} catch (err) {
console.error('Failed to update setting:', err);
// Revert on error
setProfile((prev) => ({ ...prev, [key]: !value }));
showAlert('Error', 'Failed to save setting. Please check your connection.');
} finally {
setSavingSettings(false);
}
};
// 3. Save Profile Info
const saveProfileInfo = async () => {
if (!user) return;
try {
const { error } = await supabase
.from('profiles')
.update({
full_name: editName,
bio: editBio,
updated_at: new Date().toISOString()
})
.eq('id', user.id);
if (error) throw error;
setProfile((prev) => ({ ...prev, full_name: editName, bio: editBio }));
setShowProfileEdit(false);
showAlert('Success', 'Profile updated successfully');
} catch {
showAlert('Error', 'Failed to update profile');
}
};
// 4. Biometric Handler
const handleBiometryToggle = async (value: boolean) => {
// Biometric not available on web
if (Platform.OS === 'web') {
showAlert(
'Not Available',
'Biometric authentication is only available on mobile devices.'
);
return;
}
if (value) {
const success = await enableBiometric();
if (success) {
showAlert('Success', 'Biometric authentication enabled');
}
} else {
await disableBiometric();
}
};
// 5. Network Switcher
const handleNetworkChange = async (network: 'pezkuwi' | 'dicle' | 'zagros' | 'bizinikiwi' | 'zombienet') => {
await switchNetwork(network);
setShowNetworkModal(false);
showAlert(
'Network Changed',
`Switched to ${NETWORKS[network].displayName}. The app will reconnect automatically.`,
[{ text: 'OK' }]
);
};
// 6. Font Size Handler
const handleFontSizeChange = async (size: FontSize) => {
await setFontSize(size);
setShowFontSizeModal(false);
};
// 7. Auto-Lock Timer Handler
const handleAutoLockChange = async (minutes: number) => {
await setAutoLockTimer(minutes);
setShowAutoLockModal(false);
};
// Get display text for current font size
const getFontSizeLabel = () => {
const option = FONT_SIZE_OPTIONS.find(opt => opt.value === fontSize);
return option ? option.label : 'Medium';
};
// Get display text for current auto-lock timer
const getAutoLockLabel = () => {
const option = AUTO_LOCK_OPTIONS.find(opt => opt.value === autoLockTimer);
return option ? option.label : '5 minutes';
};
// 8. Wallet Backup Handler
const handleWalletBackup = async () => {
if (!selectedAccount) {
showAlert('No Wallet', 'Please create or import a wallet first.');
return;
}
try {
// Retrieve mnemonic from secure storage
const seedKey = `pezkuwi_seed_${selectedAccount.address}`;
let storedMnemonic: string | null = null;
if (Platform.OS === 'web') {
storedMnemonic = await AsyncStorage.getItem(seedKey);
} else {
storedMnemonic = await SecureStore.getItemAsync(seedKey);
}
if (storedMnemonic) {
setBackupMnemonic(storedMnemonic);
setShowBackupModal(true);
} else {
showAlert('No Backup', 'Recovery phrase not found. It may have been imported from another device.');
}
} catch (error) {
console.error('Error retrieving mnemonic:', error);
showAlert('Error', 'Failed to retrieve recovery phrase.');
}
};
return (
<SafeAreaView style={[styles.container, { backgroundColor: colors.background }]} testID="settings-screen">
<StatusBar barStyle={isDarkMode ? "light-content" : "dark-content"} />
{/* Header */}
<View style={[styles.header, { backgroundColor: colors.surface, borderBottomColor: colors.border }]}>
<View style={{ width: 40 }} />
<Text style={[styles.headerTitle, { color: colors.text }]}>Settings</Text>
<View style={{ width: 40 }} />
</View>
<ScrollView showsVerticalScrollIndicator={false}>
{/* ACCOUNT SECTION */}
<SectionHeader title="ACCOUNT" />
<View style={[styles.section, { backgroundColor: colors.surface }]}>
<SettingItem
icon="👤"
title="Edit Profile"
subtitle={profile.full_name || user?.email || 'Set your name'}
onPress={() => setShowProfileEdit(true)}
testID="edit-profile-button"
/>
<SettingItem
icon="💳"
title="Wallet Management"
subtitle="Manage your connected keys"
onPress={() => navigation.navigate('Wallet')}
testID="wallet-management-button"
/>
</View>
{/* APP SETTINGS */}
<SectionHeader title="APP SETTINGS" />
<View style={[styles.section, { backgroundColor: colors.surface }]}>
<SettingToggle
icon="🌙"
title="Dark Mode"
subtitle={isDarkMode ? "Dark theme enabled" : "Light theme enabled"}
value={isDarkMode}
onToggle={toggleDarkMode}
testID="dark-mode"
/>
<SettingItem
icon="🔤"
title="Font Size"
subtitle={getFontSizeLabel()}
onPress={() => setShowFontSizeModal(true)}
testID="font-size-button"
/>
<SettingToggle
icon="🔔"
title="Push Notifications"
subtitle="Receive alerts about transactions"
value={profile.notifications_push}
onToggle={(val) => updateSetting('notifications_push', val)}
loading={savingSettings}
testID="push-notifications"
/>
<SettingToggle
icon="📧"
title="Email Updates"
subtitle="Receive newsletters & reports"
value={profile.notifications_email}
onToggle={(val) => updateSetting('notifications_email', val)}
loading={savingSettings}
testID="email-updates"
/>
</View>
{/* NETWORK & SECURITY */}
<SectionHeader title="NETWORK & SECURITY" />
<View style={[styles.section, { backgroundColor: colors.surface }]}>
<SettingItem
icon="📡"
title="Network Node"
subtitle={NETWORKS[currentNetwork]?.displayName || 'Unknown'}
onPress={() => setShowNetworkModal(true)}
testID="network-node-button"
/>
<SettingToggle
icon="🔐"
title="Biometric Security"
subtitle={isBiometricEnabled ? `Enabled (${biometricType})` : "FaceID / Fingerprint"}
value={isBiometricEnabled}
onToggle={handleBiometryToggle}
testID="biometric-security"
/>
<SettingItem
icon="⏱️"
title="Auto-Lock Timer"
subtitle={getAutoLockLabel()}
onPress={() => setShowAutoLockModal(true)}
testID="auto-lock-button"
/>
<SettingItem
icon="🔑"
title="Backup Recovery Phrase"
subtitle={selectedAccount ? "View your wallet's recovery phrase" : "No wallet connected"}
onPress={handleWalletBackup}
testID="backup-recovery-button"
/>
</View>
{/* SUPPORT */}
<SectionHeader title="SUPPORT" />
<View style={[styles.section, { backgroundColor: colors.surface }]}>
<SettingItem
icon="📄"
title="Terms of Service"
onPress={() => showAlert('Terms', 'Terms of service content...')}
testID="terms-of-service-button"
/>
<SettingItem
icon="🔒"
title="Privacy Policy"
onPress={() => showAlert('Privacy', 'Privacy policy content...')}
testID="privacy-policy-button"
/>
<SettingItem
icon="❓"
title="Help Center"
onPress={() => Linking.openURL('mailto:support@pezkuwichain.io')}
testID="help-center-button"
/>
</View>
{/* DEVELOPER OPTIONS (only in DEV) */}
{__DEV__ && (
<View style={[styles.section, { backgroundColor: colors.surface, marginTop: 20 }]}>
<Text style={[styles.sectionHeader, { color: colors.textSecondary }]}>DEVELOPER</Text>
<SettingItem
icon="🗑️"
title="Reset Wallet"
subtitle="Clear all wallet data"
textColor="#FF9500"
showArrow={false}
onPress={() => {
showAlert(
'Reset Wallet',
'This will delete all wallet data including saved accounts and keys. Are you sure?',
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Reset',
style: 'destructive',
onPress: async () => {
try {
await AsyncStorage.multiRemove([
'@pezkuwi_wallets',
'@pezkuwi_selected_account',
'@pezkuwi_selected_network'
]);
showAlert('Success', 'Wallet data cleared. Restart the app to see changes.');
} catch {
showAlert('Error', 'Failed to clear wallet data');
}
}
}
]
);
}}
testID="reset-wallet-button"
/>
</View>
)}
{/* LOGOUT */}
<View style={[styles.section, { backgroundColor: colors.surface, marginTop: 20 }]}>
<SettingItem
icon="🚪"
title="Sign Out"
textColor="#FF3B30"
showArrow={false}
onPress={() => {
showAlert(
'Sign Out',
'Are you sure you want to sign out?',
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'Sign Out', style: 'destructive', onPress: signOut }
]
);
}}
testID="sign-out-button"
/>
</View>
<View style={styles.footer}>
<Text style={[styles.versionText, { color: colors.textSecondary }]}>Pezkuwi Super App v1.0.0</Text>
<Text style={[styles.copyright, { color: colors.textSecondary }]}>© 2026 Digital Kurdistan</Text>
</View>
<View style={{ height: 40 }} />
</ScrollView>
{/* NETWORK MODAL */}
<Modal visible={showNetworkModal} transparent animationType="fade">
<View style={styles.modalOverlay}>
<View style={[styles.modalContent, { backgroundColor: colors.surface }]}>
<Text style={[styles.modalTitle, { color: colors.text }]}>Select Network</Text>
<TouchableOpacity
style={[styles.networkOption, currentNetwork === 'pezkuwi' && styles.selectedNetwork]}
onPress={() => handleNetworkChange('pezkuwi')}
testID="network-option-mainnet"
>
<Text style={styles.networkName}>{NETWORKS.pezkuwi.displayName}</Text>
<Text style={styles.networkUrl}>{NETWORKS.pezkuwi.rpcEndpoint}</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.networkOption, currentNetwork === 'bizinikiwi' && styles.selectedNetwork]}
onPress={() => handleNetworkChange('bizinikiwi')}
testID="network-option-testnet"
>
<Text style={styles.networkName}>{NETWORKS.bizinikiwi.displayName}</Text>
<Text style={styles.networkUrl}>{NETWORKS.bizinikiwi.rpcEndpoint}</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.networkOption, currentNetwork === 'zombienet' && styles.selectedNetwork]}
onPress={() => handleNetworkChange('zombienet')}
testID="network-option-zombienet"
>
<Text style={styles.networkName}>{NETWORKS.zombienet.displayName}</Text>
<Text style={styles.networkUrl}>{NETWORKS.zombienet.rpcEndpoint}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.cancelButton}
onPress={() => setShowNetworkModal(false)}
testID="network-modal-cancel"
>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
{/* PROFILE EDIT MODAL */}
<Modal visible={showProfileEdit} animationType="slide">
<SafeAreaView style={[styles.fullModal, { backgroundColor: colors.background }]}>
<View style={[styles.header, { backgroundColor: colors.surface }]}>
<TouchableOpacity onPress={() => setShowProfileEdit(false)}>
<Text style={{ fontSize: 16, color: colors.text }}>Cancel</Text>
</TouchableOpacity>
<Text style={[styles.headerTitle, { color: colors.text }]}>Edit Profile</Text>
<TouchableOpacity onPress={saveProfileInfo}>
<Text style={{ fontSize: 16, color: KurdistanColors.kesk, fontWeight: 'bold' }}>Save</Text>
</TouchableOpacity>
</View>
<View style={{ padding: 20 }}>
<Text style={[styles.label, { color: colors.textSecondary }]}>Full Name</Text>
<TextInput
style={[styles.input, { backgroundColor: colors.surface, color: colors.text, borderColor: colors.border }]}
value={editName}
onChangeText={setEditName}
placeholder="Enter your name"
placeholderTextColor="#999"
/>
<Text style={[styles.label, { color: colors.textSecondary, marginTop: 20 }]}>Bio</Text>
<TextInput
style={[styles.input, { backgroundColor: colors.surface, color: colors.text, borderColor: colors.border, height: 100 }]}
value={editBio}
onChangeText={setEditBio}
placeholder="Tell us about yourself"
placeholderTextColor="#999"
multiline
/>
</View>
</SafeAreaView>
</Modal>
{/* FONT SIZE MODAL */}
<Modal visible={showFontSizeModal} transparent animationType="fade" testID="font-size-modal">
<View style={styles.modalOverlay}>
<View style={[styles.modalContent, { backgroundColor: colors.surface }]}>
<Text style={[styles.modalTitle, { color: colors.text }]}>Select Font Size</Text>
{FONT_SIZE_OPTIONS.map((option) => (
<TouchableOpacity
key={option.value}
style={[styles.networkOption, fontSize === option.value && styles.selectedNetwork]}
onPress={() => handleFontSizeChange(option.value)}
testID={`font-size-option-${option.value}`}
>
<Text style={styles.networkName}>{option.label}</Text>
<Text style={styles.networkUrl}>{option.description}</Text>
</TouchableOpacity>
))}
<TouchableOpacity
style={styles.cancelButton}
onPress={() => setShowFontSizeModal(false)}
testID="font-size-modal-cancel"
>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
{/* AUTO-LOCK TIMER MODAL */}
<Modal visible={showAutoLockModal} transparent animationType="fade" testID="auto-lock-modal">
<View style={styles.modalOverlay}>
<View style={[styles.modalContent, { backgroundColor: colors.surface }]}>
<Text style={[styles.modalTitle, { color: colors.text }]}>Auto-Lock Timer</Text>
<Text style={[styles.modalSubtitle, { color: colors.textSecondary }]}>
Lock app after inactivity
</Text>
{AUTO_LOCK_OPTIONS.map((option) => (
<TouchableOpacity
key={option.value}
style={[styles.networkOption, autoLockTimer === option.value && styles.selectedNetwork]}
onPress={() => handleAutoLockChange(option.value)}
testID={`auto-lock-option-${option.value}`}
>
<Text style={styles.networkName}>{option.label}</Text>
</TouchableOpacity>
))}
<TouchableOpacity
style={styles.cancelButton}
onPress={() => setShowAutoLockModal(false)}
testID="auto-lock-modal-cancel"
>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
{/* WALLET BACKUP MODAL */}
<Modal visible={showBackupModal} transparent animationType="fade" testID="backup-modal">
<View style={styles.modalOverlay}>
<View style={[styles.modalContent, { backgroundColor: colors.surface }]}>
<Text style={[styles.modalTitle, { color: colors.text }]}>🔐 Recovery Phrase</Text>
<Text style={[styles.warningText, { color: '#EF4444' }]}>
NEVER share this with anyone! Write it down and store safely.
</Text>
<View style={styles.mnemonicContainer}>
<Text style={[styles.mnemonicText, { color: colors.text }]}>{backupMnemonic}</Text>
</View>
<View style={styles.backupActions}>
<TouchableOpacity
style={styles.copyButton}
onPress={() => {
Clipboard.setString(backupMnemonic);
showAlert('Copied', 'Recovery phrase copied to clipboard');
}}
>
<Text style={styles.copyButtonText}>📋 Copy</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
style={[styles.confirmButton, { backgroundColor: KurdistanColors.kesk }]}
onPress={() => {
setShowBackupModal(false);
setBackupMnemonic('');
}}
>
<Text style={styles.confirmButtonText}>Done</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 16,
paddingVertical: 12,
borderBottomWidth: 1,
},
backButton: {
width: 40,
height: 40,
justifyContent: 'center',
},
backButtonText: {
fontSize: 24,
color: KurdistanColors.kesk,
fontWeight: 'bold',
},
headerTitle: {
fontSize: 18,
fontWeight: 'bold',
},
sectionHeader: {
marginTop: 24,
marginBottom: 8,
paddingHorizontal: 16,
},
sectionTitle: {
fontSize: 12,
fontWeight: '700',
letterSpacing: 0.5,
},
section: {
marginHorizontal: 16,
borderRadius: 12,
overflow: 'hidden',
},
settingItem: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderBottomWidth: 1,
},
settingIcon: {
width: 32,
height: 32,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
marginRight: 12,
},
settingIconText: {
fontSize: 18,
},
settingContent: {
flex: 1,
},
settingTitle: {
fontSize: 16,
fontWeight: '500',
},
settingSubtitle: {
fontSize: 13,
marginTop: 2,
},
arrow: {
fontSize: 18,
},
footer: {
alignItems: 'center',
marginTop: 32,
},
versionText: {
fontSize: 13,
fontWeight: '600',
},
copyright: {
fontSize: 11,
marginTop: 4,
},
// Modal Styles
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
padding: 20,
},
modalContent: {
borderRadius: 16,
padding: 20,
},
modalTitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
},
modalSubtitle: {
fontSize: 13,
textAlign: 'center',
marginTop: -12,
marginBottom: 16,
},
networkOption: {
padding: 16,
borderRadius: 12,
backgroundColor: '#f5f5f5',
marginBottom: 10,
borderWidth: 1,
borderColor: '#eee',
},
selectedNetwork: {
borderColor: KurdistanColors.kesk,
backgroundColor: '#e8f5e9',
},
networkName: {
fontWeight: 'bold',
fontSize: 16,
color: '#333',
},
networkUrl: {
fontSize: 12,
color: '#666',
marginTop: 2,
},
cancelButton: {
marginTop: 10,
padding: 16,
alignItems: 'center',
},
cancelText: {
color: '#FF3B30',
fontWeight: '600',
fontSize: 16,
},
fullModal: {
flex: 1,
},
label: {
fontSize: 14,
fontWeight: '600',
marginBottom: 8,
},
input: {
borderWidth: 1,
borderRadius: 8,
padding: 12,
fontSize: 16,
},
// Backup Modal Styles
warningText: {
fontSize: 12,
textAlign: 'center',
marginBottom: 16,
fontWeight: '600',
},
mnemonicContainer: {
backgroundColor: '#FEF9E7',
padding: 16,
borderRadius: 12,
marginBottom: 16,
borderWidth: 1,
borderColor: '#F5D76E',
},
mnemonicText: {
fontSize: 14,
lineHeight: 24,
textAlign: 'center',
},
backupActions: {
flexDirection: 'row',
justifyContent: 'center',
marginBottom: 16,
},
copyButton: {
backgroundColor: '#F5F5F5',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
},
copyButtonText: {
fontSize: 16,
fontWeight: '600',
color: '#333',
},
confirmButton: {
width: '100%',
paddingVertical: 16,
borderRadius: 12,
alignItems: 'center',
},
confirmButtonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
});
export default SettingsScreen;