fixed videoplayer control for android

This commit is contained in:
tapframe 2025-09-07 19:04:26 +05:30
parent b1494e8a1d
commit 837e3735a2
5 changed files with 186 additions and 16 deletions

View file

@ -40,10 +40,10 @@ Sentry.init({
// For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/
sendDefaultPii: true,
// Configure Session Replay
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1,
integrations: [Sentry.mobileReplayIntegration(), Sentry.feedbackIntegration()],
// Configure Session Replay (disabled for performance)
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: 0,
integrations: [Sentry.feedbackIntegration()],
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
// spotlight: __DEV__,

View file

@ -33,7 +33,8 @@
"UIFileSharingEnabled": true
},
"bundleIdentifier": "com.nuvio.app",
"associatedDomains": []
"associatedDomains": [],
"jsEngine": "hermes"
},
"android": {
"adaptiveIcon": {
@ -52,7 +53,8 @@
"armeabi-v7a",
"x86",
"x86_64"
]
],
"jsEngine": "hermes"
},
"extra": {

View file

@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
import { View, TouchableOpacity, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, Image, StyleSheet, Modal } from 'react-native';
import { View, TouchableOpacity, TouchableWithoutFeedback, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, Image, StyleSheet, Modal } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Video, { VideoRef, SelectedTrack, SelectedTrackType, BufferingStrategyType } from 'react-native-video';
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
@ -435,6 +435,17 @@ const AndroidVideoPlayer: React.FC = () => {
// Removed the 100ms delay
backgroundFadeAnim.setValue(0);
});
// Fallback: ensure animation completes even if something goes wrong
setTimeout(() => {
if (!isOpeningAnimationComplete) {
logger.warn('[AndroidVideoPlayer] Opening animation fallback triggered');
setIsOpeningAnimationComplete(true);
openingScaleAnim.setValue(1);
openingFadeAnim.setValue(1);
backgroundFadeAnim.setValue(0);
}
}, 1000); // 1 second fallback
};
useEffect(() => {
@ -2035,6 +2046,14 @@ const AndroidVideoPlayer: React.FC = () => {
</View>
</PinchGestureHandler>
{/* Tap-capture overlay above the Video to toggle controls (Android fix) */}
<TouchableWithoutFeedback onPress={toggleControls}>
<View
style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}
pointerEvents={showControls ? 'none' : 'auto'}
/>
</TouchableWithoutFeedback>
<PlayerControls
showControls={showControls}
fadeAnim={fadeAnim}

View file

@ -1108,7 +1108,7 @@ const PluginsScreen: React.FC = () => {
};
const handleUseDefaultRepo = () => {
const defaultUrl = 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/master';
const defaultUrl = 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/main';
setRepositoryUrl(defaultUrl);
};
@ -1178,18 +1178,36 @@ const PluginsScreen: React.FC = () => {
{/* Quick Setup for New Users */}
{!hasRepository && (
<View style={styles.quickSetupContainer}>
<Text style={styles.quickSetupTitle}>Quick Setup</Text>
<Text style={styles.quickSetupTitle}>🚀 Quick Start with Official Plugins</Text>
<Text style={styles.quickSetupText}>
Get started with plugins in 3 easy steps! Enable local scrapers, set up a repository, and start streaming.
Get instant access to 9+ premium streaming scrapers from Tapframe's official repository. Enable local scrapers and start streaming movies and TV shows immediately.
</Text>
<TouchableOpacity
style={styles.quickSetupButton}
onPress={() => {
setExpandedSections(prev => ({ ...prev, repository: true }));
setShowHelpModal(true);
onPress={async () => {
try {
setIsLoading(true);
// Add the official tapframe repository
const tapframeInfo = localScraperService.getTapframeRepositoryInfo();
const repoId = await localScraperService.addRepository(tapframeInfo);
// Switch to the new repository and refresh it
await localScraperService.setCurrentRepository(repoId);
await loadRepositories();
await loadScrapers();
Alert.alert('Success', 'Official repository added! Enable local scrapers above to start using plugins.');
} catch (error) {
logger.error('[PluginsScreen] Failed to add tapframe repository:', error);
Alert.alert('Error', 'Failed to add official repository');
} finally {
setIsLoading(false);
}
}}
>
<Text style={styles.quickSetupButtonText}>Get Started</Text>
<Text style={styles.quickSetupButtonText}>
{isLoading ? 'Adding Repository...' : 'Add Official Repository'}
</Text>
</TouchableOpacity>
</View>
)}
@ -1309,6 +1327,31 @@ const PluginsScreen: React.FC = () => {
</View>
)}
{/* Add Official Repository Button */}
{!localScraperService.hasTapframeRepository() && (
<TouchableOpacity
style={[styles.defaultRepoButton]}
onPress={async () => {
try {
setIsLoading(true);
const tapframeInfo = localScraperService.getTapframeRepositoryInfo();
const repoId = await localScraperService.addRepository(tapframeInfo);
await loadRepositories();
Alert.alert('Success', 'Official repository added successfully!');
} catch (error) {
logger.error('[PluginsScreen] Failed to add tapframe repository:', error);
Alert.alert('Error', 'Failed to add official repository');
} finally {
setIsLoading(false);
}
}}
disabled={!settings.enableLocalScrapers || isLoading}
>
<Ionicons name="add-circle" size={16} color={colors.primary} />
<Text style={styles.defaultRepoButtonText}>Add Official Repository</Text>
</TouchableOpacity>
)}
{/* Add Repository Button */}
<TouchableOpacity
style={[styles.button, styles.primaryButton, { marginTop: 16 }]}

View file

@ -93,15 +93,17 @@ class LocalScraperService {
private async initialize(): Promise<void> {
if (this.initialized) return;
try {
// Ensure tapframe repository is available
await this.ensureTapframeRepository();
// Load repositories
const repositoriesData = await AsyncStorage.getItem(this.REPOSITORIES_KEY);
if (repositoriesData) {
const repos = JSON.parse(repositoriesData);
this.repositories = new Map(Object.entries(repos));
} else {
// Migrate from old single repository format
// Migrate from old single repository format or create default tapframe repository
const storedRepoUrl = await AsyncStorage.getItem(this.REPOSITORY_KEY);
if (storedRepoUrl) {
const defaultRepo: RepositoryInfo = {
@ -116,9 +118,26 @@ class LocalScraperService {
this.repositories.set('default', defaultRepo);
this.currentRepositoryId = 'default';
await this.saveRepositories();
} else {
// Create default tapframe repository for new users
const tapframeRepo: RepositoryInfo = {
id: 'tapframe-nuvio-providers',
name: 'Tapframe\'s Repo',
url: 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/main',
description: 'Official Nuvio streaming plugins repository by Tapframe',
isDefault: true,
enabled: true,
lastUpdated: Date.now()
};
this.repositories.set('tapframe-nuvio-providers', tapframeRepo);
this.currentRepositoryId = 'tapframe-nuvio-providers';
await this.saveRepositories();
}
}
// Ensure tapframe repository is available for existing users too
await this.ensureTapframeRepository();
// Load current repository
const currentRepoId = await AsyncStorage.getItem('current-repository-id');
if (currentRepoId && this.repositories.has(currentRepoId)) {
@ -233,6 +252,93 @@ class LocalScraperService {
}
}
/**
* Ensure the tapframe repository is available for all users
*/
public async ensureTapframeRepository(): Promise<void> {
const tapframeRepoId = 'tapframe-nuvio-providers';
const tapframeRepoUrl = 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/main';
// Check if tapframe repository already exists
if (this.repositories.has(tapframeRepoId)) {
const existingRepo = this.repositories.get(tapframeRepoId)!;
// Update URL if it changed
if (existingRepo.url !== tapframeRepoUrl) {
existingRepo.url = tapframeRepoUrl;
existingRepo.name = 'Tapframe\'s Repo';
existingRepo.description = 'Official Nuvio streaming plugins repository by Tapframe';
await this.saveRepositories();
}
return;
}
// Check if any repository with the same URL already exists
for (const [id, repo] of this.repositories) {
if (repo.url === tapframeRepoUrl) {
// Update existing repository to use the tapframe ID and info
repo.id = tapframeRepoId;
repo.name = 'Tapframe\'s Repo';
repo.description = 'Official Nuvio streaming plugins repository by Tapframe';
repo.isDefault = true;
this.repositories.delete(id);
this.repositories.set(tapframeRepoId, repo);
await this.saveRepositories();
return;
}
}
// Create new tapframe repository
const tapframeRepo: RepositoryInfo = {
id: tapframeRepoId,
name: 'Tapframe\'s Repo',
url: tapframeRepoUrl,
description: 'Official Nuvio streaming plugins repository by Tapframe',
isDefault: true,
enabled: true,
lastUpdated: Date.now()
};
this.repositories.set(tapframeRepoId, tapframeRepo);
await this.saveRepositories();
}
/**
* Get the official tapframe repository info
*/
public getTapframeRepositoryInfo(): RepositoryInfo {
return {
id: 'tapframe-nuvio-providers',
name: 'Tapframe\'s Repo',
url: 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/main',
description: 'Official Nuvio streaming plugins repository by Tapframe',
isDefault: true,
enabled: true,
lastUpdated: Date.now()
};
}
/**
* Check if the tapframe repository is available
*/
public hasTapframeRepository(): boolean {
const tapframeRepoId = 'tapframe-nuvio-providers';
const tapframeRepoUrl = 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/main';
// Check if tapframe repository exists by ID
if (this.repositories.has(tapframeRepoId)) {
return true;
}
// Check if any repository has the tapframe URL
for (const repo of this.repositories.values()) {
if (repo.url === tapframeRepoUrl) {
return true;
}
}
return false;
}
// Set repository URL
async setRepositoryUrl(url: string): Promise<void> {
this.repositoryUrl = url;