470 lines
14 KiB
TypeScript
470 lines
14 KiB
TypeScript
/**
|
||
* VaultScreen 重构使用示例
|
||
*
|
||
* 这个文件展示了如何使用新创建的组件和 hooks 来简化 VaultScreen
|
||
*
|
||
* 使用方法:
|
||
* 1. 将这些代码片段复制到 VaultScreen.tsx 中替换对应的部分
|
||
* 2. 确保导入了所有必要的组件
|
||
*/
|
||
|
||
// ============================================
|
||
// 1. 导入新组件和 Hooks
|
||
// ============================================
|
||
|
||
// 在文件顶部添加这些导入
|
||
import { VaultButton, LabeledInput, AssetCard } from '@/components/vault';
|
||
import { useAddFlow, useMnemonicFlow } from '@/hooks/vault';
|
||
|
||
// ============================================
|
||
// 2. 使用 Hooks 管理状态
|
||
// ============================================
|
||
|
||
export default function VaultScreen() {
|
||
// 原来的代码:
|
||
// const [addStep, setAddStep] = useState(1);
|
||
// const [addMethod, setAddMethod] = useState<'text' | 'file' | 'scan'>('text');
|
||
// const [addVerified, setAddVerified] = useState(false);
|
||
// const [rehearsalConfirmed, setRehearsalConfirmed] = useState(false);
|
||
// const [selectedType, setSelectedType] = useState<VaultAssetType>('custom');
|
||
// const [newLabel, setNewLabel] = useState('');
|
||
// const [treasureContent, setTreasureContent] = useState('');
|
||
// const [accountProvider, setAccountProvider] = useState<'bank' | 'steam' | 'facebook' | 'custom'>('bank');
|
||
|
||
// 新代码:使用 useAddFlow hook
|
||
const addFlow = useAddFlow();
|
||
|
||
// 原来的代码:
|
||
// const [mnemonicWords, setMnemonicWords] = useState<string[]>([]);
|
||
// const [mnemonicParts, setMnemonicParts] = useState<string[][]>([]);
|
||
// const [mnemonicStep, setMnemonicStep] = useState<1 | 2 | 3 | 4 | 5>(1);
|
||
// const [heirStep, setHeirStep] = useState<'decision' | 'asset' | 'heir' | 'summary'>('decision');
|
||
// const [replaceIndex, setReplaceIndex] = useState<number | null>(null);
|
||
// const [replaceQuery, setReplaceQuery] = useState('');
|
||
// const [progressIndex, setProgressIndex] = useState(0);
|
||
// const [isCapturing, setIsCapturing] = useState(false);
|
||
|
||
// 新代码:使用 useMnemonicFlow hook
|
||
const mnemonicFlow = useMnemonicFlow();
|
||
|
||
// ... 其他状态保持不变
|
||
|
||
// ============================================
|
||
// 3. 更新 resetAddFlow 函数
|
||
// ============================================
|
||
|
||
const resetAddFlow = () => {
|
||
// 原来的代码:需要手动重置每个状态
|
||
// setAddStep(1);
|
||
// setAddMethod('text');
|
||
// setAddVerified(false);
|
||
// setRehearsalConfirmed(false);
|
||
// setSelectedType('custom');
|
||
// setNewLabel('');
|
||
// setAccountProvider('bank');
|
||
|
||
// 新代码:一行搞定
|
||
addFlow.reset();
|
||
};
|
||
|
||
// ============================================
|
||
// 4. 使用 AssetCard 组件渲染资产列表
|
||
// ============================================
|
||
|
||
// 原来的代码(在 return 语句中的资产列表部分,第 1089-1159 行):
|
||
/*
|
||
<ScrollView
|
||
style={styles.assetList}
|
||
showsVerticalScrollIndicator={false}
|
||
contentContainerStyle={styles.assetListContent}
|
||
>
|
||
{assets.map((asset, index) => {
|
||
const config = assetTypeConfig[asset.type];
|
||
|
||
if (!assetAnimations.current.has(asset.id)) {
|
||
const anim = new Animated.Value(0);
|
||
assetAnimations.current.set(asset.id, anim);
|
||
Animated.spring(anim, {
|
||
toValue: 1,
|
||
useNativeDriver: true,
|
||
tension: 65,
|
||
friction: 10,
|
||
delay: index * 80,
|
||
}).start();
|
||
}
|
||
|
||
const animValue = assetAnimations.current.get(asset.id) || new Animated.Value(1);
|
||
|
||
return (
|
||
<Animated.View
|
||
key={asset.id}
|
||
style={{
|
||
opacity: animValue,
|
||
transform: [
|
||
{
|
||
translateY: animValue.interpolate({
|
||
inputRange: [0, 1],
|
||
outputRange: [30, 0],
|
||
}),
|
||
},
|
||
{
|
||
scale: animValue.interpolate({
|
||
inputRange: [0, 1],
|
||
outputRange: [0.92, 1],
|
||
}),
|
||
},
|
||
],
|
||
}}
|
||
>
|
||
<TouchableOpacity
|
||
style={styles.assetCard}
|
||
activeOpacity={0.7}
|
||
onPress={() => handleOpenDetail(asset)}
|
||
>
|
||
<View style={styles.assetIconContainer}>
|
||
{renderAssetTypeIcon(config, 24, colors.vault.primary)}
|
||
</View>
|
||
<View style={styles.assetInfo}>
|
||
<Text style={styles.assetType}>{config.label}</Text>
|
||
<Text style={styles.assetLabel}>{asset.label}</Text>
|
||
<View style={styles.assetMetaRow}>
|
||
<Feather name="clock" size={11} color={colors.vault.textSecondary} />
|
||
<Text style={styles.assetMeta}>Sealed {formatDate(asset.createdAt)}</Text>
|
||
</View>
|
||
</View>
|
||
<View style={styles.encryptedBadge}>
|
||
<MaterialCommunityIcons name="lock" size={18} color="#fff" />
|
||
</View>
|
||
</TouchableOpacity>
|
||
</Animated.View>
|
||
);
|
||
})}
|
||
<View style={{ height: 100 }} />
|
||
</ScrollView>
|
||
*/
|
||
|
||
// 新代码:简洁清晰
|
||
const renderAssetList = () => (
|
||
<ScrollView
|
||
style={styles.assetList}
|
||
showsVerticalScrollIndicator={false}
|
||
contentContainerStyle={styles.assetListContent}
|
||
>
|
||
{assets.map((asset, index) => (
|
||
<AssetCard
|
||
key={asset.id}
|
||
asset={asset}
|
||
index={index}
|
||
onPress={handleOpenDetail}
|
||
/>
|
||
))}
|
||
<View style={{ height: 100 }} />
|
||
</ScrollView>
|
||
);
|
||
|
||
// ============================================
|
||
// 5. 使用 VaultButton 组件替换按钮
|
||
// ============================================
|
||
|
||
// 原来的代码(解锁按钮,第 1026-1041 行):
|
||
/*
|
||
<TouchableOpacity
|
||
style={styles.unlockButton}
|
||
onPress={handleUnlock}
|
||
activeOpacity={0.9}
|
||
>
|
||
<LinearGradient
|
||
colors={[colors.vault.primary, colors.vault.secondary]}
|
||
style={styles.unlockButtonGradient}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 1 }}
|
||
>
|
||
<Ionicons
|
||
name="finger-print"
|
||
size={20}
|
||
color={colors.vault.background}
|
||
/>
|
||
<Text style={styles.unlockButtonText}>
|
||
{hasS0 ? 'Captain\'s Verification' : 'Enter Vault'}
|
||
</Text>
|
||
</LinearGradient>
|
||
</TouchableOpacity>
|
||
*/
|
||
|
||
// 新代码:
|
||
const renderUnlockButton = () => (
|
||
<VaultButton
|
||
variant="primary"
|
||
icon="finger-print"
|
||
onPress={handleUnlock}
|
||
style={styles.unlockButton}
|
||
>
|
||
{hasS0 ? "Captain's Verification" : "Enter Vault"}
|
||
</VaultButton>
|
||
);
|
||
|
||
// 原来的代码(添加按钮,第 1162-1180 行):
|
||
/*
|
||
<TouchableOpacity
|
||
style={styles.addButton}
|
||
onPress={() => {
|
||
resetAddFlow();
|
||
clearAddError();
|
||
setShowAddModal(true);
|
||
}}
|
||
activeOpacity={0.9}
|
||
>
|
||
<LinearGradient
|
||
colors={[colors.vault.primary, colors.vault.secondary]}
|
||
style={styles.addButtonGradient}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 0 }}
|
||
>
|
||
<FontAwesome5 name="plus" size={16} color={colors.vault.background} />
|
||
<Text style={styles.addButtonText}>Add Treasure</Text>
|
||
</LinearGradient>
|
||
</TouchableOpacity>
|
||
*/
|
||
|
||
// 新代码:
|
||
const renderAddButton = () => (
|
||
<VaultButton
|
||
variant="primary"
|
||
icon="plus"
|
||
onPress={() => {
|
||
resetAddFlow();
|
||
clearAddError();
|
||
setShowAddModal(true);
|
||
}}
|
||
style={styles.addButton}
|
||
>
|
||
Add Treasure
|
||
</VaultButton>
|
||
);
|
||
|
||
// ============================================
|
||
// 6. 使用 LabeledInput 组件替换输入框
|
||
// ============================================
|
||
|
||
// 在 Add Modal 中(第 1238-1245 行):
|
||
/*
|
||
<Text style={styles.modalLabel}>TREASURE TITLE</Text>
|
||
<TextInput
|
||
style={styles.input}
|
||
placeholder="e.g., Main wallet mnemonic"
|
||
placeholderTextColor={colors.nautical.sage}
|
||
value={newLabel}
|
||
onChangeText={setNewLabel}
|
||
/>
|
||
*/
|
||
|
||
// 新代码:
|
||
const renderTitleInput = () => (
|
||
<LabeledInput
|
||
label="TREASURE TITLE"
|
||
placeholder="e.g., Main wallet mnemonic"
|
||
value={addFlow.state.label}
|
||
onChangeText={addFlow.setLabel}
|
||
/>
|
||
);
|
||
|
||
// 在 Add Modal 内容步骤中(第 1305-1315 行):
|
||
/*
|
||
<Text style={styles.modalLabel}>CONTENT</Text>
|
||
<TextInput
|
||
style={[styles.input, styles.inputMultiline]}
|
||
placeholder="Enter content to seal (plaintext is encrypted locally before upload)"
|
||
placeholderTextColor={colors.nautical.sage}
|
||
value={treasureContent}
|
||
onChangeText={setTreasureContent}
|
||
multiline
|
||
numberOfLines={6}
|
||
textAlignVertical="top"
|
||
/>
|
||
*/
|
||
|
||
// 新代码:
|
||
const renderContentInput = () => (
|
||
<LabeledInput
|
||
label="CONTENT"
|
||
placeholder="Enter content to seal (plaintext is encrypted locally before upload)"
|
||
value={addFlow.state.content}
|
||
onChangeText={addFlow.setContent}
|
||
multiline
|
||
/>
|
||
);
|
||
|
||
// ============================================
|
||
// 7. 在 Modal 中使用 VaultButton
|
||
// ============================================
|
||
|
||
// 原来的模态框按钮代码(第 1428-1481 行):
|
||
/*
|
||
<View style={styles.modalButtons}>
|
||
<TouchableOpacity
|
||
style={styles.cancelButton}
|
||
onPress={() => {
|
||
if (addStep === 1) {
|
||
setShowAddModal(false);
|
||
setTreasureContent('');
|
||
clearAddError();
|
||
} else {
|
||
setAddStep(addStep - 1);
|
||
clearAddError();
|
||
}
|
||
}}
|
||
>
|
||
<Text style={styles.cancelButtonText}>
|
||
{addStep === 1 ? 'Cancel' : 'Back'}
|
||
</Text>
|
||
</TouchableOpacity>
|
||
|
||
{addStep < 3 ? (
|
||
<TouchableOpacity
|
||
style={styles.confirmButton}
|
||
onPress={() => setAddStep(addStep + 1)}
|
||
>
|
||
<LinearGradient
|
||
colors={[colors.nautical.teal, colors.nautical.seafoam]}
|
||
style={styles.confirmButtonGradient}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 0 }}
|
||
>
|
||
<Text style={styles.confirmButtonText}>Continue</Text>
|
||
</LinearGradient>
|
||
</TouchableOpacity>
|
||
) : (
|
||
<TouchableOpacity
|
||
style={styles.confirmButton}
|
||
onPress={handleAddAsset}
|
||
activeOpacity={canSeal ? 0.9 : 1}
|
||
disabled={!canSeal}
|
||
>
|
||
<LinearGradient
|
||
colors={[colors.nautical.teal, colors.nautical.seafoam]}
|
||
style={[
|
||
styles.confirmButtonGradient,
|
||
!canSeal && styles.confirmButtonGradientDisabled,
|
||
]}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 0 }}
|
||
>
|
||
<MaterialCommunityIcons name="lock" size={18} color="#fff" />
|
||
<Text style={styles.confirmButtonText}>{isSealing ? 'Sealing...' : 'Seal Treasure'}</Text>
|
||
</LinearGradient>
|
||
</TouchableOpacity>
|
||
)}
|
||
</View>
|
||
*/
|
||
|
||
// 新代码:
|
||
const renderModalButtons = () => {
|
||
const canSeal = addFlow.canProceed();
|
||
|
||
return (
|
||
<View style={styles.modalButtons}>
|
||
<VaultButton
|
||
variant="secondary"
|
||
onPress={() => {
|
||
if (addFlow.state.step === 1) {
|
||
setShowAddModal(false);
|
||
addFlow.reset();
|
||
clearAddError();
|
||
} else {
|
||
addFlow.setStep(addFlow.state.step - 1);
|
||
clearAddError();
|
||
}
|
||
}}
|
||
fullWidth
|
||
>
|
||
{addFlow.state.step === 1 ? 'Cancel' : 'Back'}
|
||
</VaultButton>
|
||
|
||
{addFlow.state.step < 3 ? (
|
||
<VaultButton
|
||
variant="primary"
|
||
onPress={() => addFlow.setStep(addFlow.state.step + 1)}
|
||
fullWidth
|
||
>
|
||
Continue
|
||
</VaultButton>
|
||
) : (
|
||
<VaultButton
|
||
variant="primary"
|
||
icon="lock"
|
||
loading={isSealing}
|
||
disabled={!canSeal}
|
||
onPress={handleAddAsset}
|
||
fullWidth
|
||
>
|
||
{isSealing ? 'Sealing...' : 'Seal Treasure'}
|
||
</VaultButton>
|
||
)}
|
||
</View>
|
||
);
|
||
};
|
||
|
||
// ============================================
|
||
// 8. 使用 Hook 访问状态的示例
|
||
// ============================================
|
||
|
||
// 原来访问状态的方式:
|
||
// if (addStep === 1) { ... }
|
||
// if (mnemonicStep === 3) { ... }
|
||
// setAddStep(2)
|
||
// setMnemonicWords(words)
|
||
|
||
// 新的访问方式:
|
||
// if (addFlow.state.step === 1) { ... }
|
||
// if (mnemonicFlow.state.step === 3) { ... }
|
||
// addFlow.setStep(2)
|
||
// mnemonicFlow.setWords(words)
|
||
|
||
return (
|
||
// ... 使用上面定义的渲染函数
|
||
);
|
||
}
|
||
|
||
// ============================================
|
||
// 9. 可以删除的代码
|
||
// ============================================
|
||
|
||
/*
|
||
重构后可以删除以下内容:
|
||
|
||
1. 大量的状态变量声明(第 111-167 行)
|
||
2. assetAnimations ref 和相关逻辑(第 171 行及使用处)
|
||
3. 资产卡片的动画代码(已移到 AssetCard 组件)
|
||
4. 所有重复的按钮样式定义
|
||
5. 所有重复的输入框样式定义
|
||
|
||
StyleSheet 中可以删除:
|
||
- unlockButton, unlockButtonGradient, unlockButtonText
|
||
- addButton, addButtonGradient, addButtonText
|
||
- assetCard, assetIconContainer, assetInfo, assetType, assetLabel, assetMetaRow, assetMeta, encryptedBadge
|
||
- 大部分 modal 相关的样式(已移到 modalStyles.ts)
|
||
*/
|
||
|
||
// ============================================
|
||
// 10. 性能优化建议
|
||
// ============================================
|
||
|
||
/*
|
||
1. 使用 React.memo 包装 AssetCard 避免不必要的重渲染
|
||
2. 使用 useCallback 包装事件处理函数
|
||
3. 考虑使用 FlatList 替代 ScrollView(如果资产列表很长)
|
||
4. 延迟加载模态框组件(React.lazy)
|
||
|
||
示例:
|
||
const AssetList = React.memo(({ assets, onOpenDetail }) => (
|
||
assets.map((asset, index) => (
|
||
<AssetCard key={asset.id} asset={asset} index={index} onPress={onOpenDetail} />
|
||
))
|
||
));
|
||
|
||
const handleOpenDetail = useCallback((asset: VaultAsset) => {
|
||
setSelectedAsset(asset);
|
||
setShowDetail(true);
|
||
}, []);
|
||
*/
|