init
This commit is contained in:
186
src/app/add-feed.tsx
Normal file
186
src/app/add-feed.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
// Add Feed Screen
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
TextInput,
|
||||
Button,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { useFeedStore } from '@/stores/feed-store';
|
||||
import { parseFeed } from '@/services/feed-service';
|
||||
import { generateId } from '@/utils/helpers';
|
||||
import { t } from '@/i18n';
|
||||
|
||||
export default function AddFeedScreen() {
|
||||
const router = useRouter();
|
||||
const [url, setUrl] = useState('');
|
||||
const [title, setTitle] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [preview, setPreview] = useState<any>(null);
|
||||
const addSubscription = useFeedStore((state) => state.addSubscription);
|
||||
|
||||
const handlePreview = async () => {
|
||||
if (!url) {
|
||||
Alert.alert('Error', 'Please enter a feed URL');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setPreview(null);
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const text = await response.text();
|
||||
const result = await parseFeed(url, text);
|
||||
|
||||
if (result.success && result.feed) {
|
||||
setPreview(result.feed);
|
||||
} else {
|
||||
Alert.alert('Error', result.error || 'Failed to parse feed');
|
||||
}
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to fetch feed');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAdd = async () => {
|
||||
if (!url) {
|
||||
Alert.alert('Error', 'Please enter a feed URL');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preview) {
|
||||
Alert.alert('Error', 'Please preview the feed first');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const subscription = {
|
||||
id: generateId(),
|
||||
url,
|
||||
title: title || preview.title,
|
||||
enabled: true,
|
||||
fetchInterval: 60, // Default 1 hour
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
await addSubscription(subscription);
|
||||
router.back();
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to add subscription');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>{t('feed.add')}</Text>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>URL</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="https://example.com/feed.xml"
|
||||
value={url}
|
||||
onChangeText={setUrl}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="url"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Title (optional)</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="My Feed"
|
||||
value={title}
|
||||
onChangeText={setTitle}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Button
|
||||
title={loading && !preview ? 'Loading...' : 'Preview'}
|
||||
onPress={handlePreview}
|
||||
disabled={loading || !url}
|
||||
/>
|
||||
|
||||
{preview && (
|
||||
<View style={styles.previewContainer}>
|
||||
<Text style={styles.previewTitle}>{preview.title}</Text>
|
||||
<Text style={styles.previewDescription}>
|
||||
{preview.description || 'No description'}
|
||||
</Text>
|
||||
<Text style={styles.previewItems}>
|
||||
{preview.items.length} items
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<Button
|
||||
title={loading ? 'Adding...' : 'Add Feed'}
|
||||
onPress={handleAdd}
|
||||
disabled={loading || !preview}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 20,
|
||||
paddingTop: 60,
|
||||
},
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 30,
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
marginBottom: 8,
|
||||
},
|
||||
input: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#ccc',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
fontSize: 16,
|
||||
},
|
||||
previewContainer: {
|
||||
marginTop: 20,
|
||||
padding: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: '#ddd',
|
||||
borderRadius: 8,
|
||||
},
|
||||
previewTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 8,
|
||||
},
|
||||
previewDescription: {
|
||||
fontSize: 14,
|
||||
color: '#666',
|
||||
marginBottom: 8,
|
||||
},
|
||||
previewItems: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user