diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx
index c7ddc79..388687e 100644
--- a/src/screens/SettingsScreen.tsx
+++ b/src/screens/SettingsScreen.tsx
@@ -389,6 +389,14 @@ const SettingsScreen: React.FC = () => {
renderControl={() => }
isTablet={isTablet}
/>
+ navigation.navigate('PluginTester')}
+ renderControl={() => }
+ isTablet={isTablet}
+ />
{
-
-
+
+
+
{t('plugin_tester.individual.load_from_url')}
@@ -219,9 +220,9 @@ export const IndividualTester = ({ onSwitchTab }: IndividualTesterProps) => {
-
+
-
+
{t('plugin_tester.individual.plugin_code')}
@@ -245,69 +246,72 @@ export const IndividualTester = ({ onSwitchTab }: IndividualTesterProps) => {
autoCapitalize="none"
autoCorrect={false}
/>
-
-
- {/* Test parameters on large screen */}
-
-
- {t('plugin_tester.individual.test_parameters')}
-
+
-
- setMediaType('movie')}
- >
-
- {t('plugin_tester.common.movie')}
-
- setMediaType('tv')}
- >
-
- {t('plugin_tester.common.tv')}
-
-
-
-
-
- {t('plugin_tester.common.tmdb_id')}
-
+ {/* Sticky footer on large screens (match mobile behavior) */}
+
+
+
+ {t('plugin_tester.individual.test_parameters')}
+
- {mediaType === 'tv' && (
- <>
-
- {t('plugin_tester.common.season')}
-
-
-
- {t('plugin_tester.common.episode')}
-
-
- >
- )}
+
+ setMediaType('movie')}
+ >
+
+ {t('plugin_tester.common.movie')}
+
+ setMediaType('tv')}
+ >
+
+ {t('plugin_tester.common.tv')}
+
+
+
+
+
+ {t('plugin_tester.common.tmdb_id')}
+
+
+
+ {mediaType === 'tv' && (
+ <>
+
+ {t('plugin_tester.common.season')}
+
+
+
+ {t('plugin_tester.common.episode')}
+
+
+ >
+ )}
+
@@ -319,7 +323,7 @@ export const IndividualTester = ({ onSwitchTab }: IndividualTesterProps) => {
{isRunning ? t('plugin_tester.common.running') : t('plugin_tester.common.run_test')}
-
+
@@ -580,71 +584,79 @@ export const IndividualTester = ({ onSwitchTab }: IndividualTesterProps) => {
} as any);
};
- const renderResultsTab = () => (
-
- {streams.length === 0 ? (
-
-
- {t('plugin_tester.individual.no_streams')}
-
- ) : (
-
- {streams.length === 1 ? t('plugin_tester.individual.streams_found', { count: streams.length }) : t('plugin_tester.individual.streams_found_plural', { count: streams.length })}
- {t('plugin_tester.individual.tap_play_hint')}
- item.url + index}
- renderItem={({ item: stream }) => (
- playStream(stream)}
- activeOpacity={0.7}
- >
-
-
- {stream.name || stream.title || t('plugin_tester.individual.unnamed_stream')}
- {t('plugin_tester.individual.quality', { quality: stream.quality || 'Unknown' })}
- {stream.description ? {t('plugin_tester.individual.size', { size: stream.description })} : null}
- {t('plugin_tester.individual.url_label', { url: stream.url })}
- {stream.headers && Object.keys(stream.headers).length > 0 && (
- {t('plugin_tester.individual.headers_info', { count: Object.keys(stream.headers).length })}
- )}
-
- playStream(stream)}
- >
-
- {t('plugin_tester.common.play')}
-
-
+ const renderResultsTab = () => {
+ if (streams.length === 0) {
+ return (
+
+
+
+ {t('plugin_tester.individual.no_streams')}
+
+
+ );
+ }
-
- {(() => {
- try {
- return JSON.stringify(stream, null, 2);
- } catch {
- return String(stream);
- }
- })()}
-
+ return (
+ item.url + index}
+ ListHeaderComponent={
+
+ {streams.length === 1 ? t('plugin_tester.individual.streams_found', { count: streams.length }) : t('plugin_tester.individual.streams_found_plural', { count: streams.length })}
+ {t('plugin_tester.individual.tap_play_hint')}
+
+ }
+ renderItem={({ item: stream }) => (
+ playStream(stream)}
+ activeOpacity={0.7}
+ >
+
+
+ {stream.name || stream.title || t('plugin_tester.individual.unnamed_stream')}
+ {t('plugin_tester.individual.quality', { quality: stream.quality || 'Unknown' })}
+ {stream.description ? {t('plugin_tester.individual.size', { size: stream.description })} : null}
+ {t('plugin_tester.individual.url_label', { url: stream.url })}
+ {stream.headers && Object.keys(stream.headers).length > 0 && (
+ {t('plugin_tester.individual.headers_info', { count: Object.keys(stream.headers).length })}
+ )}
+
+ playStream(stream)}
+ >
+
+ {t('plugin_tester.common.play')}
- )}
- />
-
- )}
-
- );
+
+
+
+ {(() => {
+ try {
+ return JSON.stringify(stream, null, 2);
+ } catch {
+ return String(stream);
+ }
+ })()}
+
+
+ )}
+ />
+ );
+ };
const renderFocusedEditor = () => (
{
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={Platform.OS === 'ios' ? 60 : 0}
>
-
-
+
+
+
{t('plugin_tester.repo.title')}
@@ -409,7 +410,7 @@ export const RepoTester = () => {
)}
-
+
{t('plugin_tester.repo.test_parameters')}
@@ -475,7 +476,7 @@ export const RepoTester = () => {
-
+
{t('plugin_tester.repo.providers_title')}
@@ -622,8 +623,9 @@ export const RepoTester = () => {
);
})}
-
-
+
+
+
);
};
diff --git a/src/screens/plugin-tester/styles.ts b/src/screens/plugin-tester/styles.ts
index e026aab..351bb29 100644
--- a/src/screens/plugin-tester/styles.ts
+++ b/src/screens/plugin-tester/styles.ts
@@ -1,7 +1,9 @@
import { StyleSheet, Platform, useWindowDimensions } from 'react-native';
-// Breakpoint for larger screens (tablets, iPads)
-export const LARGE_SCREEN_BREAKPOINT = 768;
+// Breakpoint for the two-column "large screen" layout.
+// 768px wide tablets in portrait are usually too narrow for side-by-side columns,
+// so we enable the large layout only on wider screens (e.g., tablet landscape).
+export const LARGE_SCREEN_BREAKPOINT = 900;
export const useIsLargeScreen = () => {
const { width } = useWindowDimensions();
@@ -16,13 +18,16 @@ export const getPluginTesterStyles = (theme: any, isLargeScreen: boolean = false
// Large screen wrapper for centering content
largeScreenWrapper: {
flex: 1,
- maxWidth: isLargeScreen ? 900 : undefined,
+ // Allow tablet/desktop to use more horizontal space while still
+ // keeping content comfortably contained.
+ maxWidth: isLargeScreen ? 1200 : undefined,
alignSelf: isLargeScreen ? 'center' : undefined,
width: isLargeScreen ? '100%' : undefined,
paddingHorizontal: isLargeScreen ? 24 : 0,
},
// Two-column layout for large screens
twoColumnContainer: {
+ flex: isLargeScreen ? 1 : undefined,
flexDirection: isLargeScreen ? 'row' : 'column',
gap: isLargeScreen ? 16 : 0,
},
@@ -94,7 +99,9 @@ export const getPluginTesterStyles = (theme: any, isLargeScreen: boolean = false
},
content: {
flex: 1,
- paddingHorizontal: 16,
+ // On large screens the wrapper already adds horizontal padding.
+ // Avoid "double padding" that makes columns feel cramped.
+ paddingHorizontal: isLargeScreen ? 0 : 16,
paddingTop: 12,
},
card: {