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:
tapframe 2025-06-30 13:48:20 +05:30
parent 12c7d8f860
commit 929ed9cc9e
4 changed files with 274 additions and 397 deletions

View file

@ -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>
);

View file

@ -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>
);

View file

@ -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);
}
};

View file

@ -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,
},
});