diff --git a/react-native-toast-message b/react-native-toast-message deleted file mode 160000 index e2db539..0000000 --- a/react-native-toast-message +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e2db539be40ab3caeef8de3725d5017474f71679 diff --git a/src/components/home/ContentItem.tsx b/src/components/home/ContentItem.tsx index 4635834..3a23b17 100644 --- a/src/components/home/ContentItem.tsx +++ b/src/components/home/ContentItem.tsx @@ -3,7 +3,7 @@ import { Toast } from 'toastify-react-native'; import { DeviceEventEmitter } from 'react-native'; import { View, TouchableOpacity, ActivityIndicator, StyleSheet, Dimensions, Platform, Text, Animated, Share } from 'react-native'; import FastImage from '@d11/react-native-fast-image'; -import { MaterialIcons } from '@expo/vector-icons'; +import { MaterialIcons, Feather } from '@expo/vector-icons'; import { useTheme } from '../../contexts/ThemeContext'; import { useSettings } from '../../hooks/useSettings'; import { catalogService, StreamingContent } from '../../services/catalogService'; @@ -279,7 +279,7 @@ const ContentItem = ({ item, onPress, shouldLoadImage: shouldLoadImageProp, defe )} {inLibrary && ( - + )} diff --git a/src/components/home/FeaturedContent.tsx b/src/components/home/FeaturedContent.tsx index 8437f6a..d02b19e 100644 --- a/src/components/home/FeaturedContent.tsx +++ b/src/components/home/FeaturedContent.tsx @@ -16,7 +16,7 @@ import { NavigationProp, useNavigation } from '@react-navigation/native'; import { RootStackParamList } from '../../navigation/AppNavigator'; import { LinearGradient } from 'expo-linear-gradient'; import FastImage from '@d11/react-native-fast-image'; -import { MaterialIcons } from '@expo/vector-icons'; +import { MaterialIcons, Feather } from '@expo/vector-icons'; import Animated, { FadeIn, useAnimatedStyle, @@ -518,11 +518,7 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary, loadin onPress={handleSaveToLibrary} activeOpacity={0.7} > - + {isSaved ? "Saved" : "My List"} @@ -628,11 +624,7 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary, loadin onPress={handleSaveToLibrary} activeOpacity={0.7} > - + {isSaved ? "Saved" : "Save"} diff --git a/src/components/icons/MDBListIcon.tsx b/src/components/icons/MDBListIcon.tsx new file mode 100644 index 0000000..85ae970 --- /dev/null +++ b/src/components/icons/MDBListIcon.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +interface MDBListIconProps { + size?: number; + colorPrimary?: string; // main brand color + colorSecondary?: string; // inner glyph color +} + +// MDBList logo built from provided SVG paths. Colors are kept as in the source. +const MDBListIcon: React.FC = ({ size = 24, colorPrimary = '#4284CA', colorSecondary = '#FBFCFE' }) => { + // Original SVG is 200x200; maintain square aspect. + return ( + + + + + + ); +}; + +export default MDBListIcon; + + diff --git a/src/components/icons/TMDBIcon.tsx b/src/components/icons/TMDBIcon.tsx new file mode 100644 index 0000000..fe73008 --- /dev/null +++ b/src/components/icons/TMDBIcon.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import Svg, { Defs, LinearGradient, Stop, Path } from 'react-native-svg'; + +interface TMDBIconProps { + size?: number; + color?: string; // primary theme color to tint the logo +} + +// TMDB logo rendered via react-native-svg. The gradient is themed using the provided color. +const TMDBIcon: React.FC = ({ size = 24, color = '#00b3e5' }) => { + // Maintain aspect ratio from original viewBox 185.04 x 133.4 + const width = size * (185.04 / 133.4); + const height = size; + + return ( + + + + + + + + + + + ); +}; + +export default TMDBIcon; + + diff --git a/src/components/metadata/FloatingHeader.tsx b/src/components/metadata/FloatingHeader.tsx index efcdeeb..73f1d36 100644 --- a/src/components/metadata/FloatingHeader.tsx +++ b/src/components/metadata/FloatingHeader.tsx @@ -8,7 +8,7 @@ import { Dimensions, } from 'react-native'; import { BlurView as ExpoBlurView } from 'expo-blur'; -import { MaterialIcons } from '@expo/vector-icons'; +import { MaterialIcons, Feather } from '@expo/vector-icons'; import FastImage from '@d11/react-native-fast-image'; import Animated, { useAnimatedStyle, @@ -115,11 +115,7 @@ const FloatingHeader: React.FC = ({ onPress={handleToggleLibrary} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} > - + @@ -164,11 +160,7 @@ const FloatingHeader: React.FC = ({ onPress={handleToggleLibrary} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} > - + diff --git a/src/components/metadata/HeroSection.tsx b/src/components/metadata/HeroSection.tsx index 87824a8..da0ff84 100644 --- a/src/components/metadata/HeroSection.tsx +++ b/src/components/metadata/HeroSection.tsx @@ -12,7 +12,7 @@ import { } from 'react-native'; import { useFocusEffect, useIsFocused } from '@react-navigation/native'; -import { MaterialIcons } from '@expo/vector-icons'; +import { MaterialIcons, Entypo, Feather } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; // Replaced FastImage with standard Image for logos import { BlurView as ExpoBlurView } from 'expo-blur'; @@ -285,8 +285,8 @@ const ActionButtons = memo(({ ) : ( )} - @@ -1451,8 +1451,8 @@ const HeroSection: React.FC = memo(({ borderRadius: 20, }} > - diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index ca05e52..72eb7c3 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -7,7 +7,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; import { PaperProvider, MD3DarkTheme, MD3LightTheme, adaptNavigationTheme } from 'react-native-paper'; import type { MD3Theme } from 'react-native-paper'; import type { BottomTabBarProps } from '@react-navigation/bottom-tabs'; -import { MaterialCommunityIcons } from '@expo/vector-icons'; +import { MaterialCommunityIcons, Feather, Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import { BlurView } from 'expo-blur'; import { colors } from '../styles/colors'; @@ -352,17 +352,14 @@ export const CustomNavigationDarkTheme: Theme = { fonts, }; -type IconNameType = 'home' | 'home-outline' | 'compass' | 'compass-outline' | - 'play-box-multiple' | 'play-box-multiple-outline' | - 'puzzle' | 'puzzle-outline' | - 'cog' | 'cog-outline' | 'feature-search' | 'feature-search-outline' | - 'magnify' | 'heart' | 'heart-outline' | 'download' | 'download-outline'; +type IconNameType = string; // Add TabIcon component -const TabIcon = React.memo(({ focused, color, iconName }: { +const TabIcon = React.memo(({ focused, color, iconName, iconLibrary = 'material' }: { focused: boolean; color: string; iconName: IconNameType; + iconLibrary?: 'material' | 'feather' | 'ionicons'; }) => { const scaleAnim = useRef(new Animated.Value(1)).current; @@ -375,8 +372,11 @@ const TabIcon = React.memo(({ focused, color, iconName }: { }).start(); }, [focused]); - // Use outline variant when available, but keep single-form icons (like 'magnify') the same + // Use outline variant when available for Material icons; Feather has single-form icons const finalIconName = (() => { + if (iconLibrary === 'feather') { + return iconName; + } if (iconName === 'magnify') return 'magnify'; return focused ? iconName : `${iconName}-outline` as IconNameType; })(); @@ -387,11 +387,25 @@ const TabIcon = React.memo(({ focused, color, iconName }: { justifyContent: 'center', transform: [{ scale: scaleAnim }] }}> - + {iconLibrary === 'feather' ? ( + + ) : iconLibrary === 'ionicons' ? ( + + ) : ( + + )} ); }); @@ -698,21 +712,27 @@ const MainTabs = () => { }; let iconName: IconNameType = 'home'; + let iconLibrary: 'material' | 'feather' | 'ionicons' = 'material'; switch (route.name) { case 'Home': iconName = 'home'; + iconLibrary = 'feather'; break; case 'Library': - iconName = 'heart'; + iconName = 'library'; + iconLibrary = 'ionicons'; break; case 'Search': - iconName = 'magnify'; + iconName = 'search'; + iconLibrary = 'feather'; break; case 'Downloads': iconName = 'download'; + iconLibrary = 'feather'; break; case 'Settings': - iconName = 'cog'; + iconName = 'settings'; + iconLibrary = 'feather'; break; } @@ -732,6 +752,7 @@ const MainTabs = () => { focused={isFocused} color={isFocused ? currentTheme.colors.primary : currentTheme.colors.white} iconName={iconName} + iconLibrary={iconLibrary} /> { onPress={() => navigation.navigate('Calendar')} activeOpacity={0.7} > - diff --git a/src/screens/SearchScreen.tsx b/src/screens/SearchScreen.tsx index be92d0b..22f1555 100644 --- a/src/screens/SearchScreen.tsx +++ b/src/screens/SearchScreen.tsx @@ -20,7 +20,7 @@ import { } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; -import { MaterialIcons } from '@expo/vector-icons'; +import { MaterialIcons, Feather } from '@expo/vector-icons'; import { catalogService, StreamingContent, GroupedSearchResults, AddonSearchResults } from '../services/catalogService'; import FastImage from '@d11/react-native-fast-image'; import debounce from 'lodash/debounce'; @@ -579,7 +579,7 @@ const SearchScreen = () => { {/* Bookmark and watched icons top right, bookmark to the left of watched */} {inLibrary && ( - + )} {watched && ( diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx index 118e206..20b3e9d 100644 --- a/src/screens/SettingsScreen.tsx +++ b/src/screens/SettingsScreen.tsx @@ -18,7 +18,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import FastImage from '@d11/react-native-fast-image'; -import { MaterialIcons } from '@expo/vector-icons'; +import { Feather } from '@expo/vector-icons'; import { Picker } from '@react-native-picker/picker'; import { useSettings, DEFAULT_SETTINGS } from '../hooks/useSettings'; import { RootStackParamList } from '../navigation/AppNavigator'; @@ -33,6 +33,8 @@ import { getDisplayedAppVersion } from '../utils/version'; import CustomAlert from '../components/CustomAlert'; import PluginIcon from '../components/icons/PluginIcon'; import TraktIcon from '../components/icons/TraktIcon'; +import TMDBIcon from '../components/icons/TMDBIcon'; +import MDBListIcon from '../components/icons/MDBListIcon'; const { width, height } = Dimensions.get('window'); const isTablet = width >= 768; @@ -41,17 +43,17 @@ const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0; // Settings categories for tablet sidebar const SETTINGS_CATEGORIES = [ - { id: 'account', title: 'Account', icon: 'account-circle' as keyof typeof MaterialIcons.glyphMap }, - { id: 'content', title: 'Content & Discovery', icon: 'explore' as keyof typeof MaterialIcons.glyphMap }, - { id: 'appearance', title: 'Appearance', icon: 'palette' as keyof typeof MaterialIcons.glyphMap }, - { id: 'integrations', title: 'Integrations', icon: 'extension' as keyof typeof MaterialIcons.glyphMap }, - { id: 'ai', title: 'AI Assistant', icon: 'smart-toy' as keyof typeof MaterialIcons.glyphMap }, - { id: 'playback', title: 'Playback', icon: 'play-circle-outline' as keyof typeof MaterialIcons.glyphMap }, - { id: 'backup', title: 'Backup & Restore', icon: 'save' as keyof typeof MaterialIcons.glyphMap }, - { id: 'updates', title: 'Updates', icon: 'system-update' as keyof typeof MaterialIcons.glyphMap }, - { id: 'about', title: 'About', icon: 'info-outline' as keyof typeof MaterialIcons.glyphMap }, - { id: 'developer', title: 'Developer', icon: 'code' as keyof typeof MaterialIcons.glyphMap }, - { id: 'cache', title: 'Cache', icon: 'cached' as keyof typeof MaterialIcons.glyphMap }, + { id: 'account', title: 'Account', icon: 'user' as string }, + { id: 'content', title: 'Content & Discovery', icon: 'compass' as string }, + { id: 'appearance', title: 'Appearance', icon: 'sliders' as string }, + { id: 'integrations', title: 'Integrations', icon: 'layers' as string }, + { id: 'ai', title: 'AI Assistant', icon: 'cpu' as string }, + { id: 'playback', title: 'Playback', icon: 'play-circle' as string }, + { id: 'backup', title: 'Backup & Restore', icon: 'archive' as string }, + { id: 'updates', title: 'Updates', icon: 'refresh-ccw' as string }, + { id: 'about', title: 'About', icon: 'info' as string }, + { id: 'developer', title: 'Developer', icon: 'code' as string }, + { id: 'cache', title: 'Cache', icon: 'database' as string }, ]; // Card component with minimalistic style @@ -94,7 +96,7 @@ const SettingsCard: React.FC = ({ children, title, isTablet = interface SettingItemProps { title: string; description?: string; - icon?: keyof typeof MaterialIcons.glyphMap; + icon?: string; customIcon?: React.ReactNode; renderControl?: () => React.ReactNode; isLast?: boolean; @@ -139,8 +141,8 @@ const SettingItem: React.FC = ({ {customIcon ? ( customIcon ) : ( - @@ -216,8 +218,8 @@ const Sidebar: React.FC = ({ selectedCategory, onCategorySelect, c ]} onPress={() => onCategorySelect(category.id)} > - { ); const ChevronRight = () => ( - { navigation.navigate('Addons')} isTablet={isTablet} @@ -470,7 +472,7 @@ const SettingsScreen: React.FC = () => { navigation.navigate('CatalogSettings')} isTablet={isTablet} @@ -493,7 +495,7 @@ const SettingsScreen: React.FC = () => { navigation.navigate('ThemeSettings')} isTablet={isTablet} @@ -501,7 +503,7 @@ const SettingsScreen: React.FC = () => { ( { } renderControl={ChevronRight} onPress={() => navigation.navigate('MDBListSettings')} isTablet={isTablet} @@ -528,7 +530,7 @@ const SettingsScreen: React.FC = () => { } renderControl={ChevronRight} onPress={() => navigation.navigate('TMDBSettings')} isLast={true} @@ -543,7 +545,7 @@ const SettingsScreen: React.FC = () => { navigation.navigate('AISettings')} isLast={true} @@ -561,7 +563,7 @@ const SettingsScreen: React.FC = () => { ? (settings?.preferredPlayer === 'internal' ? 'Built-in' : settings?.preferredPlayer?.toUpperCase() || 'Built-in') : (settings?.useExternalPlayer ? 'External' : 'Built-in') } - icon="play-circle-outline" + icon="play-circle" renderControl={ChevronRight} onPress={() => navigation.navigate('PlayerSettings')} isTablet={isTablet} @@ -569,7 +571,7 @@ const SettingsScreen: React.FC = () => { ( { navigation.navigate('NotificationSettings')} isLast={true} @@ -618,7 +620,7 @@ const SettingsScreen: React.FC = () => { /> Sentry.showFeedbackWidget()} renderControl={ChevronRight} isTablet={isTablet} @@ -626,7 +628,7 @@ const SettingsScreen: React.FC = () => { @@ -638,14 +640,14 @@ const SettingsScreen: React.FC = () => { navigation.navigate('Onboarding')} renderControl={ChevronRight} isTablet={isTablet} /> { try { await AsyncStorage.removeItem('hasCompletedOnboarding'); @@ -659,7 +661,7 @@ const SettingsScreen: React.FC = () => { /> { openAlert( 'Clear All Data', @@ -691,7 +693,7 @@ const SettingsScreen: React.FC = () => { { navigation.navigate('Backup')} isLast={true} @@ -720,7 +722,7 @@ const SettingsScreen: React.FC = () => { { diff --git a/toastify-react-native b/toastify-react-native deleted file mode 160000 index 17a44eb..0000000 --- a/toastify-react-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 17a44eb5d18612611cc9b0eca269101ddbf0311b