mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
ui fixes
This commit is contained in:
parent
5bb3aa7e3b
commit
ae66ec1c23
1 changed files with 415 additions and 94 deletions
|
|
@ -3,14 +3,16 @@ import {
|
|||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
Switch,
|
||||
ActivityIndicator,
|
||||
TextInput,
|
||||
ScrollView,
|
||||
RefreshControl,
|
||||
StatusBar,
|
||||
Platform,
|
||||
Image,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
|
|
@ -18,10 +20,309 @@ import { useNavigation } from '@react-navigation/native';
|
|||
import { useSettings } from '../hooks/useSettings';
|
||||
import { localScraperService, ScraperInfo } from '../services/localScraperService';
|
||||
import { logger } from '../utils/logger';
|
||||
import { useTheme } from '../contexts/ThemeContext';
|
||||
|
||||
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
||||
|
||||
// Create a styles creator function that accepts the theme colors
|
||||
const createStyles = (colors: any) => StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.background,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: Platform.OS === 'ios' ? 44 : ANDROID_STATUSBAR_HEIGHT + 16,
|
||||
paddingBottom: 16,
|
||||
},
|
||||
backButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
backText: {
|
||||
fontSize: 17,
|
||||
color: colors.primary,
|
||||
marginLeft: 8,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 34,
|
||||
fontWeight: 'bold',
|
||||
color: colors.white,
|
||||
paddingHorizontal: 16,
|
||||
marginBottom: 24,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
},
|
||||
section: {
|
||||
backgroundColor: colors.elevation1,
|
||||
marginBottom: 16,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
marginBottom: 8,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 0,
|
||||
},
|
||||
sectionDescription: {
|
||||
fontSize: 14,
|
||||
color: colors.mediumGray,
|
||||
marginBottom: 16,
|
||||
lineHeight: 20,
|
||||
},
|
||||
emptyContainer: {
|
||||
backgroundColor: colors.elevation2,
|
||||
borderRadius: 12,
|
||||
padding: 32,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 24,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4,
|
||||
elevation: 2,
|
||||
},
|
||||
emptyText: {
|
||||
marginTop: 8,
|
||||
color: colors.mediumGray,
|
||||
fontSize: 15,
|
||||
},
|
||||
scraperItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.elevation2,
|
||||
padding: 12,
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 8,
|
||||
borderRadius: 8,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 2,
|
||||
elevation: 1,
|
||||
},
|
||||
scraperLogo: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
marginRight: 12,
|
||||
borderRadius: 6,
|
||||
backgroundColor: colors.elevation3,
|
||||
},
|
||||
scraperInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
scraperName: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
marginBottom: 2,
|
||||
},
|
||||
scraperDescription: {
|
||||
fontSize: 13,
|
||||
color: colors.mediumGray,
|
||||
marginBottom: 4,
|
||||
lineHeight: 18,
|
||||
},
|
||||
scraperMeta: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
scraperVersion: {
|
||||
fontSize: 12,
|
||||
color: colors.mediumGray,
|
||||
},
|
||||
scraperDot: {
|
||||
fontSize: 12,
|
||||
color: colors.mediumGray,
|
||||
marginHorizontal: 8,
|
||||
},
|
||||
scraperTypes: {
|
||||
fontSize: 12,
|
||||
color: colors.mediumGray,
|
||||
},
|
||||
settingRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
},
|
||||
settingInfo: {
|
||||
flex: 1,
|
||||
marginRight: 16,
|
||||
},
|
||||
settingTitle: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
marginBottom: 2,
|
||||
},
|
||||
settingDescription: {
|
||||
fontSize: 14,
|
||||
color: colors.mediumEmphasis,
|
||||
lineHeight: 20,
|
||||
},
|
||||
textInput: {
|
||||
backgroundColor: colors.elevation1,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
color: colors.white,
|
||||
marginBottom: 16,
|
||||
fontSize: 15,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: colors.elevation2,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 8,
|
||||
marginRight: 8,
|
||||
},
|
||||
primaryButton: {
|
||||
backgroundColor: colors.primary,
|
||||
},
|
||||
secondaryButton: {
|
||||
backgroundColor: colors.elevation2,
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
textAlign: 'center',
|
||||
},
|
||||
secondaryButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: colors.mediumGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
clearButton: {
|
||||
backgroundColor: '#ff3b30',
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 12,
|
||||
borderRadius: 8,
|
||||
},
|
||||
clearButtonText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
},
|
||||
currentRepoContainer: {
|
||||
backgroundColor: colors.elevation1,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginBottom: 16,
|
||||
},
|
||||
currentRepoLabel: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: colors.primary,
|
||||
marginBottom: 4,
|
||||
},
|
||||
currentRepoUrl: {
|
||||
fontSize: 14,
|
||||
color: colors.white,
|
||||
fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace',
|
||||
lineHeight: 18,
|
||||
},
|
||||
urlHint: {
|
||||
fontSize: 12,
|
||||
color: colors.mediumGray,
|
||||
marginBottom: 8,
|
||||
lineHeight: 16,
|
||||
},
|
||||
defaultRepoButton: {
|
||||
backgroundColor: colors.elevation3,
|
||||
borderRadius: 6,
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 12,
|
||||
marginBottom: 16,
|
||||
alignItems: 'center',
|
||||
},
|
||||
defaultRepoButtonText: {
|
||||
color: colors.primary,
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: 'row',
|
||||
gap: 12,
|
||||
},
|
||||
infoText: {
|
||||
fontSize: 14,
|
||||
color: colors.mediumEmphasis,
|
||||
lineHeight: 20,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
emptyState: {
|
||||
alignItems: 'center',
|
||||
paddingVertical: 32,
|
||||
},
|
||||
emptyStateTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
marginTop: 16,
|
||||
marginBottom: 8,
|
||||
},
|
||||
emptyStateDescription: {
|
||||
fontSize: 14,
|
||||
color: colors.mediumGray,
|
||||
textAlign: 'center',
|
||||
lineHeight: 20,
|
||||
},
|
||||
scrapersList: {
|
||||
gap: 12,
|
||||
},
|
||||
scrapersContainer: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
lastSection: {
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
disabledSection: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
disabledText: {
|
||||
color: colors.elevation3,
|
||||
},
|
||||
disabledContainer: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
disabledInput: {
|
||||
backgroundColor: colors.elevation1,
|
||||
opacity: 0.5,
|
||||
},
|
||||
disabledButton: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
disabledImage: {
|
||||
opacity: 0.3,
|
||||
},
|
||||
});
|
||||
|
||||
const ScraperSettingsScreen: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const { settings, updateSetting } = useSettings();
|
||||
const { currentTheme } = useTheme();
|
||||
const colors = currentTheme.colors;
|
||||
const styles = createStyles(colors);
|
||||
const [repositoryUrl, setRepositoryUrl] = useState(settings.scraperRepositoryUrl);
|
||||
const [installedScrapers, setInstalledScrapers] = useState<ScraperInfo[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
|
@ -182,53 +483,33 @@ const ScraperSettingsScreen: React.FC = () => {
|
|||
await updateSetting('enableScraperUrlValidation', enabled);
|
||||
};
|
||||
|
||||
const renderScraperItem = (scraper: ScraperInfo) => (
|
||||
<View key={scraper.id} style={styles.scraperItem}>
|
||||
{scraper.logo && (
|
||||
<Image
|
||||
source={{ uri: scraper.logo }}
|
||||
style={styles.scraperLogo}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
)}
|
||||
<View style={styles.scraperInfo}>
|
||||
<Text style={styles.scraperName}>{scraper.name}</Text>
|
||||
<Text style={styles.scraperDescription}>{scraper.description}</Text>
|
||||
<View style={styles.scraperMeta}>
|
||||
<Text style={styles.scraperVersion}>v{scraper.version}</Text>
|
||||
<Text style={styles.scraperTypes}>
|
||||
{scraper.supportedTypes.join(', ')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Switch
|
||||
value={scraper.enabled}
|
||||
onValueChange={(enabled) => handleToggleScraper(scraper.id, enabled)}
|
||||
trackColor={{ false: '#767577', true: '#007AFF' }}
|
||||
thumbColor={scraper.enabled ? '#ffffff' : '#f4f3f4'}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.container}>
|
||||
<StatusBar
|
||||
barStyle={Platform.OS === 'ios' ? 'light-content' : 'light-content'}
|
||||
backgroundColor={colors.background}
|
||||
/>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity
|
||||
style={styles.backButton}
|
||||
onPress={() => navigation.goBack()}
|
||||
>
|
||||
<Ionicons name="arrow-back" size={24} color="#007AFF" />
|
||||
<Ionicons name="arrow-back" size={24} color={colors.primary} />
|
||||
<Text style={styles.backText}>Settings</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>Local Scrapers</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.headerTitle}>Local Scrapers</Text>
|
||||
|
||||
<ScrollView
|
||||
style={styles.content}
|
||||
style={styles.scrollView}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={isRefreshing} onRefresh={loadScrapers} />
|
||||
}
|
||||
>
|
||||
{/* Enable/Disable Local Scrapers */}
|
||||
{/* Enable Local Scrapers - Top Priority */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.settingRow}>
|
||||
<View style={styles.settingInfo}>
|
||||
|
|
@ -240,33 +521,17 @@ const ScraperSettingsScreen: React.FC = () => {
|
|||
<Switch
|
||||
value={settings.enableLocalScrapers}
|
||||
onValueChange={handleToggleLocalScrapers}
|
||||
trackColor={{ false: '#767577', true: '#007AFF' }}
|
||||
thumbColor={settings.enableLocalScrapers ? '#ffffff' : '#f4f3f4'}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* URL Validation Toggle */}
|
||||
<View style={styles.settingRow}>
|
||||
<View style={styles.settingInfo}>
|
||||
<Text style={styles.settingTitle}>Enable URL Validation</Text>
|
||||
<Text style={styles.settingDescription}>
|
||||
Validate streaming URLs before returning them (may slow down results but improves reliability)
|
||||
</Text>
|
||||
</View>
|
||||
<Switch
|
||||
value={settings.enableScraperUrlValidation}
|
||||
onValueChange={handleToggleUrlValidation}
|
||||
trackColor={{ false: '#767577', true: '#007AFF' }}
|
||||
thumbColor={settings.enableScraperUrlValidation ? '#ffffff' : '#f4f3f4'}
|
||||
trackColor={{ false: colors.elevation3, true: colors.primary }}
|
||||
thumbColor={settings.enableLocalScrapers ? colors.white : '#f4f3f4'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Repository Configuration */}
|
||||
<View style={styles.section}>
|
||||
{/* Repository Configuration - Moved up for better UX */}
|
||||
<View style={[styles.section, !settings.enableLocalScrapers && styles.disabledSection]}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>Repository Configuration</Text>
|
||||
{hasRepository && (
|
||||
<Text style={[styles.sectionTitle, !settings.enableLocalScrapers && styles.disabledText]}>Repository Configuration</Text>
|
||||
{hasRepository && settings.enableLocalScrapers && (
|
||||
<TouchableOpacity
|
||||
style={styles.clearButton}
|
||||
onPress={handleClearCache}
|
||||
|
|
@ -275,63 +540,65 @@ const ScraperSettingsScreen: React.FC = () => {
|
|||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
<Text style={styles.sectionDescription}>
|
||||
<Text style={[styles.sectionDescription, !settings.enableLocalScrapers && styles.disabledText]}>
|
||||
Enter the URL of a Nuvio scraper repository to download and install scrapers.
|
||||
</Text>
|
||||
|
||||
{hasRepository && repositoryUrl && (
|
||||
<View style={styles.currentRepoContainer}>
|
||||
<Text style={styles.currentRepoLabel}>Current Repository:</Text>
|
||||
<Text style={styles.currentRepoUrl}>{repositoryUrl}</Text>
|
||||
<View style={[styles.currentRepoContainer, !settings.enableLocalScrapers && styles.disabledContainer]}>
|
||||
<Text style={[styles.currentRepoLabel, !settings.enableLocalScrapers && styles.disabledText]}>Current Repository:</Text>
|
||||
<Text style={[styles.currentRepoUrl, !settings.enableLocalScrapers && styles.disabledText]}>{repositoryUrl}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
style={[styles.textInput, !settings.enableLocalScrapers && styles.disabledInput]}
|
||||
value={repositoryUrl}
|
||||
onChangeText={setRepositoryUrl}
|
||||
placeholder="https://raw.githubusercontent.com/tapframe/nuvio-providers/main"
|
||||
placeholderTextColor="#999"
|
||||
placeholderTextColor={!settings.enableLocalScrapers ? colors.elevation3 : "#999"}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="url"
|
||||
editable={settings.enableLocalScrapers}
|
||||
/>
|
||||
<Text style={styles.urlHint}>
|
||||
<Text style={[styles.urlHint, !settings.enableLocalScrapers && styles.disabledText]}>
|
||||
💡 Use GitHub raw URL format. Default: https://raw.githubusercontent.com/tapframe/nuvio-providers/main
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.defaultRepoButton}
|
||||
style={[styles.defaultRepoButton, !settings.enableLocalScrapers && styles.disabledButton]}
|
||||
onPress={handleUseDefaultRepo}
|
||||
disabled={!settings.enableLocalScrapers}
|
||||
>
|
||||
<Text style={styles.defaultRepoButtonText}>Use Default Repository</Text>
|
||||
<Text style={[styles.defaultRepoButtonText, !settings.enableLocalScrapers && styles.disabledText]}>Use Default Repository</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, styles.primaryButton]}
|
||||
style={[styles.button, styles.primaryButton, !settings.enableLocalScrapers && styles.disabledButton]}
|
||||
onPress={handleSaveRepository}
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || !settings.enableLocalScrapers}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size="small" color="#ffffff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>Save Repository</Text>
|
||||
<Text style={[styles.buttonText, !settings.enableLocalScrapers && styles.disabledText]}>Save Repository</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
{hasRepository && (
|
||||
<TouchableOpacity
|
||||
style={[styles.button, styles.secondaryButton]}
|
||||
style={[styles.button, styles.secondaryButton, !settings.enableLocalScrapers && styles.disabledButton]}
|
||||
onPress={handleRefreshRepository}
|
||||
disabled={isRefreshing}
|
||||
disabled={isRefreshing || !settings.enableLocalScrapers}
|
||||
>
|
||||
{isRefreshing ? (
|
||||
<ActivityIndicator size="small" color="#007AFF" />
|
||||
<ActivityIndicator size="small" color={colors.primary} />
|
||||
) : (
|
||||
<Text style={styles.secondaryButtonText}>Refresh</Text>
|
||||
<Text style={[styles.secondaryButtonText, !settings.enableLocalScrapers && styles.disabledText]}>Refresh</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
|
@ -339,10 +606,10 @@ const ScraperSettingsScreen: React.FC = () => {
|
|||
</View>
|
||||
|
||||
{/* Installed Scrapers */}
|
||||
<View style={styles.section}>
|
||||
<View style={[!settings.enableLocalScrapers && styles.disabledSection]}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>Installed Scrapers</Text>
|
||||
{installedScrapers.length > 0 && (
|
||||
<Text style={[styles.sectionTitle, !settings.enableLocalScrapers && styles.disabledText]}>Installed Scrapers</Text>
|
||||
{installedScrapers.length > 0 && settings.enableLocalScrapers && (
|
||||
<TouchableOpacity
|
||||
style={styles.clearButton}
|
||||
onPress={handleClearScrapers}
|
||||
|
|
@ -353,33 +620,81 @@ const ScraperSettingsScreen: React.FC = () => {
|
|||
</View>
|
||||
|
||||
{installedScrapers.length === 0 ? (
|
||||
<View style={styles.emptyState}>
|
||||
<Ionicons name="download-outline" size={48} color="#999" />
|
||||
<Text style={styles.emptyStateTitle}>No Scrapers Installed</Text>
|
||||
<Text style={styles.emptyStateDescription}>
|
||||
Add a repository URL above and refresh to install scrapers.
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.scrapersList}>
|
||||
{installedScrapers.map(renderScraperItem)}
|
||||
</View>
|
||||
)}
|
||||
<View style={[styles.emptyContainer, !settings.enableLocalScrapers && styles.disabledContainer]}>
|
||||
<Ionicons name="download-outline" size={48} color={!settings.enableLocalScrapers ? colors.elevation3 : colors.mediumGray} />
|
||||
<Text style={[styles.emptyStateTitle, !settings.enableLocalScrapers && styles.disabledText]}>No Scrapers Installed</Text>
|
||||
<Text style={[styles.emptyStateDescription, !settings.enableLocalScrapers && styles.disabledText]}>
|
||||
Configure a repository above to install scrapers.
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.scrapersContainer}>
|
||||
{installedScrapers.map((scraper) => (
|
||||
<View key={scraper.id} style={[styles.scraperItem, !settings.enableLocalScrapers && styles.disabledContainer]}>
|
||||
{scraper.logo ? (
|
||||
<Image
|
||||
source={{ uri: scraper.logo }}
|
||||
style={[styles.scraperLogo, !settings.enableLocalScrapers && styles.disabledImage]}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
) : (
|
||||
<View style={[styles.scraperLogo, !settings.enableLocalScrapers && styles.disabledContainer]} />
|
||||
)}
|
||||
<View style={styles.scraperInfo}>
|
||||
<Text style={[styles.scraperName, !settings.enableLocalScrapers && styles.disabledText]}>{scraper.name}</Text>
|
||||
<Text style={[styles.scraperDescription, !settings.enableLocalScrapers && styles.disabledText]}>{scraper.description}</Text>
|
||||
<View style={styles.scraperMeta}>
|
||||
<Text style={[styles.scraperVersion, !settings.enableLocalScrapers && styles.disabledText]}>v{scraper.version}</Text>
|
||||
<Text style={[styles.scraperDot, !settings.enableLocalScrapers && styles.disabledText]}>•</Text>
|
||||
<Text style={[styles.scraperTypes, !settings.enableLocalScrapers && styles.disabledText]}>
|
||||
{scraper.supportedTypes.join(', ')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Switch
|
||||
value={scraper.enabled && settings.enableLocalScrapers}
|
||||
onValueChange={(enabled) => handleToggleScraper(scraper.id, enabled)}
|
||||
trackColor={{ false: colors.elevation3, true: colors.primary }}
|
||||
thumbColor={scraper.enabled && settings.enableLocalScrapers ? colors.white : '#f4f3f4'}
|
||||
disabled={!settings.enableLocalScrapers}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Information */}
|
||||
<View style={styles.section}>
|
||||
{/* Additional Scraper Settings */}
|
||||
<View style={[styles.section, !settings.enableLocalScrapers && styles.disabledSection]}>
|
||||
<Text style={[styles.sectionTitle, !settings.enableLocalScrapers && styles.disabledText]}>Additional Settings</Text>
|
||||
<View style={styles.settingRow}>
|
||||
<View style={styles.settingInfo}>
|
||||
<Text style={[styles.settingTitle, !settings.enableLocalScrapers && styles.disabledText]}>Enable URL Validation</Text>
|
||||
<Text style={[styles.settingDescription, !settings.enableLocalScrapers && styles.disabledText]}>
|
||||
Validate streaming URLs before returning them (may slow down results but improves reliability)
|
||||
</Text>
|
||||
</View>
|
||||
<Switch
|
||||
value={settings.enableScraperUrlValidation && settings.enableLocalScrapers}
|
||||
onValueChange={handleToggleUrlValidation}
|
||||
trackColor={{ false: colors.elevation3, true: colors.primary }}
|
||||
thumbColor={settings.enableScraperUrlValidation && settings.enableLocalScrapers ? colors.white : '#f4f3f4'}
|
||||
disabled={!settings.enableLocalScrapers}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
{/* About */}
|
||||
<View style={[styles.section, styles.lastSection]}>
|
||||
<Text style={styles.sectionTitle}>About Local Scrapers</Text>
|
||||
<Text style={styles.infoText}>
|
||||
Local scrapers are JavaScript modules that can search for streaming links from various sources.
|
||||
They run locally on your device and can be installed from trusted repositories.
|
||||
</Text>
|
||||
<Text style={styles.infoText}>
|
||||
⚠️ Only install scrapers from trusted sources. Malicious scrapers could potentially access your data.
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -412,11 +727,16 @@ const styles = StyleSheet.create({
|
|||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#333',
|
||||
},
|
||||
lastSection: {
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
marginHorizontal: -16,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 18,
|
||||
|
|
@ -498,6 +818,7 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 12,
|
||||
borderRadius: 6,
|
||||
backgroundColor: '#ff3b30',
|
||||
marginLeft: 0,
|
||||
},
|
||||
clearButtonText: {
|
||||
color: '#ffffff',
|
||||
|
|
|
|||
Loading…
Reference in a new issue