From 74a288bc1a8d2e61130b3d28813a5d8ee839d70f Mon Sep 17 00:00:00 2001 From: tapframe Date: Sun, 4 May 2025 02:03:59 +0530 Subject: [PATCH] Enhance ThemeScreen and ThemeContext with new themes and filtering functionality This update introduces several new themes (Emerald, Ruby, Amethyst, Amber, Mint, Slate, Neon, and Retro Wave) to the ThemeContext, expanding the available options for users. Additionally, the ThemeScreen has been refactored to include a category filter for better organization of themes, allowing users to easily navigate between different theme types. The UI has been improved with updated styles and components, enhancing the overall user experience and visual consistency across the application. --- src/contexts/ThemeContext.tsx | 88 +++++ src/screens/ThemeScreen.tsx | 628 ++++++++++++++++++++++++++-------- 2 files changed, 566 insertions(+), 150 deletions(-) diff --git a/src/contexts/ThemeContext.tsx b/src/contexts/ThemeContext.tsx index 084c3c3..5eb8c96 100644 --- a/src/contexts/ThemeContext.tsx +++ b/src/contexts/ThemeContext.tsx @@ -51,6 +51,94 @@ export const DEFAULT_THEMES: Theme[] = [ }, isEditable: false, }, + { + id: 'emerald', + name: 'Emerald', + colors: { + ...defaultColors, + primary: '#2ecc71', + secondary: '#3498db', + darkBackground: '#0e1e13', + }, + isEditable: false, + }, + { + id: 'ruby', + name: 'Ruby', + colors: { + ...defaultColors, + primary: '#e74c3c', + secondary: '#9b59b6', + darkBackground: '#1a0a0a', + }, + isEditable: false, + }, + { + id: 'amethyst', + name: 'Amethyst', + colors: { + ...defaultColors, + primary: '#9b59b6', + secondary: '#3498db', + darkBackground: '#140a1c', + }, + isEditable: false, + }, + { + id: 'amber', + name: 'Amber', + colors: { + ...defaultColors, + primary: '#f39c12', + secondary: '#d35400', + darkBackground: '#1a140a', + }, + isEditable: false, + }, + { + id: 'mint', + name: 'Mint', + colors: { + ...defaultColors, + primary: '#1abc9c', + secondary: '#16a085', + darkBackground: '#0a1a17', + }, + isEditable: false, + }, + { + id: 'slate', + name: 'Slate', + colors: { + ...defaultColors, + primary: '#7f8c8d', + secondary: '#95a5a6', + darkBackground: '#10191a', + }, + isEditable: false, + }, + { + id: 'neon', + name: 'Neon', + colors: { + ...defaultColors, + primary: '#00ff00', + secondary: '#ff00ff', + darkBackground: '#0a0a0a', + }, + isEditable: false, + }, + { + id: 'retro', + name: 'Retro Wave', + colors: { + ...defaultColors, + primary: '#ff00ff', + secondary: '#00ffff', + darkBackground: '#150036', + }, + isEditable: false, + }, ]; // Theme context props diff --git a/src/screens/ThemeScreen.tsx b/src/screens/ThemeScreen.tsx index 5305810..0f1e909 100644 --- a/src/screens/ThemeScreen.tsx +++ b/src/screens/ThemeScreen.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useEffect } from 'react'; +import React, { useState, useCallback, useEffect, useMemo } from 'react'; import { View, Text, @@ -11,6 +11,7 @@ import { TextInput, Dimensions, StatusBar, + FlatList, } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; @@ -23,6 +24,14 @@ import { RootStackParamList } from '../navigation/AppNavigator'; const { width } = Dimensions.get('window'); +// Theme categories for organization +const THEME_CATEGORIES = [ + { id: 'all', name: 'All Themes' }, + { id: 'dark', name: 'Dark Themes' }, + { id: 'colorful', name: 'Colorful' }, + { id: 'custom', name: 'My Themes' }, +]; + interface ThemeCardProps { theme: Theme; isSelected: boolean; @@ -43,7 +52,12 @@ const ThemeCard: React.FC = ({ style={[ styles.themeCard, isSelected && styles.selectedThemeCard, - { borderColor: theme.colors.primary } + { + borderColor: isSelected ? theme.colors.primary : 'transparent', + backgroundColor: Platform.OS === 'ios' + ? `${theme.colors.darkBackground}60` + : 'rgba(255, 255, 255, 0.07)' + } ]} onPress={onSelect} activeOpacity={0.7} @@ -53,34 +67,32 @@ const ThemeCard: React.FC = ({ {theme.name} {isSelected && ( - + )} - - Primary - - - Secondary - - - Background - + + + {theme.isEditable && ( {onEdit && ( - - - Edit + + )} {onDelete && ( - - - Delete + + )} @@ -89,6 +101,39 @@ const ThemeCard: React.FC = ({ ); }; +// Filter tab component +interface FilterTabProps { + category: { id: string; name: string }; + isActive: boolean; + onPress: () => void; + primaryColor: string; +} + +const FilterTab: React.FC = ({ + category, + isActive, + onPress, + primaryColor +}) => ( + + + {category.name} + + +); + type ColorKey = 'primary' | 'secondary' | 'darkBackground'; interface ThemeColorEditorProps { @@ -137,74 +182,119 @@ const ThemeColorEditor: React.FC = ({ }); }; + // Compact preview component + const ThemePreview = () => ( + + + {/* App header */} + + + + + + + + + {/* Content area */} + + {/* Featured content poster */} + + + + + + + + + + {/* Content row */} + + + + + + + + + + + + ); + return ( - Custom Theme - - - Theme Name + + + + + + Save + - - setSelectedColorKey('primary')} - > - Primary - + + + + + + setSelectedColorKey('primary')} + > + Primary + + + setSelectedColorKey('secondary')} + > + Secondary + + + setSelectedColorKey('darkBackground')} + > + Background + + + - setSelectedColorKey('secondary')} - > - Secondary - - - setSelectedColorKey('darkBackground')} - > - Background - - - - - - - - - - Cancel - - - Save Theme - + + + ); @@ -224,6 +314,7 @@ const ThemeScreen: React.FC = () => { const [isEditMode, setIsEditMode] = useState(false); const [editingTheme, setEditingTheme] = useState(null); + const [activeFilter, setActiveFilter] = useState('all'); // Force consistent status bar settings useEffect(() => { @@ -241,6 +332,34 @@ const ThemeScreen: React.FC = () => { return unsubscribe; }, [navigation]); + // Filter themes based on selected category + const filteredThemes = useMemo(() => { + switch (activeFilter) { + case 'dark': + // Themes with darker colors + return availableThemes.filter(theme => + !theme.isEditable && + theme.id !== 'neon' && + theme.id !== 'retro' + ); + case 'colorful': + // Themes with vibrant colors + return availableThemes.filter(theme => + !theme.isEditable && + (theme.id === 'neon' || + theme.id === 'retro' || + theme.id === 'sunset' || + theme.id === 'amber') + ); + case 'custom': + // User's custom themes + return availableThemes.filter(theme => theme.isEditable); + default: + // All themes + return availableThemes; + } + }, [availableThemes, activeFilter]); + const handleThemeSelect = useCallback((themeId: string) => { setCurrentTheme(themeId); }, [setCurrentTheme]); @@ -345,7 +464,7 @@ const ThemeScreen: React.FC = () => { ]}> navigation.goBack()} > @@ -353,13 +472,36 @@ const ThemeScreen: React.FC = () => { App Themes - + {/* Category filter */} + + item.id} + renderItem={({ item }) => ( + setActiveFilter(item.id)} + primaryColor={currentTheme.colors.primary} + /> + )} + contentContainerStyle={styles.filterList} + /> + + + SELECT THEME - {availableThemes.map(theme => ( + {filteredThemes.map(theme => ( { - + Create Custom Theme @@ -390,26 +536,50 @@ const styles = StyleSheet.create({ header: { flexDirection: 'row', alignItems: 'center', - padding: 16, + paddingHorizontal: 12, + paddingVertical: 8, }, backButton: { - padding: 8, + padding: 6, + borderRadius: 20, + backgroundColor: 'rgba(255, 255, 255, 0.1)', }, headerTitle: { - fontSize: 20, + fontSize: 18, fontWeight: 'bold', - marginLeft: 16, + marginLeft: 12, }, content: { flex: 1, }, contentContainer: { - padding: 16, + padding: 12, + paddingBottom: 24, + }, + filterContainer: { + marginBottom: 8, + }, + filterList: { + paddingHorizontal: 12, + }, + filterTab: { + paddingHorizontal: 12, + paddingVertical: 6, + borderRadius: 16, + marginRight: 8, + backgroundColor: 'rgba(255, 255, 255, 0.1)', + }, + filterTabText: { + fontSize: 12, + fontWeight: '600', + color: 'rgba(255, 255, 255, 0.8)', }, sectionTitle: { fontSize: 12, fontWeight: 'bold', - marginBottom: 16, + marginBottom: 10, + letterSpacing: 0.5, + textTransform: 'uppercase', }, themeGrid: { flexDirection: 'row', @@ -417,13 +587,20 @@ const styles = StyleSheet.create({ justifyContent: 'space-between', }, themeCard: { - width: (width - 48) / 2, - marginBottom: 16, + width: (width - 36) / 2, + marginBottom: 12, borderRadius: 12, - padding: 12, - backgroundColor: 'rgba(255, 255, 255, 0.05)', + padding: 10, borderWidth: 2, borderColor: 'transparent', + shadowColor: "#000", + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.1, + shadowRadius: 3.84, + elevation: 5, }, selectedThemeCard: { borderWidth: 2, @@ -432,93 +609,221 @@ const styles = StyleSheet.create({ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', - marginBottom: 12, + marginBottom: 8, }, themeCardTitle: { - fontSize: 16, + fontSize: 14, fontWeight: 'bold', }, colorPreviewContainer: { flexDirection: 'row', justifyContent: 'space-between', - marginBottom: 12, + marginBottom: 8, }, colorPreview: { - width: 30, - height: 30, - borderRadius: 15, - justifyContent: 'center', - alignItems: 'center', + width: 24, + height: 24, + borderRadius: 12, }, - colorPreviewLabel: { - fontSize: 6, - color: '#FFFFFF', - textShadowColor: 'rgba(0, 0, 0, 0.75)', - textShadowOffset: { width: 0, height: 1 }, - textShadowRadius: 2, + colorPreviewShadow: { + shadowColor: "#000", + shadowOffset: { + width: 0, + height: 1, + }, + shadowOpacity: 0.2, + shadowRadius: 1.5, + elevation: 2, }, themeCardActions: { flexDirection: 'row', - justifyContent: 'space-between', + justifyContent: 'flex-end', }, themeCardAction: { - flexDirection: 'row', - alignItems: 'center', - padding: 4, + padding: 6, + marginLeft: 8, + backgroundColor: 'rgba(255, 255, 255, 0.1)', + borderRadius: 16, }, - themeCardActionText: { - fontSize: 12, - marginLeft: 4, + buttonShadow: { + shadowColor: "#000", + shadowOffset: { + width: 0, + height: 1, + }, + shadowOpacity: 0.2, + shadowRadius: 1.41, + elevation: 2, }, createButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', - padding: 16, - borderRadius: 12, - marginTop: 16, + padding: 12, + borderRadius: 10, + marginTop: 12, }, createButtonText: { color: '#FFFFFF', fontWeight: 'bold', + fontSize: 14, marginLeft: 8, }, + + // Editor styles editorContainer: { flex: 1, - padding: 16, }, - editorTitle: { - fontSize: 22, - fontWeight: 'bold', + editorHeader: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: 10, + paddingVertical: 8, + borderBottomWidth: 1, + borderBottomColor: 'rgba(255, 255, 255, 0.1)', + }, + editorBackButton: { + padding: 5, + borderRadius: 16, + backgroundColor: 'rgba(255, 255, 255, 0.12)', + }, + editorTitleInput: { + flex: 1, color: '#FFFFFF', - marginBottom: 24, - }, - inputContainer: { - marginBottom: 24, - }, - inputLabel: { fontSize: 14, - color: 'rgba(255,255,255,0.7)', - marginBottom: 8, + fontWeight: 'bold', + marginHorizontal: 10, + padding: 0, + height: 28, }, - textInput: { - backgroundColor: 'rgba(255,255,255,0.1)', + editorSaveButton: { + paddingHorizontal: 10, + paddingVertical: 4, + borderRadius: 12, + backgroundColor: colors.primary, + }, + editorBody: { + flex: 1, + padding: 10, + }, + colorSectionRow: { + flexDirection: 'row', + marginBottom: 10, + }, + colorButtonsColumn: { + width: width * 0.4 - 20, // 40% minus padding + marginLeft: 10, + justifyContent: 'space-between', + }, + previewContainer: { + width: width * 0.6, + height: 120, borderRadius: 8, - padding: 12, - color: '#FFFFFF', - fontSize: 16, + overflow: 'hidden', + padding: 4, }, - colorSelectorContainer: { + previewContent: { + flex: 1, + borderRadius: 4, + overflow: 'hidden', + }, + previewHeader: { + height: 16, flexDirection: 'row', justifyContent: 'space-between', - marginBottom: 24, + alignItems: 'center', + paddingHorizontal: 4, + backgroundColor: 'rgba(0,0,0,0.3)', + }, + previewHeaderTitle: { + width: 40, + height: 8, + borderRadius: 2, + backgroundColor: 'rgba(255,255,255,0.4)', + }, + previewIconGroup: { + flexDirection: 'row', + }, + previewIcon: { + width: 8, + height: 8, + borderRadius: 4, + backgroundColor: 'rgba(255,255,255,0.4)', + marginLeft: 4, + }, + previewBody: { + flex: 1, + padding: 2, + }, + previewFeatured: { + height: 50, + borderRadius: 4, + backgroundColor: 'rgba(0,0,0,0.5)', + marginBottom: 4, + justifyContent: 'flex-end', + padding: 4, + }, + previewPosterGradient: { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + height: 30, + backgroundColor: 'rgba(0,0,0,0.4)', + }, + previewTitle: { + width: 60, + height: 6, + borderRadius: 3, + backgroundColor: 'rgba(255,255,255,0.7)', + marginBottom: 4, + }, + previewButtonRow: { + flexDirection: 'row', + alignItems: 'center', + }, + previewPlayButton: { + width: 35, + height: 12, + borderRadius: 3, + marginRight: 4, + }, + previewActionButton: { + width: 12, + height: 12, + borderRadius: 6, + backgroundColor: 'rgba(255,255,255,0.15)', + }, + previewSectionHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 2, + }, + previewSectionTitle: { + width: 40, + height: 6, + borderRadius: 3, + backgroundColor: 'rgba(255,255,255,0.4)', + }, + previewPosterRow: { + flexDirection: 'row', + justifyContent: 'space-between', + }, + previewPoster: { + width: '30%', + height: 30, + borderRadius: 3, + backgroundColor: 'rgba(255,255,255,0.15)', }, colorSelectorButton: { - width: (width - 64) / 3, - padding: 12, - borderRadius: 8, + height: 36, + paddingVertical: 5, + borderRadius: 6, alignItems: 'center', justifyContent: 'center', + marginBottom: 6, }, selectedColorButton: { borderWidth: 2, @@ -526,36 +831,58 @@ const styles = StyleSheet.create({ }, colorButtonText: { color: '#FFFFFF', - fontSize: 12, + fontSize: 10, fontWeight: 'bold', textShadowColor: 'rgba(0, 0, 0, 0.75)', textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 2, }, colorPickerContainer: { - height: 300, - marginBottom: 24, + flex: 1, + backgroundColor: 'rgba(255, 255, 255, 0.05)', + borderRadius: 8, + padding: 8, + marginBottom: 10, }, - editorActions: { - flexDirection: 'row', - justifyContent: 'space-between', + + // Legacy styles - keep for backward compatibility + editorTitle: { + fontSize: 18, + fontWeight: 'bold', + color: '#FFFFFF', + }, + inputContainer: { + marginBottom: 16, + }, + inputLabel: { + fontSize: 14, + color: 'rgba(255,255,255,0.7)', + marginBottom: 6, + }, + textInput: { + backgroundColor: 'rgba(255,255,255,0.1)', + borderRadius: 8, + padding: 10, + color: '#FFFFFF', + fontSize: 14, }, cancelButton: { - width: (width - 48) / 2, - padding: 16, - borderRadius: 8, + width: (width - 36) / 2, + padding: 12, + borderRadius: 10, alignItems: 'center', justifyContent: 'center', - backgroundColor: 'rgba(255,255,255,0.1)', + backgroundColor: 'rgba(255, 255, 255, 0.1)', }, cancelButtonText: { color: '#FFFFFF', fontWeight: 'bold', + fontSize: 14, }, saveButton: { - width: (width - 48) / 2, - padding: 16, - borderRadius: 8, + width: (width - 36) / 2, + padding: 12, + borderRadius: 10, alignItems: 'center', justifyContent: 'center', backgroundColor: colors.primary, @@ -563,6 +890,7 @@ const styles = StyleSheet.create({ saveButtonText: { color: '#FFFFFF', fontWeight: 'bold', + fontSize: 14, }, });