feat(mobile): Phase M-1 모바일 프로젝트 기반 + V3 마스터 플랜
- V3 모바일 마스터 플랜 작성 (docs/v3/00-mobile-master-plan.md) 11개 Phase, 5주 로드맵, 전략 결정사항 확정 - 7개 디자인 HTML 레퍼런스 저장 (docs/v3/designs/) - app.json → app.config.ts 전환 + 환경변수 체계 - 5탭 네비게이션 (DASH/HIST/REC FAB/TALK/SET) - metro.config.js monorepo 격리 (root RN 0.84 충돌 해결) - ui-native 테마 디자인 목업 색상 동기화 - SafeArea 적용 (useSafeAreaInsets) - DEV 로그인 우회 (__DEV__ 전용) - Supabase .env 연동 - iOS 시뮬레이터 검증 완료
This commit is contained in:
parent
ffca07d120
commit
211673bc6c
30 changed files with 15010 additions and 525 deletions
204
apps/mobile/app/(tabs)/settings.tsx
Normal file
204
apps/mobile/app/(tabs)/settings.tsx
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
// apps/mobile/app/(tabs)/settings.tsx
|
||||
// 설정 탭 — 계정, 백엔드, 환경설정
|
||||
// Phase M-2에서 디자인(docs/v3/designs/settings.html) 정밀 적용
|
||||
|
||||
import { View, ScrollView, StyleSheet, Alert, Switch } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { MetalCard, PhosphorText, PhysicalButton, Led, d3roNativePalette } from '@d3ro/ui-native'
|
||||
import { useAuth } from '../../lib/auth-context'
|
||||
import { supabase } from '../../lib/supabase'
|
||||
|
||||
export default function SettingsScreen(): React.ReactElement {
|
||||
const insets = useSafeAreaInsets()
|
||||
const { user } = useAuth()
|
||||
|
||||
async function handleLogout(): Promise<void> {
|
||||
Alert.alert('Logout', 'Are you sure you want to log out?', [
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Logout',
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
await supabase.auth.signOut()
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
const initials = user?.email
|
||||
? user.email.substring(0, 2).toUpperCase()
|
||||
: 'US'
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
|
||||
{/* Header */}
|
||||
<PhosphorText variant="title" color="primary" style={[styles.title, { paddingTop: insets.top + 8 }]}>
|
||||
Settings
|
||||
</PhosphorText>
|
||||
|
||||
{/* Account Section */}
|
||||
<PhosphorText variant="label" color="muted" style={styles.sectionLabel}>
|
||||
ACCOUNT & PLAN
|
||||
</PhosphorText>
|
||||
<MetalCard style={styles.section}>
|
||||
<View style={styles.profileRow}>
|
||||
<View style={styles.avatar}>
|
||||
<PhosphorText variant="body" color="amber">{initials}</PhosphorText>
|
||||
</View>
|
||||
<View style={styles.profileInfo}>
|
||||
<PhosphorText variant="body" color="primary">
|
||||
{user?.email?.split('@')[0] ?? 'User'}
|
||||
</PhosphorText>
|
||||
<PhosphorText variant="label" color="muted">
|
||||
{user?.email ?? '—'}
|
||||
</PhosphorText>
|
||||
</View>
|
||||
</View>
|
||||
<View style={[styles.row, { backgroundColor: d3roNativePalette.bg.inset }]}>
|
||||
<PhosphorText variant="small" color="muted">TIER</PhosphorText>
|
||||
<View style={styles.rowRight}>
|
||||
<Led color="amber" size={6} />
|
||||
<PhosphorText variant="body" color="amber" style={{ marginLeft: 8 }}>
|
||||
FREE
|
||||
</PhosphorText>
|
||||
</View>
|
||||
</View>
|
||||
</MetalCard>
|
||||
|
||||
{/* Backend Section */}
|
||||
<PhosphorText variant="label" color="muted" style={styles.sectionLabel}>
|
||||
BACKEND CONFIG
|
||||
</PhosphorText>
|
||||
<MetalCard style={styles.section}>
|
||||
<View style={styles.row}>
|
||||
<View>
|
||||
<PhosphorText variant="body" color="primary">LLM Model</PhosphorText>
|
||||
<PhosphorText variant="label" color="muted">AI processing backend</PhosphorText>
|
||||
</View>
|
||||
<PhosphorText variant="body" color="amber">CLAUDE</PhosphorText>
|
||||
</View>
|
||||
<View style={[styles.row, styles.rowBorder]}>
|
||||
<View>
|
||||
<PhosphorText variant="body" color="primary">Cloud STT</PhosphorText>
|
||||
<PhosphorText variant="label" color="muted">Google Cloud Speech</PhosphorText>
|
||||
</View>
|
||||
<Switch
|
||||
value={true}
|
||||
trackColor={{
|
||||
false: d3roNativePalette.bg.inset,
|
||||
true: d3roNativePalette.accent.amber
|
||||
}}
|
||||
thumbColor="#ffffff"
|
||||
/>
|
||||
</View>
|
||||
</MetalCard>
|
||||
|
||||
{/* Preferences Section */}
|
||||
<PhosphorText variant="label" color="muted" style={styles.sectionLabel}>
|
||||
PREFERENCES
|
||||
</PhosphorText>
|
||||
<MetalCard style={styles.section}>
|
||||
<View style={styles.row}>
|
||||
<PhosphorText variant="body" color="primary">Language</PhosphorText>
|
||||
<PhosphorText variant="body" color="muted">Korean</PhosphorText>
|
||||
</View>
|
||||
<View style={[styles.row, styles.rowBorder]}>
|
||||
<PhosphorText variant="body" color="primary">Auto Polish</PhosphorText>
|
||||
<Switch
|
||||
value={true}
|
||||
trackColor={{
|
||||
false: d3roNativePalette.bg.inset,
|
||||
true: d3roNativePalette.accent.amber
|
||||
}}
|
||||
thumbColor="#ffffff"
|
||||
/>
|
||||
</View>
|
||||
<View style={[styles.row, styles.rowBorder]}>
|
||||
<PhosphorText variant="body" color="primary">Haptic Feedback</PhosphorText>
|
||||
<Switch
|
||||
value={true}
|
||||
trackColor={{
|
||||
false: d3roNativePalette.bg.inset,
|
||||
true: d3roNativePalette.accent.amber
|
||||
}}
|
||||
thumbColor="#ffffff"
|
||||
/>
|
||||
</View>
|
||||
</MetalCard>
|
||||
|
||||
{/* Logout */}
|
||||
<View style={styles.logoutWrap}>
|
||||
<PhysicalButton label="LOGOUT" variant="secondary" onPress={() => void handleLogout()} />
|
||||
</View>
|
||||
|
||||
{/* Status Footer */}
|
||||
<View style={styles.footer}>
|
||||
<Led color="green" size={6} />
|
||||
<PhosphorText variant="label" color="muted" style={{ marginLeft: 6, letterSpacing: 1 }}>
|
||||
CLOUD CONNECTED
|
||||
</PhosphorText>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: d3roNativePalette.bg.app },
|
||||
content: { paddingBottom: 120 },
|
||||
title: {
|
||||
paddingHorizontal: 20,
|
||||
paddingBottom: 12,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: 'rgba(46, 46, 50, 0.5)',
|
||||
fontFamily: undefined
|
||||
},
|
||||
sectionLabel: {
|
||||
paddingHorizontal: 24,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 8,
|
||||
letterSpacing: 3
|
||||
},
|
||||
section: {
|
||||
marginHorizontal: 20,
|
||||
padding: 0,
|
||||
overflow: 'hidden'
|
||||
},
|
||||
profileRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: 'rgba(46, 46, 50, 0.5)'
|
||||
},
|
||||
avatar: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: d3roNativePalette.bg.inset,
|
||||
borderWidth: 1,
|
||||
borderColor: d3roNativePalette.border.default,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
profileInfo: { gap: 2 },
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: 16
|
||||
},
|
||||
rowBorder: {
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: 'rgba(46, 46, 50, 0.5)'
|
||||
},
|
||||
rowRight: { flexDirection: 'row', alignItems: 'center' },
|
||||
logoutWrap: { margin: 20 },
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
opacity: 0.5,
|
||||
marginTop: 16
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue