diff --git a/package-lock.json b/package-lock.json index f3f5b58f..99bfb79d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "nuvio", "version": "1.0.0", + "hasInstallScript": true, "dependencies": { "@expo/metro-runtime": "~4.0.1", "@expo/vector-icons": "^14.1.0", diff --git a/src/screens/LogoSourceSettings.tsx b/src/screens/LogoSourceSettings.tsx index e27ee9e0..2ebb9bee 100644 --- a/src/screens/LogoSourceSettings.tsx +++ b/src/screens/LogoSourceSettings.tsx @@ -95,6 +95,12 @@ const LogoSourceSettings = () => { const [tmdbBanner, setTmdbBanner] = useState(null); const [metahubBanner, setMetahubBanner] = useState(null); const [loadingLogos, setLoadingLogos] = useState(true); + + // State for TMDB language selection + const [selectedTmdbLanguage, setSelectedTmdbLanguage] = useState('en'); + // Store unique language codes as strings + const [uniqueTmdbLanguages, setUniqueTmdbLanguages] = useState([]); + const [tmdbLogosData, setTmdbLogosData] = useState | null>(null); // Load example logos for selected show useEffect(() => { @@ -108,6 +114,10 @@ const LogoSourceSettings = () => { setMetahubLogo(null); setTmdbBanner(null); setMetahubBanner(null); + // Reset unique languages and logos data + setUniqueTmdbLanguages([]); + setTmdbLogosData(null); + setSelectedTmdbLanguage('en'); // Reset to default language try { const tmdbService = TMDBService.getInstance(); @@ -119,482 +129,578 @@ const LogoSourceSettings = () => { // Get TMDB logo and banner try { - // Manually fetch images from TMDB API const apiKey = TMDB_API_KEY; const endpoint = contentType === 'tv' ? 'tv' : 'movie'; const response = await fetch(`https://api.themoviedb.org/3/${endpoint}/${tmdbId}/images?api_key=${apiKey}`); const imagesData = await response.json(); - // Get TMDB logo + // Store all TMDB logos data and extract unique languages if (imagesData.logos && imagesData.logos.length > 0) { - // Look for English logo first - let logoPath = null; + setTmdbLogosData(imagesData.logos); - // First try to find an English logo - const englishLogo = imagesData.logos.find((logo: { iso_639_1: string; file_path: string }) => - logo.iso_639_1 === 'en' - ); - if (englishLogo) { - logoPath = englishLogo.file_path; - } else if (imagesData.logos[0]) { - // Fallback to the first logo - logoPath = imagesData.logos[0].file_path; + // Filter for logos with valid language codes and get unique codes + const validLogoLanguages = imagesData.logos + .map((logo: { iso_639_1: string | null }) => logo.iso_639_1) + .filter((lang: string | null): lang is string => lang !== null && typeof lang === 'string'); + + // Explicitly type the Set and resulting array + const uniqueCodes: string[] = [...new Set(validLogoLanguages)]; + setUniqueTmdbLanguages(uniqueCodes); + + // Find initial logo (prefer 'en') + let initialLogoPath: string | null = null; + let initialLanguage = 'en'; + + const englishLogo = imagesData.logos.find((logo: { iso_639_1: string; file_path: string }) => logo.iso_639_1 === 'en'); + + if (englishLogo) { + initialLogoPath = englishLogo.file_path; + initialLanguage = 'en'; + logger.log(`[LogoSourceSettings] Found initial English TMDB logo for ${show.name}`); + } else if (imagesData.logos[0]) { + // Fallback to the first available logo + initialLogoPath = imagesData.logos[0].file_path; + initialLanguage = imagesData.logos[0].iso_639_1; + logger.log(`[LogoSourceSettings] No English logo, using first available (${initialLanguage}) TMDB logo for ${show.name}`); + } + + if (initialLogoPath) { + setTmdbLogo(`https://image.tmdb.org/t/p/original${initialLogoPath}`); + setSelectedTmdbLanguage(initialLanguage); // Set selected language based on found logo + } else { + logger.warn(`[LogoSourceSettings] No valid initial TMDB logo found for ${show.name}`); + } + } else { + logger.warn(`[LogoSourceSettings] No TMDB logos found in response for ${show.name}`); + setUniqueTmdbLanguages([]); // Ensure it's empty if no logos } - if (logoPath) { - const tmdbLogoUrl = `https://image.tmdb.org/t/p/original${logoPath}`; - setTmdbLogo(tmdbLogoUrl); - logger.log(`[LogoSourceSettings] Got ${show.name} TMDB logo: ${tmdbLogoUrl}`); + // Get TMDB banner (backdrop) + if (imagesData.backdrops && imagesData.backdrops.length > 0) { + const backdropPath = imagesData.backdrops[0].file_path; + const tmdbBannerUrl = `https://image.tmdb.org/t/p/original${backdropPath}`; + setTmdbBanner(tmdbBannerUrl); + logger.log(`[LogoSourceSettings] Got ${show.name} TMDB banner: ${tmdbBannerUrl}`); + } else { + // Try to get backdrop from details + const detailsResponse = await fetch(`https://api.themoviedb.org/3/${endpoint}/${tmdbId}?api_key=${apiKey}`); + const details = await detailsResponse.json(); + + if (details.backdrop_path) { + const tmdbBannerUrl = `https://image.tmdb.org/t/p/original${details.backdrop_path}`; + setTmdbBanner(tmdbBannerUrl); + logger.log(`[LogoSourceSettings] Got ${show.name} TMDB banner from details: ${tmdbBannerUrl}`); + } } + } catch (tmdbError) { + logger.error(`[LogoSourceSettings] Error fetching TMDB images:`, tmdbError); } - // Get TMDB banner (backdrop) - if (imagesData.backdrops && imagesData.backdrops.length > 0) { - const backdropPath = imagesData.backdrops[0].file_path; - const tmdbBannerUrl = `https://image.tmdb.org/t/p/original${backdropPath}`; - setTmdbBanner(tmdbBannerUrl); - logger.log(`[LogoSourceSettings] Got ${show.name} TMDB banner: ${tmdbBannerUrl}`); - } else { - // Try to get backdrop from details - const detailsResponse = await fetch(`https://api.themoviedb.org/3/${endpoint}/${tmdbId}?api_key=${apiKey}`); - const details = await detailsResponse.json(); + // Get Metahub logo and banner + try { + // Metahub logo + const metahubLogoUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`; + const logoResponse = await fetch(metahubLogoUrl, { method: 'HEAD' }); - if (details.backdrop_path) { - const tmdbBannerUrl = `https://image.tmdb.org/t/p/original${details.backdrop_path}`; - setTmdbBanner(tmdbBannerUrl); - logger.log(`[LogoSourceSettings] Got ${show.name} TMDB banner from details: ${tmdbBannerUrl}`); + if (logoResponse.ok) { + setMetahubLogo(metahubLogoUrl); + logger.log(`[LogoSourceSettings] Got ${show.name} Metahub logo: ${metahubLogoUrl}`); } + + // Metahub banner + const metahubBannerUrl = `https://images.metahub.space/background/medium/${imdbId}/img`; + const bannerResponse = await fetch(metahubBannerUrl, { method: 'HEAD' }); + + if (bannerResponse.ok) { + setMetahubBanner(metahubBannerUrl); + logger.log(`[LogoSourceSettings] Got ${show.name} Metahub banner: ${metahubBannerUrl}`); + } else if (tmdbBanner) { + // If Metahub banner doesn't exist, use TMDB banner + setMetahubBanner(tmdbBanner); + } + } catch (metahubErr) { + logger.error(`[LogoSourceSettings] Error checking Metahub images:`, metahubErr); } - } catch (tmdbError) { - logger.error(`[LogoSourceSettings] Error fetching TMDB images:`, tmdbError); + } catch (err) { + logger.error(`[LogoSourceSettings] Error fetching ${show.name} logos:`, err); + } finally { + setLoadingLogos(false); + } + }; + + // Apply setting and show confirmation + const applyLogoSourceSetting = (source: 'metahub' | 'tmdb') => { + setLogoSource(source); + updateSetting('logoSourcePreference', source); + + // Clear any cached logo data in storage + try { + AsyncStorage.removeItem('_last_logos_'); + } catch (e) { + console.error('Error clearing logo cache:', e); } - // Get Metahub logo and banner - try { - // Metahub logo - const metahubLogoUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`; - const logoResponse = await fetch(metahubLogoUrl, { method: 'HEAD' }); - - if (logoResponse.ok) { - setMetahubLogo(metahubLogoUrl); - logger.log(`[LogoSourceSettings] Got ${show.name} Metahub logo: ${metahubLogoUrl}`); - } - - // Metahub banner - const metahubBannerUrl = `https://images.metahub.space/background/medium/${imdbId}/img`; - const bannerResponse = await fetch(metahubBannerUrl, { method: 'HEAD' }); - - if (bannerResponse.ok) { - setMetahubBanner(metahubBannerUrl); - logger.log(`[LogoSourceSettings] Got ${show.name} Metahub banner: ${metahubBannerUrl}`); - } else if (tmdbBanner) { - // If Metahub banner doesn't exist, use TMDB banner - setMetahubBanner(tmdbBanner); - } - } catch (metahubErr) { - logger.error(`[LogoSourceSettings] Error checking Metahub images:`, metahubErr); - } - } catch (err) { - logger.error(`[LogoSourceSettings] Error fetching ${show.name} logos:`, err); - } finally { - setLoadingLogos(false); - } - }; - - // Apply setting and show confirmation - const applyLogoSourceSetting = (source: 'metahub' | 'tmdb') => { - setLogoSource(source); - updateSetting('logoSourcePreference', source); + // Show confirmation alert + Alert.alert( + 'Settings Updated', + `Logo and background source preference set to ${source === 'metahub' ? 'Metahub' : 'TMDB'}. Changes will apply when you navigate to content.`, + [{ text: 'OK' }] + ); + }; - // Clear any cached logo data in storage - try { - AsyncStorage.removeItem('_last_logos_'); - } catch (e) { - console.error('Error clearing logo cache:', e); - } - - // Show confirmation alert - Alert.alert( - 'Settings Updated', - `Logo and background source preference set to ${source === 'metahub' ? 'Metahub' : 'TMDB'}. Changes will apply when you navigate to content.`, - [{ text: 'OK' }] - ); - }; - - // Save selected show to AsyncStorage to persist across navigation - const saveSelectedShow = async (show: typeof EXAMPLE_SHOWS[0]) => { - try { - await AsyncStorage.setItem('logo_settings_selected_show', show.imdbId); - } catch (e) { - console.error('Error saving selected show:', e); - } - }; - - // Load selected show from AsyncStorage on mount - useEffect(() => { - const loadSelectedShow = async () => { + // Save selected show to AsyncStorage to persist across navigation + const saveSelectedShow = async (show: typeof EXAMPLE_SHOWS[0]) => { try { - const savedShowId = await AsyncStorage.getItem('logo_settings_selected_show'); - if (savedShowId) { - const foundShow = EXAMPLE_SHOWS.find(show => show.imdbId === savedShowId); - if (foundShow) { - setSelectedShow(foundShow); - } - } + await AsyncStorage.setItem('logo_settings_selected_show', show.imdbId); } catch (e) { - console.error('Error loading selected show:', e); + console.error('Error saving selected show:', e); } }; - loadSelectedShow(); - }, []); - - // Update selected show and save to AsyncStorage - const handleShowSelect = (show: typeof EXAMPLE_SHOWS[0]) => { - setSelectedShow(show); - saveSelectedShow(show); - }; + // Load selected show from AsyncStorage on mount + useEffect(() => { + const loadSelectedShow = async () => { + try { + const savedShowId = await AsyncStorage.getItem('logo_settings_selected_show'); + if (savedShowId) { + const foundShow = EXAMPLE_SHOWS.find(show => show.imdbId === savedShowId); + if (foundShow) { + setSelectedShow(foundShow); + } + } + } catch (e) { + console.error('Error loading selected show:', e); + } + }; + + loadSelectedShow(); + }, []); + + // Update selected show and save to AsyncStorage + const handleShowSelect = (show: typeof EXAMPLE_SHOWS[0]) => { + setSelectedShow(show); + saveSelectedShow(show); + }; - // Handle back navigation - const handleBack = () => { - navigation.goBack(); - }; + // Handle back navigation + const handleBack = () => { + navigation.goBack(); + }; - // Render logo example with loading state and background - const renderLogoExample = (logo: string | null, banner: string | null, isLoading: boolean) => { - if (isLoading) { + // Render logo example with loading state and background + const renderLogoExample = (logo: string | null, banner: string | null, isLoading: boolean) => { + if (isLoading) { + return ( + + + + ); + } + return ( - - + + + + {logo && ( + + )} + {!logo && ( + + No logo available + + )} ); - } - + }; + + // Handle TMDB language selection + const handleTmdbLanguageSelect = (languageCode: string) => { + setSelectedTmdbLanguage(languageCode); + if (tmdbLogosData) { + const selectedLogoData = tmdbLogosData.find(logo => logo.iso_639_1 === languageCode); + if (selectedLogoData) { + setTmdbLogo(`https://image.tmdb.org/t/p/original${selectedLogoData.file_path}`); + logger.log(`[LogoSourceSettings] Switched TMDB logo to language: ${languageCode}`); + } else { + logger.warn(`[LogoSourceSettings] Could not find logo data for selected language: ${languageCode}`); + } + } + }; + return ( - - - - {logo && ( - - )} - {!logo && ( - - No logo available + + + + {/* Header */} + + + + + Logo Source + + + + + {/* Description */} + + + Choose the primary source for content logos and background images. This affects the appearance + of titles in the metadata screen. + - )} - + + {/* Show selector */} + + Select a show/movie to preview: + + {EXAMPLE_SHOWS.map((show) => ( + handleShowSelect(show)} + > + + {show.name} + + + ))} + + + + {/* Options */} + + applyLogoSourceSetting('metahub')} + > + + Metahub + {logoSource === 'metahub' && ( + + )} + + + + Prioritizes high-quality title logos from the Metahub image repository. + Offers good coverage for popular titles. + + + + Example: + {renderLogoExample(metahubLogo, metahubBanner, loadingLogos)} + {selectedShow.name} logo from Metahub + + + + applyLogoSourceSetting('tmdb')} + > + + TMDB + {logoSource === 'tmdb' && ( + + )} + + + + Uses logos from The Movie Database. Often includes more localized and newer logos, + with better coverage for recent content. + + + + Example: + {renderLogoExample(tmdbLogo, tmdbBanner, loadingLogos)} + {selectedShow.name} logo from TMDB + + + {/* TMDB Language Selector */} + {uniqueTmdbLanguages.length > 1 && ( + + Available logo languages: + + {/* Iterate over unique language codes */} + {uniqueTmdbLanguages.map((langCode) => ( + handleTmdbLanguageSelect(langCode)} + > + + {(langCode || '').toUpperCase() || '??'} + + + ))} + + + )} + + + + {/* Additional Info */} + + + If a logo is not available from your preferred source, the app will automatically fall back to the other source. + If no logo is found, the title text will be shown instead. + + + + ); }; - return ( - - - - {/* Header */} - - - - - Logo Source - - - - - {/* Description */} - - - Choose the primary source for content logos and background images. This affects the appearance - of titles in the metadata screen. - - - - {/* Show selector */} - - Select a show/movie to preview: - - {EXAMPLE_SHOWS.map((show) => ( - handleShowSelect(show)} - > - - {show.name} - - - ))} - - - - {/* Options */} - - applyLogoSourceSetting('metahub')} - > - - Metahub - {logoSource === 'metahub' && ( - - )} - - - - Prioritizes high-quality title logos from the Metahub image repository. - Offers good coverage for popular titles. - - - - Example: - {renderLogoExample(metahubLogo, metahubBanner, loadingLogos)} - {selectedShow.name} logo from Metahub - - - - applyLogoSourceSetting('tmdb')} - > - - TMDB - {logoSource === 'tmdb' && ( - - )} - - - - Uses logos from The Movie Database. Often includes more localized and newer logos, - with better coverage for recent content. - - - - Example: - {renderLogoExample(tmdbLogo, tmdbBanner, loadingLogos)} - {selectedShow.name} logo from TMDB - - - - - {/* Additional Info */} - - - If a logo is not available from your preferred source, the app will automatically fall back to the other source. - If no logo is found, the title text will be shown instead. - - - - - ); -}; + const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: colors.darkBackground, + }, + header: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: 16, + height: 56, + backgroundColor: colors.elevation2, + }, + backButton: { + width: 40, + height: 40, + alignItems: 'center', + justifyContent: 'center', + }, + headerTitle: { + color: colors.white, + fontSize: 20, + fontWeight: '600', + }, + headerRight: { + width: 40, + }, + scrollView: { + flex: 1, + }, + descriptionContainer: { + padding: 16, + borderBottomWidth: 1, + borderBottomColor: 'rgba(255,255,255,0.1)', + }, + description: { + color: colors.text, + fontSize: 16, + lineHeight: 24, + }, + showSelectorContainer: { + padding: 16, + paddingBottom: 8, + }, + selectorLabel: { + color: colors.text, + fontSize: 16, + marginBottom: 12, + }, + showsScrollContent: { + paddingRight: 16, + }, + showItem: { + paddingHorizontal: 16, + paddingVertical: 8, + backgroundColor: colors.elevation2, + borderRadius: 20, + marginRight: 8, + borderWidth: 1, + borderColor: 'transparent', + }, + selectedShowItem: { + borderColor: colors.primary, + backgroundColor: colors.elevation3, + }, + showItemText: { + color: colors.mediumEmphasis, + fontSize: 14, + }, + selectedShowItemText: { + color: colors.white, + fontWeight: '600', + }, + optionsContainer: { + padding: 16, + gap: 16, + }, + optionCard: { + backgroundColor: colors.elevation2, + borderRadius: 12, + padding: 16, + borderWidth: 2, + borderColor: 'transparent', + }, + selectedCard: { + borderColor: colors.primary, + }, + optionHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 8, + }, + optionTitle: { + color: colors.white, + fontSize: 18, + fontWeight: '600', + }, + optionDescription: { + color: colors.mediumEmphasis, + fontSize: 14, + lineHeight: 20, + marginBottom: 16, + }, + exampleContainer: { + marginTop: 8, + }, + exampleLabel: { + color: colors.mediumEmphasis, + fontSize: 14, + marginBottom: 8, + }, + exampleImage: { + height: 60, + width: '100%', + backgroundColor: 'rgba(0,0,0,0.5)', + borderRadius: 8, + }, + loadingContainer: { + justifyContent: 'center', + alignItems: 'center', + }, + infoBox: { + margin: 16, + padding: 16, + backgroundColor: 'rgba(255,255,255,0.05)', + borderRadius: 8, + borderLeftWidth: 4, + borderLeftColor: colors.primary, + }, + infoText: { + color: colors.mediumEmphasis, + fontSize: 14, + lineHeight: 20, + }, + logoSourceLabel: { + color: colors.mediumEmphasis, + fontSize: 12, + marginTop: 4, + }, + languageSelectorContainer: { + marginTop: 16, + }, + languageSelectorLabel: { + color: colors.mediumEmphasis, + fontSize: 13, + marginBottom: 8, + }, + languageScrollContent: { + paddingRight: 16, // Match container padding + }, + languageItem: { + paddingHorizontal: 12, + paddingVertical: 6, + backgroundColor: colors.elevation1, + borderRadius: 16, + marginRight: 8, + borderWidth: 1, + borderColor: colors.elevation3, + }, + selectedLanguageItem: { + backgroundColor: colors.primary, + borderColor: colors.primary, + }, + languageItemText: { + color: colors.mediumEmphasis, + fontSize: 13, + fontWeight: '600', + }, + selectedLanguageItemText: { + color: colors.white, + }, + bannerContainer: { + height: 120, + width: '100%', + borderRadius: 8, + overflow: 'hidden', + position: 'relative', + }, + bannerImage: { + ...StyleSheet.absoluteFillObject, + }, + bannerOverlay: { + ...StyleSheet.absoluteFillObject, + backgroundColor: 'rgba(0,0,0,0.5)', + }, + logoOverBanner: { + position: 'absolute', + width: '80%', + height: '80%', + alignSelf: 'center', + top: '10%', + }, + noLogoContainer: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + justifyContent: 'center', + alignItems: 'center', + }, + noLogoText: { + color: colors.white, + fontSize: 14, + backgroundColor: 'rgba(0,0,0,0.5)', + paddingHorizontal: 12, + paddingVertical: 6, + borderRadius: 4, + }, + }); -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: colors.darkBackground, - }, - header: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 16, - height: 56, - backgroundColor: colors.elevation2, - }, - backButton: { - width: 40, - height: 40, - alignItems: 'center', - justifyContent: 'center', - }, - headerTitle: { - color: colors.white, - fontSize: 20, - fontWeight: '600', - }, - headerRight: { - width: 40, - }, - scrollView: { - flex: 1, - }, - descriptionContainer: { - padding: 16, - borderBottomWidth: 1, - borderBottomColor: 'rgba(255,255,255,0.1)', - }, - description: { - color: colors.text, - fontSize: 16, - lineHeight: 24, - }, - showSelectorContainer: { - padding: 16, - paddingBottom: 8, - }, - selectorLabel: { - color: colors.text, - fontSize: 16, - marginBottom: 12, - }, - showsScrollContent: { - paddingRight: 16, - }, - showItem: { - paddingHorizontal: 16, - paddingVertical: 8, - backgroundColor: colors.elevation2, - borderRadius: 20, - marginRight: 8, - borderWidth: 1, - borderColor: 'transparent', - }, - selectedShowItem: { - borderColor: colors.primary, - backgroundColor: colors.elevation3, - }, - showItemText: { - color: colors.mediumEmphasis, - fontSize: 14, - }, - selectedShowItemText: { - color: colors.white, - fontWeight: '600', - }, - optionsContainer: { - padding: 16, - gap: 16, - }, - optionCard: { - backgroundColor: colors.elevation2, - borderRadius: 12, - padding: 16, - borderWidth: 2, - borderColor: 'transparent', - }, - selectedCard: { - borderColor: colors.primary, - }, - optionHeader: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: 8, - }, - optionTitle: { - color: colors.white, - fontSize: 18, - fontWeight: '600', - }, - optionDescription: { - color: colors.mediumEmphasis, - fontSize: 14, - lineHeight: 20, - marginBottom: 16, - }, - exampleContainer: { - marginTop: 8, - }, - exampleLabel: { - color: colors.mediumEmphasis, - fontSize: 14, - marginBottom: 8, - }, - exampleImage: { - height: 60, - width: '100%', - backgroundColor: 'rgba(0,0,0,0.5)', - borderRadius: 8, - }, - loadingContainer: { - justifyContent: 'center', - alignItems: 'center', - }, - infoBox: { - margin: 16, - padding: 16, - backgroundColor: 'rgba(255,255,255,0.05)', - borderRadius: 8, - borderLeftWidth: 4, - borderLeftColor: colors.primary, - }, - infoText: { - color: colors.mediumEmphasis, - fontSize: 14, - lineHeight: 20, - }, - logoSourceLabel: { - color: colors.mediumEmphasis, - fontSize: 12, - marginTop: 4, - }, - bannerContainer: { - height: 120, - width: '100%', - borderRadius: 8, - overflow: 'hidden', - position: 'relative', - }, - bannerImage: { - ...StyleSheet.absoluteFillObject, - }, - bannerOverlay: { - ...StyleSheet.absoluteFillObject, - backgroundColor: 'rgba(0,0,0,0.5)', - }, - logoOverBanner: { - position: 'absolute', - width: '80%', - height: '80%', - alignSelf: 'center', - top: '10%', - }, - noLogoContainer: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, - justifyContent: 'center', - alignItems: 'center', - }, - noLogoText: { - color: colors.white, - fontSize: 14, - backgroundColor: 'rgba(0,0,0,0.5)', - paddingHorizontal: 12, - paddingVertical: 6, - borderRadius: 4, - }, -}); - -export default LogoSourceSettings; \ No newline at end of file + export default LogoSourceSettings; \ No newline at end of file