fix the warning
This commit is contained in:
@@ -23,6 +23,7 @@ import { colors, typography, spacing, borderRadius, shadows } from '../theme/col
|
|||||||
import { SystemStatus, KillSwitchLog } from '../types';
|
import { SystemStatus, KillSwitchLog } from '../types';
|
||||||
import VaultScreen from './VaultScreen';
|
import VaultScreen from './VaultScreen';
|
||||||
|
|
||||||
|
// Nautical-themed mnemonic word list (unique words only)
|
||||||
const MNEMONIC_WORDS = [
|
const MNEMONIC_WORDS = [
|
||||||
'anchor', 'harbor', 'compass', 'lighthouse', 'current', 'ocean', 'tide', 'voyage',
|
'anchor', 'harbor', 'compass', 'lighthouse', 'current', 'ocean', 'tide', 'voyage',
|
||||||
'keel', 'stern', 'bow', 'mast', 'sail', 'port', 'starboard', 'reef',
|
'keel', 'stern', 'bow', 'mast', 'sail', 'port', 'starboard', 'reef',
|
||||||
@@ -30,9 +31,17 @@ const MNEMONIC_WORDS = [
|
|||||||
'horizon', 'sextant', 'sound', 'drift', 'wake', 'mariner', 'pilot', 'fathom',
|
'horizon', 'sextant', 'sound', 'drift', 'wake', 'mariner', 'pilot', 'fathom',
|
||||||
'buoy', 'lantern', 'harpoon', 'lagoon', 'bay', 'strait', 'riptide', 'foam',
|
'buoy', 'lantern', 'harpoon', 'lagoon', 'bay', 'strait', 'riptide', 'foam',
|
||||||
'coral', 'pearl', 'trident', 'ebb', 'flow', 'vault', 'cipher', 'shroud',
|
'coral', 'pearl', 'trident', 'ebb', 'flow', 'vault', 'cipher', 'shroud',
|
||||||
'salt', 'wave', 'grotto', 'lagoon', 'storm', 'north', 'south', 'east',
|
'salt', 'wave', 'grotto', 'storm', 'north', 'south', 'east', 'west',
|
||||||
'west', 'ember', 'cabin', 'signal', 'ledger', 'torch', 'sanctum', 'oath',
|
'ember', 'cabin', 'ledger', 'torch', 'sanctum', 'oath', 'depths', 'captain',
|
||||||
];
|
] as const;
|
||||||
|
|
||||||
|
// Animation timing constants
|
||||||
|
const ANIMATION_DURATION = {
|
||||||
|
pulse: 1200,
|
||||||
|
glow: 1500,
|
||||||
|
rotate: 30000,
|
||||||
|
heartbeatPress: 150,
|
||||||
|
} as const;
|
||||||
|
|
||||||
const generateMnemonic = (wordCount = 12) => {
|
const generateMnemonic = (wordCount = 12) => {
|
||||||
const words: string[] = [];
|
const words: string[] = [];
|
||||||
@@ -49,11 +58,14 @@ const splitMnemonic = (words: string[]) => [
|
|||||||
words.slice(8, 12),
|
words.slice(8, 12),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Icon names type for type safety
|
||||||
|
type StatusIconName = 'checkmark-circle' | 'warning' | 'alert-circle';
|
||||||
|
|
||||||
// Status configuration with nautical theme
|
// Status configuration with nautical theme
|
||||||
const statusConfig: Record<SystemStatus, {
|
const statusConfig: Record<SystemStatus, {
|
||||||
color: string;
|
color: string;
|
||||||
label: string;
|
label: string;
|
||||||
icon: string;
|
icon: StatusIconName;
|
||||||
description: string;
|
description: string;
|
||||||
gradientColors: [string, string];
|
gradientColors: [string, string];
|
||||||
}> = {
|
}> = {
|
||||||
@@ -123,46 +135,56 @@ export default function SentinelScreen() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Pulse animation
|
// Pulse animation
|
||||||
Animated.loop(
|
const pulseAnimation = Animated.loop(
|
||||||
Animated.sequence([
|
Animated.sequence([
|
||||||
Animated.timing(pulseAnim, {
|
Animated.timing(pulseAnim, {
|
||||||
toValue: 1.06,
|
toValue: 1.06,
|
||||||
duration: 1200,
|
duration: ANIMATION_DURATION.pulse,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}),
|
}),
|
||||||
Animated.timing(pulseAnim, {
|
Animated.timing(pulseAnim, {
|
||||||
toValue: 1,
|
toValue: 1,
|
||||||
duration: 1200,
|
duration: ANIMATION_DURATION.pulse,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
).start();
|
);
|
||||||
|
pulseAnimation.start();
|
||||||
|
|
||||||
// Glow animation
|
// Glow animation
|
||||||
Animated.loop(
|
const glowAnimation = Animated.loop(
|
||||||
Animated.sequence([
|
Animated.sequence([
|
||||||
Animated.timing(glowAnim, {
|
Animated.timing(glowAnim, {
|
||||||
toValue: 1,
|
toValue: 1,
|
||||||
duration: 1500,
|
duration: ANIMATION_DURATION.glow,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}),
|
}),
|
||||||
Animated.timing(glowAnim, {
|
Animated.timing(glowAnim, {
|
||||||
toValue: 0.5,
|
toValue: 0.5,
|
||||||
duration: 1500,
|
duration: ANIMATION_DURATION.glow,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
).start();
|
);
|
||||||
|
glowAnimation.start();
|
||||||
|
|
||||||
// Slow rotate for ship wheel
|
// Slow rotate for ship wheel
|
||||||
Animated.loop(
|
const rotateAnimation = Animated.loop(
|
||||||
Animated.timing(rotateAnim, {
|
Animated.timing(rotateAnim, {
|
||||||
toValue: 1,
|
toValue: 1,
|
||||||
duration: 30000,
|
duration: ANIMATION_DURATION.rotate,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
})
|
})
|
||||||
).start();
|
);
|
||||||
}, []);
|
rotateAnimation.start();
|
||||||
|
|
||||||
|
// Cleanup animations on unmount to prevent memory leaks
|
||||||
|
return () => {
|
||||||
|
pulseAnimation.stop();
|
||||||
|
glowAnimation.stop();
|
||||||
|
rotateAnimation.stop();
|
||||||
|
};
|
||||||
|
}, [pulseAnim, glowAnim, rotateAnim]);
|
||||||
|
|
||||||
const openVaultWithMnemonic = () => {
|
const openVaultWithMnemonic = () => {
|
||||||
const words = generateMnemonic();
|
const words = generateMnemonic();
|
||||||
@@ -230,23 +252,23 @@ export default function SentinelScreen() {
|
|||||||
Animated.sequence([
|
Animated.sequence([
|
||||||
Animated.timing(pulseAnim, {
|
Animated.timing(pulseAnim, {
|
||||||
toValue: 1.15,
|
toValue: 1.15,
|
||||||
duration: 150,
|
duration: ANIMATION_DURATION.heartbeatPress,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}),
|
}),
|
||||||
Animated.timing(pulseAnim, {
|
Animated.timing(pulseAnim, {
|
||||||
toValue: 1,
|
toValue: 1,
|
||||||
duration: 150,
|
duration: ANIMATION_DURATION.heartbeatPress,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}),
|
}),
|
||||||
]).start();
|
]).start();
|
||||||
|
|
||||||
// Add new log
|
// Add new log using functional update to avoid stale closure
|
||||||
const newLog: KillSwitchLog = {
|
const newLog: KillSwitchLog = {
|
||||||
id: Date.now().toString(),
|
id: Date.now().toString(),
|
||||||
action: 'HEARTBEAT_CONFIRMED',
|
action: 'HEARTBEAT_CONFIRMED',
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setLogs([newLog, ...logs]);
|
setLogs((prevLogs) => [newLog, ...prevLogs]);
|
||||||
|
|
||||||
// Reset status if warning
|
// Reset status if warning
|
||||||
if (status === 'warning') {
|
if (status === 'warning') {
|
||||||
@@ -324,7 +346,7 @@ export default function SentinelScreen() {
|
|||||||
colors={currentStatus.gradientColors}
|
colors={currentStatus.gradientColors}
|
||||||
style={styles.statusCircle}
|
style={styles.statusCircle}
|
||||||
>
|
>
|
||||||
<Ionicons name={currentStatus.icon as any} size={56} color="#fff" />
|
<Ionicons name={currentStatus.icon} size={56} color="#fff" />
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
<Text style={[styles.statusLabel, { color: currentStatus.color }]}>
|
<Text style={[styles.statusLabel, { color: currentStatus.color }]}>
|
||||||
@@ -390,6 +412,8 @@ export default function SentinelScreen() {
|
|||||||
style={styles.vaultAccessButton}
|
style={styles.vaultAccessButton}
|
||||||
onPress={openVaultWithMnemonic}
|
onPress={openVaultWithMnemonic}
|
||||||
activeOpacity={0.8}
|
activeOpacity={0.8}
|
||||||
|
accessibilityLabel="Open Shadow Vault"
|
||||||
|
accessibilityRole="button"
|
||||||
>
|
>
|
||||||
<Text style={styles.vaultAccessButtonText}>Open</Text>
|
<Text style={styles.vaultAccessButtonText}>Open</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -400,6 +424,8 @@ export default function SentinelScreen() {
|
|||||||
style={styles.heartbeatButton}
|
style={styles.heartbeatButton}
|
||||||
onPress={handleHeartbeat}
|
onPress={handleHeartbeat}
|
||||||
activeOpacity={0.9}
|
activeOpacity={0.9}
|
||||||
|
accessibilityLabel="Signal the watch - Confirm your presence"
|
||||||
|
accessibilityRole="button"
|
||||||
>
|
>
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={[colors.nautical.teal, colors.nautical.seafoam]}
|
colors={[colors.nautical.teal, colors.nautical.seafoam]}
|
||||||
@@ -451,6 +477,8 @@ export default function SentinelScreen() {
|
|||||||
style={styles.vaultCloseButton}
|
style={styles.vaultCloseButton}
|
||||||
onPress={() => setShowVault(false)}
|
onPress={() => setShowVault(false)}
|
||||||
activeOpacity={0.85}
|
activeOpacity={0.85}
|
||||||
|
accessibilityLabel="Close vault"
|
||||||
|
accessibilityRole="button"
|
||||||
>
|
>
|
||||||
<Ionicons name="close" size={20} color={colors.nautical.cream} />
|
<Ionicons name="close" size={20} color={colors.nautical.cream} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -468,15 +496,17 @@ export default function SentinelScreen() {
|
|||||||
style={styles.mnemonicOverlay}
|
style={styles.mnemonicOverlay}
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
||||||
>
|
>
|
||||||
<LinearGradient
|
<View ref={mnemonicRef} collapsable={false}>
|
||||||
colors={[colors.sentinel.cardBackground, colors.sentinel.backgroundGradientEnd]}
|
<LinearGradient
|
||||||
style={styles.mnemonicCard}
|
colors={[colors.sentinel.cardBackground, colors.sentinel.backgroundGradientEnd]}
|
||||||
ref={mnemonicRef}
|
style={styles.mnemonicCard}
|
||||||
>
|
>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.mnemonicClose}
|
style={styles.mnemonicClose}
|
||||||
onPress={() => setShowMnemonic(false)}
|
onPress={() => setShowMnemonic(false)}
|
||||||
activeOpacity={0.85}
|
activeOpacity={0.85}
|
||||||
|
accessibilityLabel="Close mnemonic modal"
|
||||||
|
accessibilityRole="button"
|
||||||
>
|
>
|
||||||
<Ionicons name="close" size={18} color={colors.sentinel.textSecondary} />
|
<Ionicons name="close" size={18} color={colors.sentinel.textSecondary} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -514,6 +544,9 @@ export default function SentinelScreen() {
|
|||||||
onPress={handleScreenshot}
|
onPress={handleScreenshot}
|
||||||
activeOpacity={0.85}
|
activeOpacity={0.85}
|
||||||
disabled={isCapturing}
|
disabled={isCapturing}
|
||||||
|
accessibilityLabel="Take screenshot backup of mnemonic"
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityState={{ disabled: isCapturing }}
|
||||||
>
|
>
|
||||||
<Text style={styles.mnemonicPrimaryText}>
|
<Text style={styles.mnemonicPrimaryText}>
|
||||||
{isCapturing ? 'CAPTURING...' : 'PHYSICAL BACKUP (SCREENSHOT)'}
|
{isCapturing ? 'CAPTURING...' : 'PHYSICAL BACKUP (SCREENSHOT)'}
|
||||||
@@ -523,6 +556,8 @@ export default function SentinelScreen() {
|
|||||||
style={styles.mnemonicSecondaryButton}
|
style={styles.mnemonicSecondaryButton}
|
||||||
onPress={handleEmailBackup}
|
onPress={handleEmailBackup}
|
||||||
activeOpacity={0.85}
|
activeOpacity={0.85}
|
||||||
|
accessibilityLabel="Send mnemonic backup via email"
|
||||||
|
accessibilityRole="button"
|
||||||
>
|
>
|
||||||
<Text style={styles.mnemonicSecondaryText}>EMAIL BACKUP</Text>
|
<Text style={styles.mnemonicSecondaryText}>EMAIL BACKUP</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -542,12 +577,15 @@ export default function SentinelScreen() {
|
|||||||
style={styles.emailSendButton}
|
style={styles.emailSendButton}
|
||||||
onPress={handleSendEmail}
|
onPress={handleSendEmail}
|
||||||
activeOpacity={0.85}
|
activeOpacity={0.85}
|
||||||
|
accessibilityLabel="Send backup email"
|
||||||
|
accessibilityRole="button"
|
||||||
>
|
>
|
||||||
<Text style={styles.emailSendText}>SEND EMAIL</Text>
|
<Text style={styles.emailSendText}>SEND EMAIL</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
|
</View>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
</Modal>
|
</Modal>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
Reference in New Issue
Block a user