This commit is contained in:
tapframe 2025-07-27 19:10:22 +05:30
parent 2180453a16
commit 49e9b213bc
2 changed files with 71 additions and 26 deletions

View file

@ -39,29 +39,39 @@ const SPACING = {
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
// Screen dimensions and grid layout
const { width } = Dimensions.get('window');
// Dynamic column calculation based on screen width
const calculateCatalogLayout = (screenWidth: number) => {
const MIN_ITEM_WIDTH = 120; // Increased minimum for better readability
const MAX_ITEM_WIDTH = 160; // Adjusted maximum
const HORIZONTAL_PADDING = SPACING.lg * 2; // Total horizontal padding
const ITEM_SPACING = SPACING.sm; // Space between items
const MIN_ITEM_WIDTH = 120;
const MAX_ITEM_WIDTH = 180; // Increased for tablets
const HORIZONTAL_PADDING = SPACING.lg * 2;
const ITEM_SPACING = SPACING.sm;
// Calculate how many columns can fit
const availableWidth = screenWidth - HORIZONTAL_PADDING;
const maxColumns = Math.floor(availableWidth / (MIN_ITEM_WIDTH + ITEM_SPACING));
// Limit to reasonable number of columns (2-4 for better UX)
const numColumns = Math.min(Math.max(maxColumns, 2), 4);
// More flexible column limits for different screen sizes
let numColumns;
if (screenWidth < 600) {
// Phone: 2-3 columns
numColumns = Math.min(Math.max(maxColumns, 2), 3);
} else if (screenWidth < 900) {
// Small tablet: 3-5 columns
numColumns = Math.min(Math.max(maxColumns, 3), 5);
} else if (screenWidth < 1200) {
// Large tablet: 4-6 columns
numColumns = Math.min(Math.max(maxColumns, 4), 6);
} else {
// Very large screens: 5-8 columns
numColumns = Math.min(Math.max(maxColumns, 5), 8);
}
// Calculate actual item width with proper spacing
const totalSpacing = ITEM_SPACING * (numColumns - 1);
const itemWidth = (availableWidth - totalSpacing) / numColumns;
// For 2 columns, ensure we use the full available width
const finalItemWidth = numColumns === 2 ? itemWidth : Math.min(itemWidth, MAX_ITEM_WIDTH);
// Ensure item width doesn't exceed maximum
const finalItemWidth = Math.min(itemWidth, MAX_ITEM_WIDTH);
return {
numColumns,
@ -69,11 +79,6 @@ const calculateCatalogLayout = (screenWidth: number) => {
};
};
const catalogLayout = calculateCatalogLayout(width);
const NUM_COLUMNS = catalogLayout.numColumns;
const ITEM_MARGIN = SPACING.sm;
const ITEM_WIDTH = catalogLayout.itemWidth;
// Create a styles creator function that accepts the theme colors
const createStyles = (colors: any) => StyleSheet.create({
container: {
@ -85,6 +90,10 @@ const createStyles = (colors: any) => StyleSheet.create({
alignItems: 'center',
paddingHorizontal: 16,
paddingTop: Platform.OS === 'android' ? ANDROID_STATUSBAR_HEIGHT + 8 : 8,
// Center header on very wide screens
alignSelf: 'center',
maxWidth: 1400,
width: '100%',
},
backButton: {
flexDirection: 'row',
@ -103,10 +112,18 @@ const createStyles = (colors: any) => StyleSheet.create({
paddingHorizontal: 16,
paddingBottom: 16,
paddingTop: 8,
// Center title on very wide screens
alignSelf: 'center',
maxWidth: 1400,
width: '100%',
},
list: {
padding: SPACING.lg,
paddingTop: SPACING.sm,
// Center content on very wide screens
alignSelf: 'center',
maxWidth: 1400, // Prevent content from being too wide on large screens
width: '100%',
},
item: {
marginBottom: SPACING.lg,
@ -162,6 +179,10 @@ const createStyles = (colors: any) => StyleSheet.create({
justifyContent: 'center',
alignItems: 'center',
padding: SPACING.xl,
// Center content on very wide screens
alignSelf: 'center',
maxWidth: 600, // Narrower max width for centered content
width: '100%',
},
emptyText: {
color: colors.white,
@ -195,12 +216,31 @@ const CatalogScreen: React.FC<CatalogScreenProps> = ({ route, navigation }) => {
const [error, setError] = useState<string | null>(null);
const [dataSource, setDataSource] = useState<DataSource>(DataSource.STREMIO_ADDONS);
const [actualCatalogName, setActualCatalogName] = useState<string | null>(null);
const [screenData, setScreenData] = useState(() => {
const { width } = Dimensions.get('window');
return {
width,
...calculateCatalogLayout(width)
};
});
const { currentTheme } = useTheme();
const colors = currentTheme.colors;
const styles = createStyles(colors);
const isDarkMode = true;
const isInitialRender = React.useRef(true);
// Handle screen dimension changes
useEffect(() => {
const subscription = Dimensions.addEventListener('change', ({ window }) => {
setScreenData({
width: window.width,
...calculateCatalogLayout(window.width)
});
});
return () => subscription?.remove();
}, []);
const { getCustomName, isLoadingCustomNames } = useCustomCatalogNames();
// Create display name with proper type suffix
@ -504,8 +544,8 @@ const CatalogScreen: React.FC<CatalogScreenProps> = ({ route, navigation }) => {
const renderItem = useCallback(({ item, index }: { item: Meta; index: number }) => {
// Calculate if this is the last item in a row
const isLastInRow = (index + 1) % NUM_COLUMNS === 0;
// For 2-column layout, ensure proper spacing
const isLastInRow = (index + 1) % screenData.numColumns === 0;
// For proper spacing
const rightMargin = isLastInRow ? 0 : SPACING.sm;
return (
@ -514,8 +554,7 @@ const CatalogScreen: React.FC<CatalogScreenProps> = ({ route, navigation }) => {
styles.item,
{
marginRight: rightMargin,
// For 2 columns, ensure items fill the available space properly
width: NUM_COLUMNS === 2 ? ITEM_WIDTH : ITEM_WIDTH
width: screenData.itemWidth
}
]}
onPress={() => navigation.navigate('Metadata', { id: item.id, type: item.type, addonId })}
@ -542,7 +581,7 @@ const CatalogScreen: React.FC<CatalogScreenProps> = ({ route, navigation }) => {
</View>
</TouchableOpacity>
);
}, [navigation, styles, NUM_COLUMNS, ITEM_WIDTH]);
}, [navigation, styles, screenData.numColumns, screenData.itemWidth]);
const renderEmptyState = () => (
<View style={styles.centered}>
@ -640,8 +679,8 @@ const CatalogScreen: React.FC<CatalogScreenProps> = ({ route, navigation }) => {
data={items}
renderItem={renderItem}
keyExtractor={(item) => `${item.id}-${item.type}`}
numColumns={NUM_COLUMNS}
key={NUM_COLUMNS}
numColumns={screenData.numColumns}
key={screenData.numColumns}
refreshControl={
<RefreshControl
refreshing={refreshing}
@ -667,4 +706,4 @@ const CatalogScreen: React.FC<CatalogScreenProps> = ({ route, navigation }) => {
);
};
export default CatalogScreen;
export default CatalogScreen;

View file

@ -29,6 +29,7 @@ import { useTheme } from '../contexts/ThemeContext';
import { Stream } from '../types/metadata';
import { tmdbService } from '../services/tmdbService';
import { stremioService } from '../services/stremioService';
import { localScraperService } from '../services/localScraperService';
import { VideoPlayerService } from '../services/videoPlayerService';
import { useSettings } from '../hooks/useSettings';
import QualityBadge from '../components/metadata/QualityBadge';
@ -365,7 +366,12 @@ export const StreamsScreen = () => {
const checkProviders = async () => {
// Check for Stremio addons
const hasStremioProviders = await stremioService.hasStreamProviders();
const hasProviders = hasStremioProviders;
// Check for local scrapers (only if enabled in settings)
const hasLocalScrapers = settings.enableLocalScrapers && await localScraperService.hasScrapers();
// We have providers if we have either Stremio addons OR enabled local scrapers
const hasProviders = hasStremioProviders || hasLocalScrapers;
if (!isMounted.current) return;
@ -1648,4 +1654,4 @@ const createStyles = (colors: any) => StyleSheet.create({
},
});
export default memo(StreamsScreen);
export default memo(StreamsScreen);