mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-21 00:32:04 +00:00
UI fix
This commit is contained in:
parent
238f08192f
commit
f31942efdf
5 changed files with 35 additions and 174 deletions
|
|
@ -1,10 +1,4 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Usage: build-and-publish-app-release.sh <xavia-ota-url> [--yes] [--release-notes "text here"]
|
|
||||||
# --yes Skip interactive confirmation
|
|
||||||
# --release-notes Provide release notes to attach to this upload
|
|
||||||
|
|
||||||
# Parse arguments
|
|
||||||
if [ "$#" -lt 1 ]; then
|
if [ "$#" -lt 1 ]; then
|
||||||
echo "Usage: $0 <xavia-ota-url> [--yes] [--release-notes \"text here\"]"
|
echo "Usage: $0 <xavia-ota-url> [--yes] [--release-notes \"text here\"]"
|
||||||
echo "Example: $0 https://grim-reyna-tapframe-69970143.koyeb.app --yes --release-notes \"Bug fixes and improvements\""
|
echo "Example: $0 https://grim-reyna-tapframe-69970143.koyeb.app --yes --release-notes \"Bug fixes and improvements\""
|
||||||
|
|
|
||||||
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -48,7 +48,7 @@
|
||||||
"expo-haptics": "~14.0.1",
|
"expo-haptics": "~14.0.1",
|
||||||
"expo-image": "~2.0.7",
|
"expo-image": "~2.0.7",
|
||||||
"expo-intent-launcher": "~12.0.2",
|
"expo-intent-launcher": "~12.0.2",
|
||||||
"expo-libvlc-player": "^2.2.1",
|
"expo-libvlc-player": "^2.1.7",
|
||||||
"expo-linear-gradient": "~14.0.2",
|
"expo-linear-gradient": "~14.0.2",
|
||||||
"expo-localization": "~16.0.1",
|
"expo-localization": "~16.0.1",
|
||||||
"expo-notifications": "~0.29.14",
|
"expo-notifications": "~0.29.14",
|
||||||
|
|
@ -8015,9 +8015,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-libvlc-player": {
|
"node_modules/expo-libvlc-player": {
|
||||||
"version": "2.2.1",
|
"version": "2.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/expo-libvlc-player/-/expo-libvlc-player-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/expo-libvlc-player/-/expo-libvlc-player-2.1.7.tgz",
|
||||||
"integrity": "sha512-RYp5t+2B5v8b5h1vfQfKwRYi8WjMaZQ6gWYFJJ+Phrx3tND+moTDIvG+OvPn6Uxn9TslzlbX1n6ad9jv/cypDw==",
|
"integrity": "sha512-WJz5vZE3qcFi2yeSYFWimdUS6oG+/gZZzsuhTvjCJ0pDTWsVeYVvmZbF4fg6cKRZf2WkZTaLzfngfVEBa6+3hA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"expo": "*",
|
"expo": "*",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
"expo-haptics": "~14.0.1",
|
"expo-haptics": "~14.0.1",
|
||||||
"expo-image": "~2.0.7",
|
"expo-image": "~2.0.7",
|
||||||
"expo-intent-launcher": "~12.0.2",
|
"expo-intent-launcher": "~12.0.2",
|
||||||
"expo-libvlc-player": "^2.2.1",
|
"expo-libvlc-player": "^2.1.7",
|
||||||
"expo-linear-gradient": "~14.0.2",
|
"expo-linear-gradient": "~14.0.2",
|
||||||
"expo-localization": "~16.0.1",
|
"expo-localization": "~16.0.1",
|
||||||
"expo-notifications": "~0.29.14",
|
"expo-notifications": "~0.29.14",
|
||||||
|
|
|
||||||
|
|
@ -38,16 +38,17 @@ export function useFeaturedContent() {
|
||||||
const currentIndexRef = useRef(0);
|
const currentIndexRef = useRef(0);
|
||||||
const abortControllerRef = useRef<AbortController | null>(null);
|
const abortControllerRef = useRef<AbortController | null>(null);
|
||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
const [contentSource, setContentSource] = useState<'tmdb' | 'catalogs'>(settings.featuredContentSource);
|
const [contentSource, setContentSource] = useState<'tmdb' | 'catalogs'>('catalogs');
|
||||||
const [selectedCatalogs, setSelectedCatalogs] = useState<string[]>(settings.selectedHeroCatalogs || []);
|
const [selectedCatalogs, setSelectedCatalogs] = useState<string[]>(settings.selectedHeroCatalogs || []);
|
||||||
|
|
||||||
const { genreMap, loadingGenres } = useGenres();
|
const { genreMap, loadingGenres } = useGenres();
|
||||||
|
|
||||||
// Simple update for state variables
|
// Simple update for state variables
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setContentSource(settings.featuredContentSource);
|
// Always use catalogs as the featured source
|
||||||
|
setContentSource('catalogs');
|
||||||
setSelectedCatalogs(settings.selectedHeroCatalogs || []);
|
setSelectedCatalogs(settings.selectedHeroCatalogs || []);
|
||||||
}, [settings]);
|
}, [settings.selectedHeroCatalogs]);
|
||||||
|
|
||||||
const cleanup = useCallback(() => {
|
const cleanup = useCallback(() => {
|
||||||
if (abortControllerRef.current) {
|
if (abortControllerRef.current) {
|
||||||
|
|
@ -58,14 +59,7 @@ export function useFeaturedContent() {
|
||||||
|
|
||||||
const loadFeaturedContent = useCallback(async (forceRefresh = false) => {
|
const loadFeaturedContent = useCallback(async (forceRefresh = false) => {
|
||||||
const t0 = Date.now();
|
const t0 = Date.now();
|
||||||
logger.info('[useFeaturedContent] load:start', { forceRefresh, contentSource, selectedCatalogsCount: (selectedCatalogs || []).length });
|
logger.info('[useFeaturedContent] load:start', { forceRefresh, contentSource: 'catalogs', selectedCatalogsCount: (selectedCatalogs || []).length });
|
||||||
// First, ensure contentSource matches current settings (could be outdated due to async updates)
|
|
||||||
if (contentSource !== settings.featuredContentSource) {
|
|
||||||
logger.debug('[useFeaturedContent] load:source-mismatch', { from: contentSource, to: settings.featuredContentSource });
|
|
||||||
setContentSource(settings.featuredContentSource);
|
|
||||||
// We return here and let the effect triggered by contentSource change handle the loading
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we should use cached data (disabled if DISABLE_CACHE)
|
// Check if we should use cached data (disabled if DISABLE_CACHE)
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
@ -92,7 +86,7 @@ export function useFeaturedContent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('[useFeaturedContent] fetch:start', { source: contentSource });
|
logger.info('[useFeaturedContent] fetch:start', { source: 'catalogs' });
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
cleanup();
|
cleanup();
|
||||||
abortControllerRef.current = new AbortController();
|
abortControllerRef.current = new AbortController();
|
||||||
|
|
@ -101,100 +95,7 @@ export function useFeaturedContent() {
|
||||||
try {
|
try {
|
||||||
let formattedContent: StreamingContent[] = [];
|
let formattedContent: StreamingContent[] = [];
|
||||||
|
|
||||||
if (contentSource === 'tmdb') {
|
{
|
||||||
// Load from TMDB trending
|
|
||||||
const tTmdb = Date.now();
|
|
||||||
const trendingResults = await tmdbService.getTrending('movie', 'day');
|
|
||||||
logger.info('[useFeaturedContent] tmdb:trending', { count: trendingResults?.length || 0, duration: `${Date.now() - tTmdb}ms` });
|
|
||||||
|
|
||||||
if (signal.aborted) return;
|
|
||||||
|
|
||||||
if (trendingResults.length > 0) {
|
|
||||||
// First convert items to StreamingContent objects
|
|
||||||
const preFormattedContent = trendingResults
|
|
||||||
.filter(item => item.title || item.name)
|
|
||||||
.map(item => {
|
|
||||||
const yearString = (item.release_date || item.first_air_date)?.substring(0, 4);
|
|
||||||
return {
|
|
||||||
id: `tmdb:${item.id}`,
|
|
||||||
type: 'movie',
|
|
||||||
name: item.title || item.name || 'Unknown Title',
|
|
||||||
poster: tmdbService.getImageUrl(item.poster_path) || '',
|
|
||||||
banner: tmdbService.getImageUrl(item.backdrop_path) || '',
|
|
||||||
logo: undefined, // Will be populated below
|
|
||||||
description: item.overview || '',
|
|
||||||
year: yearString ? parseInt(yearString, 10) : undefined,
|
|
||||||
genres: item.genre_ids.map(id =>
|
|
||||||
loadingGenres ? '...' : (genreMap[id] || `ID:${id}`)
|
|
||||||
),
|
|
||||||
inLibrary: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Then fetch logos for each item (TMDB when enrichment enabled)
|
|
||||||
const tLogos = Date.now();
|
|
||||||
const preferredLanguage = settings.tmdbLanguagePreference || 'en';
|
|
||||||
|
|
||||||
const fetchLogoForItem = async (item: StreamingContent): Promise<StreamingContent> => {
|
|
||||||
try {
|
|
||||||
// Support both TMDB-prefixed and IMDb-prefixed IDs
|
|
||||||
const isTmdb = item.id.startsWith('tmdb:');
|
|
||||||
const isImdb = item.id.startsWith('tt');
|
|
||||||
let tmdbId: string | null = null;
|
|
||||||
let imdbId: string | null = null;
|
|
||||||
|
|
||||||
if (isTmdb) {
|
|
||||||
tmdbId = item.id.split(':')[1];
|
|
||||||
} else if (isImdb) {
|
|
||||||
imdbId = item.id.split(':')[0];
|
|
||||||
} else {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enrichment path: TMDB only
|
|
||||||
logger.debug('[useFeaturedContent] logo:try:tmdb', { name: item.name, id: item.id, tmdbId, lang: preferredLanguage });
|
|
||||||
// Resolve TMDB id if we only have IMDb
|
|
||||||
if (!tmdbId && imdbId) {
|
|
||||||
const found = await tmdbService.findTMDBIdByIMDB(imdbId);
|
|
||||||
tmdbId = found ? String(found) : null;
|
|
||||||
}
|
|
||||||
if (!tmdbId) return item;
|
|
||||||
const logoUrl = tmdbId ? await tmdbService.getContentLogo('movie', tmdbId as string, preferredLanguage) : null;
|
|
||||||
if (logoUrl) {
|
|
||||||
logger.debug('[useFeaturedContent] logo:tmdb:ok', { name: item.name, id: item.id, url: logoUrl, lang: preferredLanguage });
|
|
||||||
return { ...item, logo: logoUrl };
|
|
||||||
}
|
|
||||||
logger.debug('[useFeaturedContent] logo:none', { name: item.name, id: item.id });
|
|
||||||
return item;
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('[useFeaturedContent] logo:error', { name: item.name, id: item.id, error: String(error) });
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only fetch logos if enrichment is enabled
|
|
||||||
if (settings.enrichMetadataWithTMDB) {
|
|
||||||
formattedContent = await Promise.all(preFormattedContent.map(fetchLogoForItem));
|
|
||||||
} else {
|
|
||||||
// When enrichment is disabled, just use the pre-formatted content with addon logos
|
|
||||||
formattedContent = preFormattedContent.map((item: StreamingContent) => ({
|
|
||||||
...item,
|
|
||||||
logo: item.logo && !isTmdbUrl(item.logo) ? item.logo : undefined
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
logger.info('[useFeaturedContent] logos:resolved', { count: formattedContent.length, duration: `${Date.now() - tLogos}ms` });
|
|
||||||
try {
|
|
||||||
const details = formattedContent.slice(0, 20).map((c) => ({
|
|
||||||
id: c.id,
|
|
||||||
name: c.name,
|
|
||||||
hasLogo: Boolean(c.logo),
|
|
||||||
logoSource: c.logo ? (isTmdbUrl(String(c.logo)) ? 'tmdb' : 'addon') : 'none',
|
|
||||||
logo: c.logo || undefined,
|
|
||||||
}));
|
|
||||||
logger.debug('[useFeaturedContent] logos:details', { items: details });
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Load from installed catalogs
|
// Load from installed catalogs
|
||||||
const tCats = Date.now();
|
const tCats = Date.now();
|
||||||
const catalogs = await catalogService.getHomeCatalogs();
|
const catalogs = await catalogService.getHomeCatalogs();
|
||||||
|
|
@ -431,7 +332,7 @@ export function useFeaturedContent() {
|
||||||
logger.info('[useFeaturedContent] load:done', { duration: `${Date.now() - t0}ms` });
|
logger.info('[useFeaturedContent] load:done', { duration: `${Date.now() - t0}ms` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [cleanup, genreMap, loadingGenres, contentSource, selectedCatalogs]);
|
}, [cleanup, genreMap, loadingGenres, selectedCatalogs]);
|
||||||
|
|
||||||
// Hydrate from persisted cache immediately for instant render
|
// Hydrate from persisted cache immediately for instant render
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -470,7 +371,6 @@ export function useFeaturedContent() {
|
||||||
// Check if settings changed while app was closed
|
// Check if settings changed while app was closed
|
||||||
const settingsChanged =
|
const settingsChanged =
|
||||||
persistentStore.lastSettings.showHeroSection !== settings.showHeroSection ||
|
persistentStore.lastSettings.showHeroSection !== settings.showHeroSection ||
|
||||||
persistentStore.lastSettings.featuredContentSource !== settings.featuredContentSource ||
|
|
||||||
JSON.stringify(persistentStore.lastSettings.selectedHeroCatalogs) !== JSON.stringify(settings.selectedHeroCatalogs) ||
|
JSON.stringify(persistentStore.lastSettings.selectedHeroCatalogs) !== JSON.stringify(settings.selectedHeroCatalogs) ||
|
||||||
persistentStore.lastSettings.logoSourcePreference !== settings.logoSourcePreference ||
|
persistentStore.lastSettings.logoSourcePreference !== settings.logoSourcePreference ||
|
||||||
persistentStore.lastSettings.tmdbLanguagePreference !== settings.tmdbLanguagePreference;
|
persistentStore.lastSettings.tmdbLanguagePreference !== settings.tmdbLanguagePreference;
|
||||||
|
|
@ -478,7 +378,7 @@ export function useFeaturedContent() {
|
||||||
// Update our tracking of last used settings
|
// Update our tracking of last used settings
|
||||||
persistentStore.lastSettings = {
|
persistentStore.lastSettings = {
|
||||||
showHeroSection: settings.showHeroSection,
|
showHeroSection: settings.showHeroSection,
|
||||||
featuredContentSource: settings.featuredContentSource,
|
featuredContentSource: 'catalogs',
|
||||||
selectedHeroCatalogs: [...settings.selectedHeroCatalogs],
|
selectedHeroCatalogs: [...settings.selectedHeroCatalogs],
|
||||||
logoSourcePreference: settings.logoSourcePreference,
|
logoSourcePreference: settings.logoSourcePreference,
|
||||||
tmdbLanguagePreference: settings.tmdbLanguagePreference
|
tmdbLanguagePreference: settings.tmdbLanguagePreference
|
||||||
|
|
@ -486,7 +386,7 @@ export function useFeaturedContent() {
|
||||||
|
|
||||||
// Force refresh if settings changed during app restart, but only if we have content
|
// Force refresh if settings changed during app restart, but only if we have content
|
||||||
if (settingsChanged && persistentStore.featuredContent) {
|
if (settingsChanged && persistentStore.featuredContent) {
|
||||||
logger.info('[useFeaturedContent] settings:changed', { source: settings.featuredContentSource, selectedCount: settings.selectedHeroCatalogs?.length || 0 });
|
logger.info('[useFeaturedContent] settings:changed', { selectedCount: settings.selectedHeroCatalogs?.length || 0 });
|
||||||
loadFeaturedContent(true);
|
loadFeaturedContent(true);
|
||||||
}
|
}
|
||||||
}, [settings, loadFeaturedContent]);
|
}, [settings, loadFeaturedContent]);
|
||||||
|
|
@ -495,34 +395,29 @@ export function useFeaturedContent() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleSettingsChange = () => {
|
const handleSettingsChange = () => {
|
||||||
// Always reflect settings immediately in this hook
|
// Always reflect settings immediately in this hook
|
||||||
const nextSource = settings.featuredContentSource;
|
|
||||||
const nextSelected = settings.selectedHeroCatalogs || [];
|
const nextSelected = settings.selectedHeroCatalogs || [];
|
||||||
const nextLogoPref = settings.logoSourcePreference;
|
const nextLogoPref = settings.logoSourcePreference;
|
||||||
const nextTmdbLang = settings.tmdbLanguagePreference;
|
const nextTmdbLang = settings.tmdbLanguagePreference;
|
||||||
|
|
||||||
const sourceChanged = contentSource !== nextSource;
|
|
||||||
const catalogsChanged = JSON.stringify(selectedCatalogs) !== JSON.stringify(nextSelected);
|
const catalogsChanged = JSON.stringify(selectedCatalogs) !== JSON.stringify(nextSelected);
|
||||||
const logoPrefChanged = persistentStore.lastSettings.logoSourcePreference !== nextLogoPref;
|
const logoPrefChanged = persistentStore.lastSettings.logoSourcePreference !== nextLogoPref;
|
||||||
const tmdbLangChanged = persistentStore.lastSettings.tmdbLanguagePreference !== nextTmdbLang;
|
const tmdbLangChanged = persistentStore.lastSettings.tmdbLanguagePreference !== nextTmdbLang;
|
||||||
|
|
||||||
if (sourceChanged || (nextSource === 'catalogs' && catalogsChanged) || logoPrefChanged || tmdbLangChanged) {
|
if (catalogsChanged || logoPrefChanged || tmdbLangChanged) {
|
||||||
logger.info('[useFeaturedContent] event:settings-changed:immediate-refresh', {
|
logger.info('[useFeaturedContent] event:settings-changed:immediate-refresh', {
|
||||||
fromSource: contentSource,
|
|
||||||
toSource: nextSource,
|
|
||||||
catalogsChanged,
|
catalogsChanged,
|
||||||
logoPrefChanged,
|
logoPrefChanged,
|
||||||
tmdbLangChanged
|
tmdbLangChanged
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update internal state immediately so dependent effects are in sync
|
// Update internal state immediately so dependent effects are in sync
|
||||||
setContentSource(nextSource);
|
|
||||||
setSelectedCatalogs(nextSelected);
|
setSelectedCatalogs(nextSelected);
|
||||||
// Update tracked last settings for subsequent comparisons
|
// Update tracked last settings for subsequent comparisons
|
||||||
persistentStore.lastSettings.logoSourcePreference = nextLogoPref;
|
persistentStore.lastSettings.logoSourcePreference = nextLogoPref;
|
||||||
persistentStore.lastSettings.tmdbLanguagePreference = nextTmdbLang;
|
persistentStore.lastSettings.tmdbLanguagePreference = nextTmdbLang;
|
||||||
|
|
||||||
// Only clear current data if it's a significant change (source or catalogs)
|
// Only clear current data if it's a significant change (source or catalogs)
|
||||||
if (sourceChanged || (nextSource === 'catalogs' && catalogsChanged)) {
|
if (catalogsChanged) {
|
||||||
setAllFeaturedContent([]);
|
setAllFeaturedContent([]);
|
||||||
setFeaturedContent(null);
|
setFeaturedContent(null);
|
||||||
persistentStore.allFeaturedContent = [];
|
persistentStore.allFeaturedContent = [];
|
||||||
|
|
@ -540,28 +435,15 @@ export function useFeaturedContent() {
|
||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
}, [loadFeaturedContent, settings, contentSource, selectedCatalogs]);
|
}, [loadFeaturedContent, settings, contentSource, selectedCatalogs]);
|
||||||
|
|
||||||
// Load featured content initially and when content source changes
|
// Load featured content initially and when catalogs selection changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Force refresh when switching to catalogs or when catalog selection changes
|
// Always use catalogs
|
||||||
if (contentSource === 'catalogs') {
|
setAllFeaturedContent([]);
|
||||||
// Clear cache when switching to catalogs mode
|
setFeaturedContent(null);
|
||||||
setAllFeaturedContent([]);
|
persistentStore.allFeaturedContent = [];
|
||||||
setFeaturedContent(null);
|
persistentStore.featuredContent = null;
|
||||||
persistentStore.allFeaturedContent = [];
|
loadFeaturedContent(true);
|
||||||
persistentStore.featuredContent = null;
|
}, [loadFeaturedContent, selectedCatalogs]);
|
||||||
loadFeaturedContent(true);
|
|
||||||
} else if (contentSource === 'tmdb' && contentSource !== persistentStore.featuredContent?.type) {
|
|
||||||
// Clear cache when switching to TMDB mode from catalogs
|
|
||||||
setAllFeaturedContent([]);
|
|
||||||
setFeaturedContent(null);
|
|
||||||
persistentStore.allFeaturedContent = [];
|
|
||||||
persistentStore.featuredContent = null;
|
|
||||||
loadFeaturedContent(true);
|
|
||||||
} else {
|
|
||||||
// Normal load (might use cache if available)
|
|
||||||
loadFeaturedContent(false);
|
|
||||||
}
|
|
||||||
}, [loadFeaturedContent, contentSource, selectedCatalogs]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (featuredContent) {
|
if (featuredContent) {
|
||||||
|
|
|
||||||
|
|
@ -313,16 +313,7 @@ const HomeScreenSettings: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<SettingItem
|
{settings.showHeroSection && (
|
||||||
title="Featured Content Source"
|
|
||||||
description={settings.featuredContentSource === 'tmdb' ? 'TMDB Trending' : 'From Catalogs'}
|
|
||||||
icon="settings-input-component"
|
|
||||||
isDarkMode={isDarkMode}
|
|
||||||
colors={colors}
|
|
||||||
renderControl={() => <View />}
|
|
||||||
isLast={!settings.showHeroSection || settings.featuredContentSource !== 'catalogs'}
|
|
||||||
/>
|
|
||||||
{settings.showHeroSection && settings.featuredContentSource === 'catalogs' && (
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title="Select Catalogs"
|
title="Select Catalogs"
|
||||||
description={getSelectedCatalogsText()}
|
description={getSelectedCatalogsText()}
|
||||||
|
|
@ -350,21 +341,15 @@ const HomeScreenSettings: React.FC = () => {
|
||||||
|
|
||||||
<View style={styles.segmentCard}>
|
<View style={styles.segmentCard}>
|
||||||
<Text style={[styles.segmentTitle, { color: isDarkMode ? colors.mediumEmphasis : colors.textMutedDark }]}>Featured Source</Text>
|
<Text style={[styles.segmentTitle, { color: isDarkMode ? colors.mediumEmphasis : colors.textMutedDark }]}>Featured Source</Text>
|
||||||
<SegmentedControl
|
<Text style={[styles.segmentHint, { color: isDarkMode ? colors.mediumEmphasis : colors.textMutedDark }]}>Using Catalogs</Text>
|
||||||
options={[{ label: 'TMDB', value: 'tmdb' }, { label: 'Catalogs', value: 'catalogs' }]}
|
<TouchableOpacity
|
||||||
value={settings.featuredContentSource}
|
onPress={() => navigation.navigate('HeroCatalogs')}
|
||||||
onChange={(val) => handleUpdateSetting('featuredContentSource', val as any)}
|
style={[styles.manageLink, { backgroundColor: isDarkMode ? colors.elevation1 : 'rgba(0,0,0,0.04)' }]}
|
||||||
/>
|
activeOpacity={0.8}
|
||||||
{settings.featuredContentSource === 'catalogs' && (
|
>
|
||||||
<TouchableOpacity
|
<Text style={{ color: isDarkMode ? colors.highEmphasis : colors.textDark, fontWeight: '600' }}>Manage selected catalogs</Text>
|
||||||
onPress={() => navigation.navigate('HeroCatalogs')}
|
<MaterialIcons name="chevron-right" size={20} color={isDarkMode ? colors.mediumEmphasis : colors.textMutedDark} />
|
||||||
style={[styles.manageLink, { backgroundColor: isDarkMode ? colors.elevation1 : 'rgba(0,0,0,0.04)' }]}
|
</TouchableOpacity>
|
||||||
activeOpacity={0.8}
|
|
||||||
>
|
|
||||||
<Text style={{ color: isDarkMode ? colors.highEmphasis : colors.textDark, fontWeight: '600' }}>Manage selected catalogs</Text>
|
|
||||||
<MaterialIcons name="chevron-right" size={20} color={isDarkMode ? colors.mediumEmphasis : colors.textMutedDark} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{settings.heroStyle === 'carousel' && (
|
{settings.heroStyle === 'carousel' && (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue