Pluginscreen UI changes

This commit is contained in:
tapframe 2025-09-30 01:39:00 +05:30
parent 9ae0a7010c
commit bbbc22f30f
5 changed files with 87 additions and 35 deletions

View file

@ -57,6 +57,8 @@ export interface AppSettings {
excludedQualities: string[]; // Array of quality strings to exclude (e.g., ['2160p', '4K', '1080p', '720p']) excludedQualities: string[]; // Array of quality strings to exclude (e.g., ['2160p', '4K', '1080p', '720p'])
// Playback behavior // Playback behavior
alwaysResume: boolean; // If true, resume automatically without prompt when progress < 85% alwaysResume: boolean; // If true, resume automatically without prompt when progress < 85%
// Downloads
enableDownloads: boolean; // Show Downloads tab and enable saving streams
// Theme settings // Theme settings
themeId: string; themeId: string;
customThemes: CustomThemeDef[]; customThemes: CustomThemeDef[];
@ -105,6 +107,8 @@ export const DEFAULT_SETTINGS: AppSettings = {
excludedQualities: [], // No qualities excluded by default excludedQualities: [], // No qualities excluded by default
// Playback behavior defaults // Playback behavior defaults
alwaysResume: true, alwaysResume: true,
// Downloads
enableDownloads: false,
// Theme defaults // Theme defaults
themeId: 'default', themeId: 'default',
customThemes: [], customThemes: [],

View file

@ -458,6 +458,9 @@ const WrappedScreen: React.FC<{Screen: React.ComponentType<any>}> = ({ Screen })
// Tab Navigator // Tab Navigator
const MainTabs = () => { const MainTabs = () => {
const { currentTheme } = useTheme(); const { currentTheme } = useTheme();
const { settings } = require('../hooks/useSettings');
const { useSettings: useSettingsHook } = require('../hooks/useSettings');
const { settings: appSettings } = useSettingsHook();
const [hasUpdateBadge, setHasUpdateBadge] = React.useState(false); const [hasUpdateBadge, setHasUpdateBadge] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
if (Platform.OS !== 'android') return; if (Platform.OS !== 'android') return;
@ -829,16 +832,18 @@ const MainTabs = () => {
), ),
}} }}
/> />
<Tab.Screen {appSettings?.enableDownloads !== false && (
name="Downloads" <Tab.Screen
component={DownloadsScreen} name="Downloads"
options={{ component={DownloadsScreen}
tabBarLabel: 'Downloads', options={{
tabBarIcon: ({ color, size, focused }) => ( tabBarLabel: 'Downloads',
<MaterialCommunityIcons name={focused ? 'download' : 'download-outline'} size={size} color={color} /> tabBarIcon: ({ color, size, focused }) => (
), <MaterialCommunityIcons name={focused ? 'download' : 'download-outline'} size={size} color={color} />
}} ),
/> }}
/>
)}
<Tab.Screen <Tab.Screen
name="Settings" name="Settings"
component={SettingsScreen} component={SettingsScreen}

View file

@ -33,7 +33,7 @@ const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
const createStyles = (colors: any) => StyleSheet.create({ const createStyles = (colors: any) => StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: colors.background, backgroundColor: colors.darkBackground,
}, },
header: { header: {
flexDirection: 'row', flexDirection: 'row',
@ -63,7 +63,7 @@ const createStyles = (colors: any) => StyleSheet.create({
headerTitle: { headerTitle: {
fontSize: 34, fontSize: 34,
fontWeight: 'bold', fontWeight: 'bold',
color: colors.white, color: colors.text,
paddingHorizontal: 16, paddingHorizontal: 16,
marginBottom: 24, marginBottom: 24,
}, },
@ -71,7 +71,7 @@ const createStyles = (colors: any) => StyleSheet.create({
flex: 1, flex: 1,
}, },
section: { section: {
backgroundColor: colors.darkBackground, backgroundColor: colors.elevation1,
marginBottom: 16, marginBottom: 16,
borderRadius: 12, borderRadius: 12,
padding: 16, padding: 16,
@ -852,6 +852,7 @@ const PluginsScreen: React.FC = () => {
const [showboxUiToken, setShowboxUiToken] = useState<string>(''); const [showboxUiToken, setShowboxUiToken] = useState<string>('');
const [showboxSavedToken, setShowboxSavedToken] = useState<string>(''); const [showboxSavedToken, setShowboxSavedToken] = useState<string>('');
const [showboxScraperId, setShowboxScraperId] = useState<string | null>(null); const [showboxScraperId, setShowboxScraperId] = useState<string | null>(null);
const [showboxTokenVisible, setShowboxTokenVisible] = useState<boolean>(false);
// Multiple repositories state // Multiple repositories state
const [repositories, setRepositories] = useState<RepositoryInfo[]>([]); const [repositories, setRepositories] = useState<RepositoryInfo[]>([]);
@ -1084,10 +1085,12 @@ const PluginsScreen: React.FC = () => {
const s = await localScraperService.getScraperSettings(sb.id); const s = await localScraperService.getScraperSettings(sb.id);
setShowboxUiToken(s.uiToken || ''); setShowboxUiToken(s.uiToken || '');
setShowboxSavedToken(s.uiToken || ''); setShowboxSavedToken(s.uiToken || '');
setShowboxTokenVisible(false);
} else { } else {
setShowboxScraperId(null); setShowboxScraperId(null);
setShowboxUiToken(''); setShowboxUiToken('');
setShowboxSavedToken(''); setShowboxSavedToken('');
setShowboxTokenVisible(false);
} }
} catch (error) { } catch (error) {
logger.error('[ScraperSettings] Failed to load scrapers:', error); logger.error('[ScraperSettings] Failed to load scrapers:', error);
@ -1630,17 +1633,25 @@ const PluginsScreen: React.FC = () => {
{showboxScraperId && scraper.id === showboxScraperId && settings.enableLocalScrapers && ( {showboxScraperId && scraper.id === showboxScraperId && settings.enableLocalScrapers && (
<View style={{ marginTop: 16, paddingTop: 16, borderTopWidth: 1, borderTopColor: colors.elevation3 }}> <View style={{ marginTop: 16, paddingTop: 16, borderTopWidth: 1, borderTopColor: colors.elevation3 }}>
<Text style={[styles.settingTitle, { marginBottom: 8 }]}>ShowBox UI Token</Text> <Text style={[styles.settingTitle, { marginBottom: 8 }]}>ShowBox UI Token</Text>
<TextInput <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 12 }}>
style={[styles.textInput, { marginBottom: 12 }]} <TextInput
value={showboxUiToken} style={[styles.textInput, { flex: 1, marginBottom: 0 }]}
onChangeText={setShowboxUiToken} value={showboxUiToken}
placeholder="Paste your ShowBox UI token" onChangeText={setShowboxUiToken}
placeholderTextColor={colors.mediumGray} placeholder="Paste your ShowBox UI token"
autoCapitalize="none" placeholderTextColor={colors.mediumGray}
autoCorrect={false} autoCapitalize="none"
multiline={true} autoCorrect={false}
numberOfLines={3} secureTextEntry={showboxSavedToken.length > 0 && !showboxTokenVisible}
/> multiline={false}
numberOfLines={1}
/>
{showboxSavedToken.length > 0 && (
<TouchableOpacity onPress={() => setShowboxTokenVisible(v => !v)} accessibilityRole="button" accessibilityLabel={showboxTokenVisible ? 'Hide token' : 'Show token'} style={{ marginLeft: 10 }}>
<Ionicons name={showboxTokenVisible ? 'eye-off' : 'eye'} size={18} color={colors.primary} />
</TouchableOpacity>
)}
</View>
<View style={styles.buttonRow}> <View style={styles.buttonRow}>
{showboxUiToken !== showboxSavedToken && ( {showboxUiToken !== showboxSavedToken && (
<TouchableOpacity <TouchableOpacity

View file

@ -278,6 +278,8 @@ const SettingsScreen: React.FC = () => {
// Tablet-specific state // Tablet-specific state
const [selectedCategory, setSelectedCategory] = useState('account'); const [selectedCategory, setSelectedCategory] = useState('account');
const [downloadsDevUnlocked, setDownloadsDevUnlocked] = useState(false);
const [versionTapCount, setVersionTapCount] = useState(0);
// States for dynamic content // States for dynamic content
const [addonCount, setAddonCount] = useState<number>(0); const [addonCount, setAddonCount] = useState<number>(0);
@ -613,6 +615,22 @@ const SettingsScreen: React.FC = () => {
)} )}
isTablet={isTablet} isTablet={isTablet}
/> />
{downloadsDevUnlocked && (
<SettingItem
title="Enable Downloads"
description="Show Downloads tab and enable saving streams"
icon="download"
renderControl={() => (
<Switch
value={settings?.enableDownloads ?? true}
onValueChange={(value) => updateSetting('enableDownloads', value)}
trackColor={{ false: 'rgba(255,255,255,0.2)', true: currentTheme.colors.primary }}
thumbColor={settings?.enableDownloads ? '#fff' : '#f4f3f4'}
/>
)}
isTablet={isTablet}
/>
)}
<SettingItem <SettingItem
title="Notifications" title="Notifications"
description="Episode reminders" description="Episode reminders"
@ -646,6 +664,16 @@ const SettingsScreen: React.FC = () => {
title="Version" title="Version"
description={getDisplayedAppVersion()} description={getDisplayedAppVersion()}
icon="info-outline" icon="info-outline"
onPress={() => {
if (downloadsDevUnlocked) return;
const next = versionTapCount + 1;
setVersionTapCount(next);
if (next >= 5) {
setDownloadsDevUnlocked(true);
setVersionTapCount(0);
openAlert('Developer option unlocked', 'Downloads toggle is now visible in Playback settings.');
}
}}
isLast={true} isLast={true}
isTablet={isTablet} isTablet={isTablet}
/> />

View file

@ -221,6 +221,8 @@ const StreamCard = memo(({ stream, onPress, index, isLoading, statusMessage, the
parentPosterUrl?: string | null; parentPosterUrl?: string | null;
providerName?: string; providerName?: string;
}) => { }) => {
const { useSettings } = require('../hooks/useSettings');
const { settings } = useSettings();
const { startDownload } = useDownloads(); const { startDownload } = useDownloads();
// Handle long press to copy stream URL to clipboard // Handle long press to copy stream URL to clipboard
@ -398,17 +400,19 @@ const StreamCard = memo(({ stream, onPress, index, isLoading, statusMessage, the
color={theme.colors.white} color={theme.colors.white}
/> />
</View> </View>
<TouchableOpacity {settings?.enableDownloads !== false && (
style={[styles.streamAction, { marginLeft: 8, backgroundColor: theme.colors.elevation2 }]} <TouchableOpacity
onPress={handleDownload} style={[styles.streamAction, { marginLeft: 8, backgroundColor: theme.colors.elevation2 }]}
activeOpacity={0.7} onPress={handleDownload}
> activeOpacity={0.7}
<MaterialIcons >
name="download" <MaterialIcons
size={20} name="download"
color={theme.colors.highEmphasis} size={20}
/> color={theme.colors.highEmphasis}
</TouchableOpacity> />
</TouchableOpacity>
)}
</TouchableOpacity> </TouchableOpacity>
); );
}); });