mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
Refactor CatalogSection and HomeScreen for improved rendering performance and update MDBListSettingsScreen to default to disabled state
This update modifies the initial rendering parameters in CatalogSection and HomeScreen components to optimize performance by reducing the number of items rendered initially and adjusting batch sizes. Additionally, the MDBListSettingsScreen now defaults to a disabled state for the MDBList feature, enhancing user clarity regarding its status. Other minor adjustments include improved layout handling and visual consistency across settings components.
This commit is contained in:
parent
12c7d8f860
commit
929ed9cc9e
4 changed files with 274 additions and 397 deletions
|
|
@ -109,15 +109,20 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
|
|||
decelerationRate="fast"
|
||||
snapToAlignment="start"
|
||||
ItemSeparatorComponent={() => <View style={{ width: 8 }} />}
|
||||
initialNumToRender={4}
|
||||
maxToRenderPerBatch={4}
|
||||
windowSize={5}
|
||||
initialNumToRender={3}
|
||||
maxToRenderPerBatch={2}
|
||||
windowSize={3}
|
||||
removeClippedSubviews={Platform.OS === 'android'}
|
||||
updateCellsBatchingPeriod={50}
|
||||
getItemLayout={(data, index) => ({
|
||||
length: POSTER_WIDTH + 8,
|
||||
offset: (POSTER_WIDTH + 8) * index,
|
||||
index,
|
||||
})}
|
||||
maintainVisibleContentPosition={{
|
||||
minIndexForVisible: 0
|
||||
}}
|
||||
onEndReachedThreshold={1}
|
||||
/>
|
||||
</Animated.View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -602,9 +602,21 @@ const HomeScreen = () => {
|
|||
]}
|
||||
showsVerticalScrollIndicator={false}
|
||||
ListFooterComponent={ListFooterComponent}
|
||||
initialNumToRender={5}
|
||||
maxToRenderPerBatch={5}
|
||||
windowSize={10}
|
||||
initialNumToRender={3}
|
||||
maxToRenderPerBatch={2}
|
||||
windowSize={5}
|
||||
removeClippedSubviews={Platform.OS === 'android'}
|
||||
updateCellsBatchingPeriod={50}
|
||||
onEndReachedThreshold={0.5}
|
||||
maintainVisibleContentPosition={{
|
||||
minIndexForVisible: 0,
|
||||
autoscrollToTopThreshold: 10
|
||||
}}
|
||||
getItemLayout={(data, index) => ({
|
||||
length: index === 0 ? 400 : 280, // Approximate heights for different item types
|
||||
offset: index === 0 ? 0 : 400 + (index - 1) * 280,
|
||||
index,
|
||||
})}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
|||
export const isMDBListEnabled = async (): Promise<boolean> => {
|
||||
try {
|
||||
const enabledSetting = await AsyncStorage.getItem(MDBLIST_ENABLED_STORAGE_KEY);
|
||||
return enabledSetting === null || enabledSetting === 'true';
|
||||
return enabledSetting === 'true';
|
||||
} catch (error) {
|
||||
logger.error('[MDBList] Error checking if MDBList is enabled:', error);
|
||||
return true; // Default to enabled if there's an error
|
||||
return false; // Default to disabled if there's an error
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -364,7 +364,7 @@ const MDBListSettingsScreen = () => {
|
|||
const [apiKey, setApiKey] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isKeySet, setIsKeySet] = useState(false);
|
||||
const [isMdbListEnabled, setIsMdbListEnabled] = useState(true);
|
||||
const [isMdbListEnabled, setIsMdbListEnabled] = useState(false);
|
||||
const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
const [isInputFocused, setIsInputFocused] = useState(false);
|
||||
const [enabledProviders, setEnabledProviders] = useState<Record<string, boolean>>({});
|
||||
|
|
@ -388,14 +388,14 @@ const MDBListSettingsScreen = () => {
|
|||
setIsMdbListEnabled(savedSetting === 'true');
|
||||
logger.log('[MDBListSettingsScreen] MDBList enabled setting:', savedSetting === 'true');
|
||||
} else {
|
||||
// Default to enabled if no setting found
|
||||
setIsMdbListEnabled(true);
|
||||
await AsyncStorage.setItem(MDBLIST_ENABLED_STORAGE_KEY, 'true');
|
||||
logger.log('[MDBListSettingsScreen] MDBList enabled setting not found, defaulting to true');
|
||||
// Default to disabled if no setting found
|
||||
setIsMdbListEnabled(false);
|
||||
await AsyncStorage.setItem(MDBLIST_ENABLED_STORAGE_KEY, 'false');
|
||||
logger.log('[MDBListSettingsScreen] MDBList enabled setting not found, defaulting to false');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[MDBListSettingsScreen] Failed to load MDBList enabled setting:', error);
|
||||
setIsMdbListEnabled(true);
|
||||
setIsMdbListEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,37 +29,42 @@ import { useTheme } from '../contexts/ThemeContext';
|
|||
import { catalogService, DataSource } from '../services/catalogService';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
import Animated, { FadeInDown } from 'react-native-reanimated';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
||||
|
||||
// Card component with modern style
|
||||
// Card component with minimalistic style
|
||||
interface SettingsCardProps {
|
||||
children: React.ReactNode;
|
||||
title?: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
const SettingsCard: React.FC<SettingsCardProps> = ({ children, title }) => {
|
||||
const SettingsCard: React.FC<SettingsCardProps> = ({ children, title, delay = 0 }) => {
|
||||
const { currentTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={[styles.cardContainer]}>
|
||||
<Animated.View
|
||||
entering={FadeInDown.delay(delay).duration(400)}
|
||||
style={[styles.cardContainer]}
|
||||
>
|
||||
{title && (
|
||||
<Text style={[
|
||||
styles.cardTitle,
|
||||
{ color: currentTheme.colors.mediumEmphasis }
|
||||
]}>
|
||||
{title.toUpperCase()}
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
<View style={[
|
||||
styles.card,
|
||||
{ backgroundColor: currentTheme.colors.elevation2 }
|
||||
{ backgroundColor: currentTheme.colors.elevation1 }
|
||||
]}>
|
||||
{children}
|
||||
</View>
|
||||
</View>
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -67,7 +72,7 @@ interface SettingItemProps {
|
|||
title: string;
|
||||
description?: string;
|
||||
icon: string;
|
||||
renderControl: () => React.ReactNode;
|
||||
renderControl?: () => React.ReactNode;
|
||||
isLast?: boolean;
|
||||
onPress?: () => void;
|
||||
badge?: string | number;
|
||||
|
|
@ -86,40 +91,42 @@ const SettingItem: React.FC<SettingItemProps> = ({
|
|||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
activeOpacity={0.6}
|
||||
onPress={onPress}
|
||||
style={[
|
||||
styles.settingItem,
|
||||
!isLast && styles.settingItemBorder,
|
||||
{ borderBottomColor: 'rgba(255,255,255,0.08)' }
|
||||
{ borderBottomColor: currentTheme.colors.elevation2 }
|
||||
]}
|
||||
>
|
||||
<View style={[
|
||||
styles.settingIconContainer,
|
||||
{ backgroundColor: 'rgba(255,255,255,0.1)' }
|
||||
{ backgroundColor: currentTheme.colors.elevation2 }
|
||||
]}>
|
||||
<MaterialIcons name={icon} size={Math.min(20, width * 0.05)} color={currentTheme.colors.primary} />
|
||||
<MaterialIcons name={icon} size={20} color={currentTheme.colors.primary} />
|
||||
</View>
|
||||
<View style={styles.settingContent}>
|
||||
<View style={styles.settingTextContainer}>
|
||||
<Text style={[styles.settingTitle, { color: currentTheme.colors.highEmphasis }]} numberOfLines={1} adjustsFontSizeToFit>
|
||||
<Text style={[styles.settingTitle, { color: currentTheme.colors.highEmphasis }]}>
|
||||
{title}
|
||||
</Text>
|
||||
{description && (
|
||||
<Text style={[styles.settingDescription, { color: currentTheme.colors.mediumEmphasis }]} numberOfLines={2} adjustsFontSizeToFit>
|
||||
<Text style={[styles.settingDescription, { color: currentTheme.colors.mediumEmphasis }]} numberOfLines={1}>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
{badge && (
|
||||
<View style={[styles.badge, { backgroundColor: currentTheme.colors.primary }]}>
|
||||
<Text style={styles.badgeText} numberOfLines={1} adjustsFontSizeToFit>{String(badge)}</Text>
|
||||
<View style={[styles.badge, { backgroundColor: `${currentTheme.colors.primary}20` }]}>
|
||||
<Text style={[styles.badgeText, { color: currentTheme.colors.primary }]}>{String(badge)}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.settingControl}>
|
||||
{renderControl()}
|
||||
</View>
|
||||
{renderControl && (
|
||||
<View style={styles.settingControl}>
|
||||
{renderControl()}
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
|
@ -256,17 +263,17 @@ const SettingsScreen: React.FC = () => {
|
|||
<Switch
|
||||
value={value}
|
||||
onValueChange={onValueChange}
|
||||
trackColor={{ false: 'rgba(255,255,255,0.1)', true: currentTheme.colors.primary }}
|
||||
thumbColor={Platform.OS === 'android' ? (value ? currentTheme.colors.white : currentTheme.colors.white) : ''}
|
||||
ios_backgroundColor={'rgba(255,255,255,0.1)'}
|
||||
trackColor={{ false: currentTheme.colors.elevation2, true: currentTheme.colors.primary }}
|
||||
thumbColor={value ? currentTheme.colors.white : currentTheme.colors.mediumEmphasis}
|
||||
ios_backgroundColor={currentTheme.colors.elevation2}
|
||||
/>
|
||||
);
|
||||
|
||||
const ChevronRight = () => (
|
||||
<MaterialIcons
|
||||
name="chevron-right"
|
||||
size={22}
|
||||
color={'rgba(255,255,255,0.3)'}
|
||||
size={20}
|
||||
color={currentTheme.colors.mediumEmphasis}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
@ -300,93 +307,89 @@ const SettingsScreen: React.FC = () => {
|
|||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
>
|
||||
<SettingsCard title="User & Account">
|
||||
{/* Account Section */}
|
||||
<SettingsCard title="ACCOUNT" delay={0}>
|
||||
<SettingItem
|
||||
title="Trakt"
|
||||
description={isAuthenticated ? `Connected as ${userProfile?.username || 'User'}` : "Not Connected"}
|
||||
description={isAuthenticated ? `@${userProfile?.username || 'User'}` : "Sign in to sync"}
|
||||
icon="person"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('TraktSettings')}
|
||||
isLast={false}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Profiles">
|
||||
{isAuthenticated ? (
|
||||
{isAuthenticated && (
|
||||
<SettingItem
|
||||
title="Manage Profiles"
|
||||
description="Create and switch between profiles"
|
||||
title="Profiles"
|
||||
description="Manage multiple users"
|
||||
icon="people"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('ProfilesSettings')}
|
||||
isLast={true}
|
||||
/>
|
||||
) : (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.profileLockContainer,
|
||||
{
|
||||
backgroundColor: `${currentTheme.colors.primary}10`,
|
||||
borderWidth: 1,
|
||||
borderColor: `${currentTheme.colors.primary}30`
|
||||
}
|
||||
]}
|
||||
activeOpacity={1}
|
||||
>
|
||||
<View style={styles.profileLockContent}>
|
||||
<MaterialIcons name="lock-outline" size={24} color={currentTheme.colors.primary} />
|
||||
<View style={styles.profileLockTextContainer}>
|
||||
<Text style={[styles.profileLockTitle, { color: currentTheme.colors.text }]}>
|
||||
Sign in to use Profiles
|
||||
</Text>
|
||||
<Text style={[styles.profileLockDescription, { color: currentTheme.colors.textMuted }]}>
|
||||
Create multiple profiles for different users and preferences
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.profileBenefits}>
|
||||
<View style={styles.benefitCol}>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialIcons name="check-circle" size={16} color={currentTheme.colors.primary} />
|
||||
<Text style={[styles.benefitText, { color: currentTheme.colors.textMuted }]}>
|
||||
Separate watchlists
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialIcons name="check-circle" size={16} color={currentTheme.colors.primary} />
|
||||
<Text style={[styles.benefitText, { color: currentTheme.colors.textMuted }]}>
|
||||
Content preferences
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.benefitCol}>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialIcons name="check-circle" size={16} color={currentTheme.colors.primary} />
|
||||
<Text style={[styles.benefitText, { color: currentTheme.colors.textMuted }]}>
|
||||
Personalized recommendations
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<MaterialIcons name="check-circle" size={16} color={currentTheme.colors.primary} />
|
||||
<Text style={[styles.benefitText, { color: currentTheme.colors.textMuted }]}>
|
||||
Individual viewing history
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={[styles.loginButton, { backgroundColor: currentTheme.colors.primary }]}
|
||||
activeOpacity={0.7}
|
||||
onPress={() => navigation.navigate('TraktSettings')}
|
||||
>
|
||||
<Text style={styles.loginButtonText}>Connect with Trakt</Text>
|
||||
<MaterialIcons name="arrow-forward" size={18} color="#FFFFFF" style={styles.loginButtonIcon} />
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Appearance">
|
||||
{/* Content & Discovery */}
|
||||
<SettingsCard title="CONTENT & DISCOVERY" delay={100}>
|
||||
<SettingItem
|
||||
title="Addons"
|
||||
description={`${addonCount} installed`}
|
||||
icon="extension"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('Addons')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Catalogs"
|
||||
description={`${catalogCount} active`}
|
||||
icon="view-list"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('CatalogSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Home Screen"
|
||||
description="Layout and content"
|
||||
icon="home"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('HomeScreenSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Discover Source"
|
||||
icon="explore"
|
||||
renderControl={() => (
|
||||
<View style={styles.segmentedControl}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.segment,
|
||||
discoverDataSource === DataSource.STREMIO_ADDONS && styles.segmentActive
|
||||
]}
|
||||
onPress={() => handleDiscoverDataSourceChange(DataSource.STREMIO_ADDONS)}
|
||||
>
|
||||
<Text style={[
|
||||
styles.segmentText,
|
||||
discoverDataSource === DataSource.STREMIO_ADDONS && styles.segmentTextActive,
|
||||
{ color: currentTheme.colors.mediumEmphasis }
|
||||
]}>Addons</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.segment,
|
||||
discoverDataSource === DataSource.TMDB && styles.segmentActive
|
||||
]}
|
||||
onPress={() => handleDiscoverDataSourceChange(DataSource.TMDB)}
|
||||
>
|
||||
<Text style={[
|
||||
styles.segmentText,
|
||||
discoverDataSource === DataSource.TMDB && styles.segmentTextActive,
|
||||
{ color: currentTheme.colors.mediumEmphasis }
|
||||
]}>TMDB</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
{/* Appearance & Interface */}
|
||||
<SettingsCard title="APPEARANCE" delay={200}>
|
||||
<SettingItem
|
||||
title="Theme"
|
||||
description={currentTheme.name}
|
||||
|
|
@ -396,245 +399,161 @@ const SettingsScreen: React.FC = () => {
|
|||
/>
|
||||
<SettingItem
|
||||
title="Episode Layout"
|
||||
description={settings?.episodeLayoutStyle === 'horizontal' ? 'Horizontal Cards' : 'Vertical List'}
|
||||
description={settings?.episodeLayoutStyle === 'horizontal' ? 'Horizontal' : 'Vertical'}
|
||||
icon="view-module"
|
||||
renderControl={() => (
|
||||
<View style={styles.selectorContainer}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.selectorButton,
|
||||
settings?.episodeLayoutStyle === 'vertical' && {
|
||||
backgroundColor: currentTheme.colors.primary
|
||||
}
|
||||
]}
|
||||
onPress={() => updateSetting('episodeLayoutStyle', 'vertical')}
|
||||
>
|
||||
<Text style={[
|
||||
styles.selectorText,
|
||||
{ color: currentTheme.colors.mediumEmphasis },
|
||||
settings?.episodeLayoutStyle === 'vertical' && {
|
||||
color: currentTheme.colors.white,
|
||||
fontWeight: '600'
|
||||
}
|
||||
]}>Vertical</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.selectorButton,
|
||||
settings?.episodeLayoutStyle === 'horizontal' && {
|
||||
backgroundColor: currentTheme.colors.primary
|
||||
}
|
||||
]}
|
||||
onPress={() => updateSetting('episodeLayoutStyle', 'horizontal')}
|
||||
>
|
||||
<Text style={[
|
||||
styles.selectorText,
|
||||
{ color: currentTheme.colors.mediumEmphasis },
|
||||
settings?.episodeLayoutStyle === 'horizontal' && {
|
||||
color: currentTheme.colors.white,
|
||||
fontWeight: '600'
|
||||
}
|
||||
]}>Horizontal</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<CustomSwitch
|
||||
value={settings?.episodeLayoutStyle === 'horizontal'}
|
||||
onValueChange={(value) => updateSetting('episodeLayoutStyle', value ? 'horizontal' : 'vertical')}
|
||||
/>
|
||||
)}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Features">
|
||||
{/* Integrations */}
|
||||
<SettingsCard title="INTEGRATIONS" delay={300}>
|
||||
<SettingItem
|
||||
title="MDBList"
|
||||
description={mdblistKeySet ? "Connected" : "Enable to add ratings & reviews"}
|
||||
icon="star"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('MDBListSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="TMDB"
|
||||
description="Metadata provider"
|
||||
icon="movie"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('TMDBSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Media Sources"
|
||||
description="Logo & image preferences"
|
||||
icon="image"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('LogoSourceSettings')}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
{/* Playback & Experience */}
|
||||
<SettingsCard title="PLAYBACK" delay={400}>
|
||||
<SettingItem
|
||||
title="Video Player"
|
||||
description={Platform.OS === 'ios'
|
||||
? (settings?.preferredPlayer === 'internal' ? 'Built-in' : settings?.preferredPlayer?.toUpperCase() || 'Built-in')
|
||||
: (settings?.useExternalPlayer ? 'External' : 'Built-in')
|
||||
}
|
||||
icon="play-circle-outline"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('PlayerSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Calendar"
|
||||
description="Manage your show calendar settings"
|
||||
icon="calendar-today"
|
||||
description="Episode tracking"
|
||||
icon="event"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('Calendar')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Notifications"
|
||||
description="Configure episode notifications and reminders"
|
||||
icon="notifications"
|
||||
description="Episode reminders"
|
||||
icon="notifications-none"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('NotificationSettings')}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Content">
|
||||
{/* About & Support */}
|
||||
<SettingsCard title="ABOUT" delay={500}>
|
||||
<SettingItem
|
||||
title="Addons"
|
||||
description="Manage your installed addons"
|
||||
icon="extension"
|
||||
title="Privacy Policy"
|
||||
icon="lock"
|
||||
onPress={() => Linking.openURL('https://github.com/Stremio/stremio-expo/blob/main/PRIVACY_POLICY.md')}
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('Addons')}
|
||||
badge={addonCount}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Catalogs"
|
||||
description="Configure content sources"
|
||||
icon="view-list"
|
||||
title="Report Issue"
|
||||
icon="bug-report"
|
||||
onPress={() => Sentry.showFeedbackWidget()}
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('CatalogSettings')}
|
||||
badge={catalogCount}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Trakt"
|
||||
icon="sync"
|
||||
onPress={() => navigation.navigate('TraktSettings')}
|
||||
renderControl={() => <ChevronRight />}
|
||||
badge={isAuthenticated ? `Logged in as ${userProfile?.username}`: "Not Logged In"}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Home Screen"
|
||||
description="Customize layout and content"
|
||||
icon="home"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('HomeScreenSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="MDBList Integration"
|
||||
description={mdblistKeySet ? "Ratings and reviews provided by MDBList" : "Connect MDBList for ratings and reviews"}
|
||||
title="Version"
|
||||
description="1.0.0"
|
||||
icon="info-outline"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('MDBListSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Image Sources"
|
||||
description="Choose primary source for title logos and backgrounds"
|
||||
icon="image"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('LogoSourceSettings')}
|
||||
/>
|
||||
<SettingItem
|
||||
title="TMDB"
|
||||
description="API & Metadata Settings"
|
||||
icon="movie-filter"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('TMDBSettings')}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Playback">
|
||||
<SettingItem
|
||||
title="Video Player"
|
||||
description={Platform.OS === 'ios'
|
||||
? (settings?.preferredPlayer === 'internal'
|
||||
? 'Built-in Player'
|
||||
: settings?.preferredPlayer
|
||||
? settings.preferredPlayer.toUpperCase()
|
||||
: 'Built-in Player')
|
||||
: (settings?.useExternalPlayer ? 'External Player' : 'Built-in Player')
|
||||
}
|
||||
icon="play-arrow"
|
||||
renderControl={ChevronRight}
|
||||
onPress={() => navigation.navigate('PlayerSettings')}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Discover">
|
||||
<SettingItem
|
||||
title="Content Source"
|
||||
description="Choose where to get content for the Discover screen"
|
||||
icon="explore"
|
||||
renderControl={() => (
|
||||
<View style={styles.selectorContainer}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.selectorButton,
|
||||
discoverDataSource === DataSource.STREMIO_ADDONS && {
|
||||
backgroundColor: currentTheme.colors.primary
|
||||
}
|
||||
]}
|
||||
onPress={() => handleDiscoverDataSourceChange(DataSource.STREMIO_ADDONS)}
|
||||
>
|
||||
<Text style={[
|
||||
styles.selectorText,
|
||||
{ color: currentTheme.colors.mediumEmphasis },
|
||||
discoverDataSource === DataSource.STREMIO_ADDONS && {
|
||||
color: currentTheme.colors.white,
|
||||
fontWeight: '600'
|
||||
}
|
||||
]}>Addons</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.selectorButton,
|
||||
discoverDataSource === DataSource.TMDB && {
|
||||
backgroundColor: currentTheme.colors.primary
|
||||
}
|
||||
]}
|
||||
onPress={() => handleDiscoverDataSourceChange(DataSource.TMDB)}
|
||||
>
|
||||
<Text style={[
|
||||
styles.selectorText,
|
||||
{ color: currentTheme.colors.mediumEmphasis },
|
||||
discoverDataSource === DataSource.TMDB && {
|
||||
color: currentTheme.colors.white,
|
||||
fontWeight: '600'
|
||||
}
|
||||
]}>TMDB</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<SettingsCard title="Debugging">
|
||||
<View style={{padding: 10}}>
|
||||
<Button
|
||||
title="Report a Bug or Suggestion"
|
||||
onPress={() => Sentry.showFeedbackWidget()}
|
||||
{/* Developer Options - Only show in development */}
|
||||
{__DEV__ && (
|
||||
<SettingsCard title="DEVELOPER" delay={600}>
|
||||
<SettingItem
|
||||
title="Test Onboarding"
|
||||
icon="play-circle-outline"
|
||||
onPress={() => navigation.navigate('Onboarding')}
|
||||
renderControl={ChevronRight}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Reset Onboarding"
|
||||
icon="refresh"
|
||||
onPress={async () => {
|
||||
try {
|
||||
await AsyncStorage.removeItem('hasCompletedOnboarding');
|
||||
Alert.alert('Success', 'Onboarding has been reset. Restart the app to see the onboarding flow.');
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to reset onboarding.');
|
||||
}
|
||||
}}
|
||||
renderControl={ChevronRight}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Clear All Data"
|
||||
icon="delete-forever"
|
||||
onPress={() => {
|
||||
Alert.alert(
|
||||
'Clear All Data',
|
||||
'This will reset all settings and clear all cached data. Are you sure?',
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Clear',
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
try {
|
||||
await AsyncStorage.clear();
|
||||
Alert.alert('Success', 'All data cleared. Please restart the app.');
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to clear data.');
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
}}
|
||||
isLast={true}
|
||||
/>
|
||||
</View>
|
||||
</SettingsCard>
|
||||
|
||||
{/* MDBList Cache Management */}
|
||||
{mdblistKeySet && (
|
||||
<SettingsCard title="MDBList Cache">
|
||||
<View style={{padding: 10}}>
|
||||
<Button
|
||||
title="Clear MDBList Cache"
|
||||
onPress={handleClearMDBListCache}
|
||||
color={currentTheme.colors.error}
|
||||
/>
|
||||
</View>
|
||||
</SettingsCard>
|
||||
)}
|
||||
|
||||
<SettingsCard title="About">
|
||||
<SettingItem
|
||||
title="Privacy Policy"
|
||||
description="Information about data collection and usage"
|
||||
icon="privacy-tip"
|
||||
onPress={() => Linking.openURL('https://your-privacy-policy-url.com')}
|
||||
renderControl={() => <ChevronRight />}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Test Onboarding"
|
||||
icon="play-circle-outline"
|
||||
onPress={() => navigation.navigate('Onboarding')}
|
||||
renderControl={() => <ChevronRight />}
|
||||
/>
|
||||
<SettingItem
|
||||
title="Reset Onboarding"
|
||||
icon="refresh"
|
||||
onPress={async () => {
|
||||
try {
|
||||
await AsyncStorage.removeItem('hasCompletedOnboarding');
|
||||
Alert.alert('Success', 'Onboarding has been reset. Restart the app to see the onboarding flow.');
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to reset onboarding.');
|
||||
}
|
||||
}}
|
||||
renderControl={() => <ChevronRight />}
|
||||
/>
|
||||
</SettingsCard>
|
||||
{/* Cache Management - Only show if MDBList is connected */}
|
||||
{mdblistKeySet && (
|
||||
<SettingsCard title="CACHE MANAGEMENT" delay={600}>
|
||||
<SettingItem
|
||||
title="Clear MDBList Cache"
|
||||
icon="cached"
|
||||
onPress={handleClearMDBListCache}
|
||||
isLast={true}
|
||||
/>
|
||||
</SettingsCard>
|
||||
)}
|
||||
|
||||
<View style={styles.versionContainer}>
|
||||
<Text style={[styles.versionText, {color: currentTheme.colors.mediumEmphasis}]}>
|
||||
Version 1.0.0
|
||||
<View style={styles.footer}>
|
||||
<Text style={[styles.footerText, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||
Made with ❤️ by the Nuvio team
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
|
@ -754,98 +673,39 @@ const styles = StyleSheet.create({
|
|||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
},
|
||||
versionContainer: {
|
||||
segmentedControl: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: 'rgba(255,255,255,0.08)',
|
||||
borderRadius: 8,
|
||||
padding: 2,
|
||||
},
|
||||
segment: {
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 6,
|
||||
minWidth: 60,
|
||||
alignItems: 'center',
|
||||
},
|
||||
segmentActive: {
|
||||
backgroundColor: 'rgba(255,255,255,0.16)',
|
||||
},
|
||||
segmentText: {
|
||||
fontSize: 13,
|
||||
fontWeight: '500',
|
||||
},
|
||||
segmentTextActive: {
|
||||
color: 'white',
|
||||
fontWeight: '600',
|
||||
},
|
||||
footer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 10,
|
||||
marginBottom: 20,
|
||||
},
|
||||
versionText: {
|
||||
footerText: {
|
||||
fontSize: 14,
|
||||
},
|
||||
pickerContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
picker: {
|
||||
flex: 1,
|
||||
},
|
||||
selectorContainer: {
|
||||
flexDirection: 'row',
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
height: 36,
|
||||
minWidth: 140,
|
||||
maxWidth: 180,
|
||||
marginRight: 8,
|
||||
alignSelf: 'flex-end',
|
||||
},
|
||||
selectorButton: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 8,
|
||||
backgroundColor: 'rgba(255,255,255,0.08)',
|
||||
},
|
||||
selectorText: {
|
||||
fontSize: Math.min(13, width * 0.034),
|
||||
fontWeight: '500',
|
||||
textAlign: 'center',
|
||||
},
|
||||
profileLockContainer: {
|
||||
padding: 16,
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
marginVertical: 8,
|
||||
},
|
||||
profileLockContent: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
profileLockTextContainer: {
|
||||
flex: 1,
|
||||
marginHorizontal: 12,
|
||||
},
|
||||
profileLockTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
marginBottom: 4,
|
||||
},
|
||||
profileLockDescription: {
|
||||
fontSize: 14,
|
||||
opacity: 0.8,
|
||||
},
|
||||
profileBenefits: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 16,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
benefitCol: {
|
||||
flex: 1,
|
||||
},
|
||||
benefitItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 8,
|
||||
},
|
||||
benefitText: {
|
||||
fontSize: 14,
|
||||
marginLeft: 8,
|
||||
},
|
||||
loginButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 8,
|
||||
paddingVertical: 12,
|
||||
marginTop: 16,
|
||||
},
|
||||
loginButtonText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
loginButtonIcon: {
|
||||
marginLeft: 8,
|
||||
opacity: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue