mirror of
https://github.com/mudabbir-ahmad/Media-Aggregation-and-Sorting-System.git
synced 2026-10-07 19:40:20 +00:00
refactored code into components (major cleanup for reused code) added email for local acccount creation and changes to how nas and google photo connections work and added themes
This commit is contained in:
1 parent
c1d7139055
commit
6f4ec66e2e
17 files changed
+1761
-1018
No files matched your search
+146
-185
@@ -1,21 +1,17 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
Switch,
|
||||
TextInput,
|
||||
StyleSheet, View, Text, ScrollView, TouchableOpacity, Alert,
|
||||
ActivityIndicator, Switch, TextInput,
|
||||
} from 'react-native';
|
||||
import { useTheme } from '../services/ThemeContext';
|
||||
import DatabaseService from '../services/DatabaseService';
|
||||
import GoogleAUTH from '../AUTH/GoogleAUTH';
|
||||
import NASAUTH from '../AUTH/NASAUTH';
|
||||
import NASSetupInstructions from '../components/NASSetupInstructions';
|
||||
|
||||
const OnboardingScreen = ({ navigation, route }) => {
|
||||
const { userId } = route.params;
|
||||
const { theme } = useTheme();
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -36,20 +32,20 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
const [nasPassword, setNasPassword] = useState('');
|
||||
const [nasPhotoFolder, setNasPhotoFolder] = useState('/home/user/photos');
|
||||
|
||||
// Default service
|
||||
const [defaultService, setDefaultService] = useState(null);
|
||||
// Auto-backup checklist (multi-select)
|
||||
const [autoBackupServices, setAutoBackupServices] = useState([]);
|
||||
|
||||
const steps = [
|
||||
{ title: 'Choose Services', description: 'Select which photo services to connect (1-3)' },
|
||||
{ title: 'Connect Services', description: 'Set up each selected service' },
|
||||
{ title: 'Default Upload', description: 'Choose where new photos upload by default' },
|
||||
{ title: 'Automatic Backup', description: 'Choose where new photos are backed up' },
|
||||
];
|
||||
|
||||
const getEnabledServices = () => {
|
||||
const getConnectedServices = () => {
|
||||
const services = [];
|
||||
if (googleEnabled) services.push({ name: 'Google Photos', type: 'GOOGLE_PHOTOS' });
|
||||
if (iosEnabled) services.push({ name: 'iCloud Photos', type: 'ICLOUD_PHOTOS' });
|
||||
if (nasEnabled) services.push({ name: 'NAS Storage', type: 'NAS' });
|
||||
if (googleEnabled && googleConnected) services.push({ name: 'Google Photos', type: 'GOOGLE_PHOTOS', icon: '📷' });
|
||||
if (iosEnabled && iosConnected) services.push({ name: 'iCloud Photos', type: 'ICLOUD_PHOTOS', icon: '🍎' });
|
||||
if (nasEnabled && nasConnected) services.push({ name: 'NAS Storage', type: 'NAS', icon: '💾' });
|
||||
return services;
|
||||
};
|
||||
|
||||
@@ -78,12 +74,10 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
const handleIosAuth = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
// Placeholder - iCloud API not yet available
|
||||
await DatabaseService.linkAccount(userId, 'ICLOUD_PHOTOS', {
|
||||
status: 'placeholder',
|
||||
note: 'iCloud integration pending Apple API access',
|
||||
});
|
||||
|
||||
setIosConnected(true);
|
||||
Alert.alert('Info', 'iCloud Photos registered. Full integration coming soon.');
|
||||
} catch (error) {
|
||||
@@ -99,25 +93,19 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
Alert.alert('Error', 'Please fill in all NAS connection fields');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const nasAuth = new NASAUTH();
|
||||
await nasAuth.authenticate(
|
||||
nasHost.trim(),
|
||||
parseInt(nasPort) || 22,
|
||||
nasUsername.trim(),
|
||||
nasPassword,
|
||||
nasPhotoFolder.trim()
|
||||
nasHost.trim(), parseInt(nasPort) || 22,
|
||||
nasUsername.trim(), nasPassword, nasPhotoFolder.trim()
|
||||
);
|
||||
|
||||
await DatabaseService.linkAccount(userId, 'NAS', {
|
||||
host: nasHost.trim(),
|
||||
port: parseInt(nasPort) || 22,
|
||||
username: nasUsername.trim(),
|
||||
photoFolder: nasPhotoFolder.trim(),
|
||||
});
|
||||
|
||||
setNasConnected(true);
|
||||
Alert.alert('Success', 'NAS connected!');
|
||||
} catch (error) {
|
||||
@@ -128,38 +116,28 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const toggleAutoBackup = (serviceType) => {
|
||||
setAutoBackupServices((prev) =>
|
||||
prev.includes(serviceType) ? prev.filter((s) => s !== serviceType) : [...prev, serviceType]
|
||||
);
|
||||
};
|
||||
|
||||
const handleNext = async () => {
|
||||
if (currentStep === 0) {
|
||||
if (getEnabledServices().length === 0) {
|
||||
Alert.alert('Error', 'Please select at least one service');
|
||||
return;
|
||||
}
|
||||
const any = googleEnabled || iosEnabled || nasEnabled;
|
||||
if (!any) { Alert.alert('Error', 'Please select at least one service'); return; }
|
||||
setCurrentStep(1);
|
||||
} else if (currentStep === 1) {
|
||||
// Check at least one service is connected
|
||||
const anyConnected =
|
||||
(googleEnabled && googleConnected) ||
|
||||
(iosEnabled && iosConnected) ||
|
||||
(nasEnabled && nasConnected);
|
||||
|
||||
if (!anyConnected) {
|
||||
Alert.alert('Error', 'Please connect at least one service before continuing');
|
||||
return;
|
||||
}
|
||||
if (!anyConnected) { Alert.alert('Error', 'Please connect at least one service'); return; }
|
||||
setCurrentStep(2);
|
||||
} else if (currentStep === 2) {
|
||||
if (!defaultService) {
|
||||
Alert.alert('Error', 'Please select a default upload service');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const accounts = await DatabaseService.getLinkedAccounts(userId);
|
||||
const defaultAccount = accounts.find((a) => a.service_type === defaultService);
|
||||
if (defaultAccount) {
|
||||
await DatabaseService.setDefaultService(userId, defaultAccount.id);
|
||||
}
|
||||
await DatabaseService.setAutoBackupServices(userId, autoBackupServices);
|
||||
navigation.replace('MainTabs', { userId });
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to complete setup: ' + error.message);
|
||||
@@ -170,45 +148,36 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.container, { backgroundColor: theme.background }]}>
|
||||
{/* Progress bar */}
|
||||
<View style={styles.progressBar}>
|
||||
{steps.map((_, i) => (
|
||||
<View key={i} style={[styles.progressDot, i <= currentStep && styles.progressDotActive]} />
|
||||
<View key={i} style={[styles.progressDot, { backgroundColor: i <= currentStep ? theme.primary : theme.border }]} />
|
||||
))}
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.stepLabel}>Step {currentStep + 1} of {steps.length}</Text>
|
||||
<Text style={styles.title}>{steps[currentStep].title}</Text>
|
||||
<Text style={styles.description}>{steps[currentStep].description}</Text>
|
||||
<Text style={[styles.stepLabel, { color: theme.primary }]}>Step {currentStep + 1} of {steps.length}</Text>
|
||||
<Text style={[styles.title, { color: theme.text }]}>{steps[currentStep].title}</Text>
|
||||
<Text style={[styles.description, { color: theme.textSecondary }]}>{steps[currentStep].description}</Text>
|
||||
</View>
|
||||
|
||||
{/* Step 0: Select services */}
|
||||
{currentStep === 0 && (
|
||||
<View style={styles.cardsContainer}>
|
||||
<ServiceToggleCard
|
||||
icon="📷"
|
||||
name="Google Photos"
|
||||
<ServiceToggleCard theme={theme} icon="📷" name="Google Photos"
|
||||
description="Access your Google Photos library"
|
||||
enabled={googleEnabled}
|
||||
onToggle={() => setGoogleEnabled(!googleEnabled)}
|
||||
/>
|
||||
<ServiceToggleCard
|
||||
icon="🍎"
|
||||
name="iCloud Photos"
|
||||
enabled={googleEnabled} onToggle={() => setGoogleEnabled(!googleEnabled)} />
|
||||
<ServiceToggleCard theme={theme} icon="🍎" name="iCloud Photos"
|
||||
description="Access your iCloud photo library (placeholder)"
|
||||
enabled={iosEnabled}
|
||||
onToggle={() => setIosEnabled(!iosEnabled)}
|
||||
/>
|
||||
<ServiceToggleCard
|
||||
icon="💾"
|
||||
name="NAS Storage"
|
||||
enabled={iosEnabled} onToggle={() => setIosEnabled(!iosEnabled)} />
|
||||
<ServiceToggleCard theme={theme} icon="💾" name="NAS Storage"
|
||||
description="Connect to your Ubuntu server via SFTP"
|
||||
enabled={nasEnabled}
|
||||
onToggle={() => setNasEnabled(!nasEnabled)}
|
||||
/>
|
||||
enabled={nasEnabled} onToggle={() => setNasEnabled(!nasEnabled)} />
|
||||
|
||||
{/* NAS setup instructions dropdown */}
|
||||
{nasEnabled && <NASSetupInstructions />}
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -216,84 +185,75 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
{currentStep === 1 && (
|
||||
<View style={styles.cardsContainer}>
|
||||
{googleEnabled && (
|
||||
<View style={styles.configCard}>
|
||||
<View style={[styles.configCard, { backgroundColor: theme.card, borderColor: theme.border }]}>
|
||||
<View style={styles.configHeader}>
|
||||
<Text style={styles.configIcon}>📷</Text>
|
||||
<Text style={styles.configTitle}>Google Photos</Text>
|
||||
{googleConnected && <Text style={styles.connectedBadge}>✓ Connected</Text>}
|
||||
<Text style={[styles.configTitle, { color: theme.text }]}>Google Photos</Text>
|
||||
{googleConnected && <Text style={[styles.connectedBadge, { color: theme.accent }]}>✓ Connected</Text>}
|
||||
</View>
|
||||
{!googleConnected && (
|
||||
<TouchableOpacity
|
||||
style={[styles.authButton, loading && styles.buttonDisabled]}
|
||||
onPress={handleGoogleAuth}
|
||||
disabled={loading}
|
||||
style={[styles.authButton, { backgroundColor: theme.primary }, loading && styles.buttonDisabled]}
|
||||
onPress={handleGoogleAuth} disabled={loading}
|
||||
>
|
||||
{loading ? <ActivityIndicator color="#fff" /> : (
|
||||
<Text style={styles.authButtonText}>Sign in with Google</Text>
|
||||
)}
|
||||
{loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.authButtonText}>Sign in with Google</Text>}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{iosEnabled && (
|
||||
<View style={styles.configCard}>
|
||||
<View style={[styles.configCard, { backgroundColor: theme.card, borderColor: theme.border }]}>
|
||||
<View style={styles.configHeader}>
|
||||
<Text style={styles.configIcon}>🍎</Text>
|
||||
<Text style={styles.configTitle}>iCloud Photos</Text>
|
||||
{iosConnected && <Text style={styles.connectedBadge}>✓ Connected</Text>}
|
||||
<Text style={[styles.configTitle, { color: theme.text }]}>iCloud Photos</Text>
|
||||
{iosConnected && <Text style={[styles.connectedBadge, { color: theme.accent }]}>✓ Connected</Text>}
|
||||
</View>
|
||||
{!iosConnected && (
|
||||
<TouchableOpacity
|
||||
style={[styles.authButton, { backgroundColor: '#333' }, loading && styles.buttonDisabled]}
|
||||
onPress={handleIosAuth}
|
||||
disabled={loading}
|
||||
onPress={handleIosAuth} disabled={loading}
|
||||
>
|
||||
{loading ? <ActivityIndicator color="#fff" /> : (
|
||||
<Text style={styles.authButtonText}>Connect iCloud</Text>
|
||||
)}
|
||||
{loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.authButtonText}>Connect iCloud</Text>}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{nasEnabled && (
|
||||
<View style={styles.configCard}>
|
||||
<View style={[styles.configCard, { backgroundColor: theme.card, borderColor: theme.border }]}>
|
||||
<View style={styles.configHeader}>
|
||||
<Text style={styles.configIcon}>💾</Text>
|
||||
<Text style={styles.configTitle}>NAS Storage</Text>
|
||||
{nasConnected && <Text style={styles.connectedBadge}>✓ Connected</Text>}
|
||||
<Text style={[styles.configTitle, { color: theme.text }]}>NAS Storage</Text>
|
||||
{nasConnected && <Text style={[styles.connectedBadge, { color: theme.accent }]}>✓ Connected</Text>}
|
||||
</View>
|
||||
{!nasConnected && (
|
||||
<>
|
||||
<Text style={styles.fieldLabel}>Server Address</Text>
|
||||
<TextInput style={styles.fieldInput} placeholder="192.168.1.100" value={nasHost}
|
||||
onChangeText={setNasHost} editable={!loading} placeholderTextColor="#9aa0a6" />
|
||||
<Text style={[styles.fieldLabel, { color: theme.textSecondary }]}>Server Address</Text>
|
||||
<TextInput style={[styles.fieldInput, { backgroundColor: theme.inputBg, borderColor: theme.border, color: theme.text }]}
|
||||
placeholder="192.168.1.100" value={nasHost} onChangeText={setNasHost} editable={!loading} placeholderTextColor={theme.textTertiary} />
|
||||
|
||||
<Text style={styles.fieldLabel}>Port</Text>
|
||||
<TextInput style={styles.fieldInput} placeholder="22" value={nasPort}
|
||||
onChangeText={setNasPort} editable={!loading} keyboardType="numeric" placeholderTextColor="#9aa0a6" />
|
||||
<Text style={[styles.fieldLabel, { color: theme.textSecondary }]}>Port</Text>
|
||||
<TextInput style={[styles.fieldInput, { backgroundColor: theme.inputBg, borderColor: theme.border, color: theme.text }]}
|
||||
placeholder="22" value={nasPort} onChangeText={setNasPort} editable={!loading} keyboardType="numeric" placeholderTextColor={theme.textTertiary} />
|
||||
|
||||
<Text style={styles.fieldLabel}>Username</Text>
|
||||
<TextInput style={styles.fieldInput} placeholder="SSH username" value={nasUsername}
|
||||
onChangeText={setNasUsername} editable={!loading} autoCapitalize="none" placeholderTextColor="#9aa0a6" />
|
||||
<Text style={[styles.fieldLabel, { color: theme.textSecondary }]}>Username</Text>
|
||||
<TextInput style={[styles.fieldInput, { backgroundColor: theme.inputBg, borderColor: theme.border, color: theme.text }]}
|
||||
placeholder="SSH username" value={nasUsername} onChangeText={setNasUsername} editable={!loading} autoCapitalize="none" placeholderTextColor={theme.textTertiary} />
|
||||
|
||||
<Text style={styles.fieldLabel}>Password</Text>
|
||||
<TextInput style={styles.fieldInput} placeholder="SSH password" value={nasPassword}
|
||||
onChangeText={setNasPassword} editable={!loading} secureTextEntry autoCapitalize="none" placeholderTextColor="#9aa0a6" />
|
||||
<Text style={[styles.fieldLabel, { color: theme.textSecondary }]}>Password</Text>
|
||||
<TextInput style={[styles.fieldInput, { backgroundColor: theme.inputBg, borderColor: theme.border, color: theme.text }]}
|
||||
placeholder="SSH password" value={nasPassword} onChangeText={setNasPassword} editable={!loading} secureTextEntry autoCapitalize="none" placeholderTextColor={theme.textTertiary} />
|
||||
|
||||
<Text style={styles.fieldLabel}>Photos Folder</Text>
|
||||
<TextInput style={styles.fieldInput} placeholder="/home/user/photos" value={nasPhotoFolder}
|
||||
onChangeText={setNasPhotoFolder} editable={!loading} placeholderTextColor="#9aa0a6" />
|
||||
<Text style={[styles.fieldLabel, { color: theme.textSecondary }]}>Photos Folder</Text>
|
||||
<TextInput style={[styles.fieldInput, { backgroundColor: theme.inputBg, borderColor: theme.border, color: theme.text }]}
|
||||
placeholder="/home/user/photos" value={nasPhotoFolder} onChangeText={setNasPhotoFolder} editable={!loading} placeholderTextColor={theme.textTertiary} />
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.authButton, { backgroundColor: '#34a853' }, loading && styles.buttonDisabled]}
|
||||
onPress={handleNasAuth}
|
||||
disabled={loading}
|
||||
style={[styles.authButton, { backgroundColor: theme.accent }, loading && styles.buttonDisabled]}
|
||||
onPress={handleNasAuth} disabled={loading}
|
||||
>
|
||||
{loading ? <ActivityIndicator color="#fff" /> : (
|
||||
<Text style={styles.authButtonText}>Test & Connect</Text>
|
||||
)}
|
||||
{loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.authButtonText}>Test & Connect</Text>}
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
@@ -302,47 +262,65 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Step 2: Default service */}
|
||||
{/* Step 2: Auto-backup multi-checkbox */}
|
||||
{currentStep === 2 && (
|
||||
<View style={styles.cardsContainer}>
|
||||
{getEnabledServices().map((svc) => {
|
||||
const connected =
|
||||
(svc.type === 'GOOGLE_PHOTOS' && googleConnected) ||
|
||||
(svc.type === 'ICLOUD_PHOTOS' && iosConnected) ||
|
||||
(svc.type === 'NAS' && nasConnected);
|
||||
<View style={[styles.configCard, { backgroundColor: theme.card, borderColor: theme.border }]}>
|
||||
<Text style={[styles.checklistInfo, { color: theme.textSecondary }]}>
|
||||
Select which services new photos should automatically upload to. You can select multiple or none.
|
||||
</Text>
|
||||
|
||||
if (!connected) return null;
|
||||
|
||||
return (
|
||||
{getConnectedServices().map((svc) => (
|
||||
<TouchableOpacity
|
||||
key={svc.type}
|
||||
style={[styles.selectCard, defaultService === svc.type && styles.selectCardActive]}
|
||||
onPress={() => setDefaultService(svc.type)}
|
||||
style={[styles.checkRow, { borderBottomColor: theme.borderLight }]}
|
||||
onPress={() => toggleAutoBackup(svc.type)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={[styles.radio, defaultService === svc.type && styles.radioActive]} />
|
||||
<Text style={[styles.selectText, defaultService === svc.type && styles.selectTextActive]}>
|
||||
{svc.name}
|
||||
</Text>
|
||||
<View style={[
|
||||
styles.checkbox,
|
||||
{ borderColor: theme.primary },
|
||||
autoBackupServices.includes(svc.type) && { backgroundColor: theme.primary },
|
||||
]}>
|
||||
{autoBackupServices.includes(svc.type) && <Text style={styles.checkmark}>✓</Text>}
|
||||
</View>
|
||||
<Text style={styles.checkIcon}>{svc.icon}</Text>
|
||||
<Text style={[styles.checkLabel, { color: theme.text }]}>{svc.name}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
))}
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.checkRow, { borderBottomWidth: 0 }]}
|
||||
onPress={() => setAutoBackupServices([])}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={[
|
||||
styles.checkbox,
|
||||
{ borderColor: theme.border },
|
||||
autoBackupServices.length === 0 && { backgroundColor: theme.primary, borderColor: theme.primary },
|
||||
]}>
|
||||
{autoBackupServices.length === 0 && <Text style={styles.checkmark}>✓</Text>}
|
||||
</View>
|
||||
<Text style={[styles.checkLabel, { color: theme.text }]}>Don't automatically back up</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
|
||||
{/* Footer */}
|
||||
<View style={styles.footer}>
|
||||
<View style={[styles.footer, { borderTopColor: theme.border }]}>
|
||||
{currentStep > 0 ? (
|
||||
<TouchableOpacity style={styles.backButton} onPress={() => setCurrentStep(currentStep - 1)} disabled={loading}>
|
||||
<Text style={styles.backButtonText}>Back</Text>
|
||||
<TouchableOpacity style={[styles.backButton, { backgroundColor: theme.surface, borderColor: theme.border }]}
|
||||
onPress={() => setCurrentStep(currentStep - 1)} disabled={loading}>
|
||||
<Text style={[styles.backButtonText, { color: theme.textSecondary }]}>Back</Text>
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
<View style={{ flex: 1 }} />
|
||||
)}
|
||||
<TouchableOpacity
|
||||
style={[styles.nextButton, loading && styles.buttonDisabled]}
|
||||
onPress={handleNext}
|
||||
disabled={loading}
|
||||
style={[styles.nextButton, { backgroundColor: theme.primary }, loading && styles.buttonDisabled]}
|
||||
onPress={handleNext} disabled={loading}
|
||||
>
|
||||
{loading ? <ActivityIndicator color="#fff" /> : (
|
||||
<Text style={styles.nextButtonText}>
|
||||
@@ -355,99 +333,82 @@ const OnboardingScreen = ({ navigation, route }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const ServiceToggleCard = ({ icon, name, description, enabled, onToggle }) => (
|
||||
<View style={[styles.toggleCard, enabled && styles.toggleCardActive]}>
|
||||
const ServiceToggleCard = ({ theme, icon, name, description, enabled, onToggle }) => (
|
||||
<View style={[styles.toggleCard, { backgroundColor: theme.card, borderColor: enabled ? theme.primary : theme.border }]}>
|
||||
<View style={styles.toggleCardContent}>
|
||||
<Text style={styles.toggleIcon}>{icon}</Text>
|
||||
<View style={styles.toggleInfo}>
|
||||
<Text style={styles.toggleName}>{name}</Text>
|
||||
<Text style={styles.toggleDescription}>{description}</Text>
|
||||
<Text style={[styles.toggleName, { color: theme.text }]}>{name}</Text>
|
||||
<Text style={[styles.toggleDescription, { color: theme.textSecondary }]}>{description}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Switch
|
||||
value={enabled}
|
||||
onValueChange={onToggle}
|
||||
trackColor={{ false: '#dadce0', true: '#a8dab5' }}
|
||||
trackColor={{ false: theme.border, true: '#a8dab5' }}
|
||||
thumbColor={enabled ? '#34a853' : '#f4f3f4'}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: '#fff' },
|
||||
container: { flex: 1 },
|
||||
progressBar: {
|
||||
flexDirection: 'row', justifyContent: 'center', gap: 8,
|
||||
paddingTop: 60, paddingBottom: 8,
|
||||
},
|
||||
progressDot: {
|
||||
width: 32, height: 4, borderRadius: 2, backgroundColor: '#dadce0',
|
||||
},
|
||||
progressDotActive: { backgroundColor: '#1a73e8' },
|
||||
progressDot: { width: 32, height: 4, borderRadius: 2 },
|
||||
content: { flex: 1, paddingHorizontal: 20 },
|
||||
header: { marginBottom: 24 },
|
||||
stepLabel: { fontSize: 12, color: '#1a73e8', fontWeight: '600', marginBottom: 6 },
|
||||
title: { fontSize: 26, fontWeight: '700', color: '#202124', marginBottom: 6 },
|
||||
description: { fontSize: 14, color: '#5f6368' },
|
||||
stepLabel: { fontSize: 12, fontWeight: '600', marginBottom: 6 },
|
||||
title: { fontSize: 26, fontWeight: '700', marginBottom: 6 },
|
||||
description: { fontSize: 14 },
|
||||
cardsContainer: { gap: 12 },
|
||||
// Toggle cards (Step 0)
|
||||
toggleCard: {
|
||||
backgroundColor: '#f8f9fa', borderRadius: 12, padding: 16,
|
||||
flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center',
|
||||
borderWidth: 1.5, borderColor: '#e8eaed',
|
||||
borderRadius: 12, padding: 16, flexDirection: 'row',
|
||||
justifyContent: 'space-between', alignItems: 'center', borderWidth: 1.5,
|
||||
},
|
||||
toggleCardActive: { borderColor: '#1a73e8', backgroundColor: '#e8f0fe' },
|
||||
toggleCardContent: { flex: 1, flexDirection: 'row', alignItems: 'center' },
|
||||
toggleIcon: { fontSize: 28, marginRight: 14 },
|
||||
toggleInfo: { flex: 1 },
|
||||
toggleName: { fontSize: 15, fontWeight: '600', color: '#202124', marginBottom: 2 },
|
||||
toggleDescription: { fontSize: 12, color: '#5f6368' },
|
||||
toggleName: { fontSize: 15, fontWeight: '600', marginBottom: 2 },
|
||||
toggleDescription: { fontSize: 12 },
|
||||
// Config cards (Step 1)
|
||||
configCard: {
|
||||
backgroundColor: '#f8f9fa', borderRadius: 12, padding: 16,
|
||||
borderWidth: 1, borderColor: '#e8eaed',
|
||||
},
|
||||
configCard: { borderRadius: 12, padding: 16, borderWidth: 1 },
|
||||
configHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 12 },
|
||||
configIcon: { fontSize: 24, marginRight: 10 },
|
||||
configTitle: { fontSize: 16, fontWeight: '600', color: '#202124', flex: 1 },
|
||||
connectedBadge: { fontSize: 13, color: '#34a853', fontWeight: '600' },
|
||||
authButton: {
|
||||
backgroundColor: '#1a73e8', borderRadius: 8, paddingVertical: 12, alignItems: 'center',
|
||||
},
|
||||
configTitle: { fontSize: 16, fontWeight: '600', flex: 1 },
|
||||
connectedBadge: { fontSize: 13, fontWeight: '600' },
|
||||
authButton: { borderRadius: 8, paddingVertical: 12, alignItems: 'center', marginTop: 8 },
|
||||
authButtonText: { color: '#fff', fontSize: 14, fontWeight: '600' },
|
||||
fieldLabel: { fontSize: 12, fontWeight: '600', color: '#3c4043', marginTop: 10, marginBottom: 4 },
|
||||
fieldLabel: { fontSize: 12, fontWeight: '600', marginTop: 10, marginBottom: 4 },
|
||||
fieldInput: {
|
||||
borderWidth: 1, borderColor: '#dadce0', borderRadius: 8,
|
||||
paddingHorizontal: 12, paddingVertical: 10, fontSize: 14,
|
||||
backgroundColor: '#fff', color: '#202124',
|
||||
borderWidth: 1, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 10, fontSize: 14,
|
||||
},
|
||||
// Select cards (Step 2)
|
||||
selectCard: {
|
||||
backgroundColor: '#f8f9fa', borderRadius: 12, padding: 16,
|
||||
flexDirection: 'row', alignItems: 'center',
|
||||
borderWidth: 2, borderColor: '#e8eaed',
|
||||
// Auto-backup (Step 2)
|
||||
checklistInfo: { fontSize: 13, marginBottom: 8 },
|
||||
checkRow: {
|
||||
flexDirection: 'row', alignItems: 'center', paddingVertical: 14,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
},
|
||||
selectCardActive: { borderColor: '#1a73e8', backgroundColor: '#e8f0fe' },
|
||||
radio: {
|
||||
width: 20, height: 20, borderRadius: 10, borderWidth: 2,
|
||||
borderColor: '#dadce0', marginRight: 12,
|
||||
checkbox: {
|
||||
width: 22, height: 22, borderRadius: 4, borderWidth: 2,
|
||||
justifyContent: 'center', alignItems: 'center', marginRight: 12,
|
||||
},
|
||||
radioActive: { borderColor: '#1a73e8', backgroundColor: '#1a73e8' },
|
||||
selectText: { fontSize: 15, color: '#202124', fontWeight: '500' },
|
||||
selectTextActive: { color: '#1a73e8', fontWeight: '600' },
|
||||
checkmark: { color: '#fff', fontSize: 14, fontWeight: '700' },
|
||||
checkIcon: { fontSize: 18, marginRight: 8 },
|
||||
checkLabel: { fontSize: 14, fontWeight: '500', flex: 1 },
|
||||
// Footer
|
||||
footer: {
|
||||
flexDirection: 'row', paddingHorizontal: 20, paddingVertical: 14,
|
||||
borderTopWidth: 1, borderTopColor: '#e8eaed', gap: 12,
|
||||
borderTopWidth: 1, gap: 12,
|
||||
},
|
||||
backButton: {
|
||||
flex: 1, paddingVertical: 12, borderRadius: 8, alignItems: 'center',
|
||||
backgroundColor: '#f8f9fa', borderWidth: 1, borderColor: '#dadce0',
|
||||
},
|
||||
backButtonText: { fontSize: 15, fontWeight: '600', color: '#5f6368' },
|
||||
nextButton: {
|
||||
flex: 1, paddingVertical: 12, borderRadius: 8, alignItems: 'center',
|
||||
backgroundColor: '#1a73e8',
|
||||
flex: 1, paddingVertical: 12, borderRadius: 8, alignItems: 'center', borderWidth: 1,
|
||||
},
|
||||
backButtonText: { fontSize: 15, fontWeight: '600' },
|
||||
nextButton: { flex: 1, paddingVertical: 12, borderRadius: 8, alignItems: 'center' },
|
||||
nextButtonText: { fontSize: 15, fontWeight: '600', color: '#fff' },
|
||||
buttonDisabled: { opacity: 0.6 },
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user