mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
trakt update
This commit is contained in:
parent
22a118c383
commit
3b460ec63f
9 changed files with 127 additions and 57 deletions
|
|
@ -16,7 +16,7 @@
|
|||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
|
||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="@string/expo_runtime_version"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ERROR_RECOVERY_ONLY"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="30000"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://grim-reyna-tapframe-69970143.koyeb.app/api/manifest"/>
|
||||
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode|locale|layoutDirection" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="unspecified">
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@
|
|||
<color name="iconBackground">#020404</color>
|
||||
<color name="colorPrimary">#023c69</color>
|
||||
<color name="colorPrimaryDark">#020404</color>
|
||||
<color name="activityBackground">#020404</color>
|
||||
</resources>
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">#020404</item>
|
||||
<item name="android:windowBackground">@color/activityBackground</item>
|
||||
</style>
|
||||
<style name="ResetEditText" parent="@android:style/Widget.EditText">
|
||||
<item name="android:padding">0dp</item>
|
||||
|
|
|
|||
1
app.json
1
app.json
|
|
@ -4,6 +4,7 @@
|
|||
"slug": "nuvio",
|
||||
"version": "0.6.0-beta.11",
|
||||
"orientation": "default",
|
||||
"backgroundColor": "#020404",
|
||||
"icon": "./assets/ios/AppIcon.appiconset/Icon-App-60x60@3x.png",
|
||||
"userInterfaceStyle": "dark",
|
||||
"scheme": "stremioexpo",
|
||||
|
|
|
|||
|
|
@ -3,29 +3,42 @@ import { View, StyleSheet, Animated, Easing } from 'react-native';
|
|||
import TraktIcon from '../../../assets/rating-icons/trakt.svg';
|
||||
|
||||
export const TraktLoadingSpinner = () => {
|
||||
const spinValue = useRef(new Animated.Value(0)).current;
|
||||
const pulseValue = useRef(new Animated.Value(0)).current;
|
||||
|
||||
useEffect(() => {
|
||||
const spin = Animated.loop(
|
||||
Animated.timing(spinValue, {
|
||||
const pulse = Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(pulseValue, {
|
||||
toValue: 1,
|
||||
duration: 1500,
|
||||
easing: Easing.linear,
|
||||
duration: 900,
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(pulseValue, {
|
||||
toValue: 0,
|
||||
duration: 900,
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
useNativeDriver: true,
|
||||
})
|
||||
])
|
||||
);
|
||||
spin.start();
|
||||
return () => spin.stop();
|
||||
}, [spinValue]);
|
||||
pulse.start();
|
||||
return () => pulse.stop();
|
||||
}, [pulseValue]);
|
||||
|
||||
const rotation = spinValue.interpolate({
|
||||
const opacity = pulseValue.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['0deg', '360deg'],
|
||||
outputRange: [0.65, 1],
|
||||
});
|
||||
|
||||
const scale = pulseValue.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0.95, 1.05],
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Animated.View style={{ transform: [{ rotate: rotation }] }}>
|
||||
<Animated.View style={{ opacity, transform: [{ scale }] }}>
|
||||
<TraktIcon width={80} height={80} />
|
||||
</Animated.View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -326,6 +326,17 @@ const TraktSettingsScreen: React.FC = () => {
|
|||
]}>
|
||||
Sync Settings
|
||||
</Text>
|
||||
<View style={[
|
||||
styles.infoBox,
|
||||
{ backgroundColor: isDarkMode ? currentTheme.colors.elevation1 : '#F5F7FB', borderColor: isDarkMode ? 'rgba(255,255,255,0.06)' : '#E3E8F0' }
|
||||
]}>
|
||||
<Text style={[
|
||||
styles.infoText,
|
||||
{ color: isDarkMode ? currentTheme.colors.mediumEmphasis : currentTheme.colors.textMutedDark }
|
||||
]}>
|
||||
When connected to Trakt, Continue Watching is sourced from Trakt. Account sync for watch progress is disabled to avoid conflicts.
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.settingItem}>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
|
|
@ -564,6 +575,16 @@ const styles = StyleSheet.create({
|
|||
settingDescription: {
|
||||
fontSize: 14,
|
||||
},
|
||||
infoBox: {
|
||||
padding: 12,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
marginBottom: 16,
|
||||
},
|
||||
infoText: {
|
||||
fontSize: 13,
|
||||
lineHeight: 18,
|
||||
},
|
||||
});
|
||||
|
||||
export default TraktSettingsScreen;
|
||||
|
|
@ -7,6 +7,7 @@ import { catalogService, StreamingContent } from './catalogService';
|
|||
// import localScraperService from './localScraperService';
|
||||
import { settingsEmitter } from '../hooks/useSettings';
|
||||
import { logger } from '../utils/logger';
|
||||
import { traktService } from './traktService';
|
||||
|
||||
type WatchProgressRow = {
|
||||
user_id: string;
|
||||
|
|
@ -81,6 +82,7 @@ class SyncService {
|
|||
const user = await accountService.getCurrentUser();
|
||||
if (!user) return;
|
||||
const userId = user.id;
|
||||
const traktActive = await traktService.isAuthenticated();
|
||||
|
||||
const addChannel = (table: string, handler: (payload: any) => void) => {
|
||||
const channel = supabase
|
||||
|
|
@ -91,6 +93,8 @@ class SyncService {
|
|||
logger.log(`[Sync] Realtime subscribed: ${table}`);
|
||||
};
|
||||
|
||||
// Watch progress realtime is disabled when Trakt is active
|
||||
if (!traktActive) {
|
||||
// Watch progress: apply granular updates (ignore self-caused pushes via suppressPush)
|
||||
addChannel('watch_progress', async (payload) => {
|
||||
try {
|
||||
|
|
@ -129,6 +133,9 @@ class SyncService {
|
|||
this.suppressPush = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.log('[Sync] Trakt active → skipping watch_progress realtime subscription');
|
||||
}
|
||||
|
||||
const debouncedPull = (payload?: any) => {
|
||||
if (payload?.table) logger.log(`[Sync][rt] change on ${payload.table} → debounced fullPull`);
|
||||
|
|
@ -352,9 +359,10 @@ class SyncService {
|
|||
const user = await accountService.getCurrentUser();
|
||||
if (!user) return;
|
||||
const userId = user.id;
|
||||
const traktActive = await traktService.isAuthenticated();
|
||||
|
||||
await Promise.allSettled([
|
||||
(async () => {
|
||||
(!traktActive ? (async () => {
|
||||
logger.log('[Sync] pull watch_progress');
|
||||
const { data: wp } = await supabase
|
||||
.from('watch_progress')
|
||||
|
|
@ -397,7 +405,7 @@ class SyncService {
|
|||
}
|
||||
} catch {}
|
||||
}
|
||||
})(),
|
||||
})() : Promise.resolve()),
|
||||
(async () => {
|
||||
logger.log('[Sync] pull user_settings');
|
||||
const { data: us } = await supabase
|
||||
|
|
@ -673,6 +681,13 @@ class SyncService {
|
|||
async pushWatchProgress(): Promise<void> {
|
||||
const user = await accountService.getCurrentUser();
|
||||
if (!user) return;
|
||||
// When Trakt is authenticated, disable account push for continue watching
|
||||
try {
|
||||
if (await traktService.isAuthenticated()) {
|
||||
logger.log('[Sync] Trakt active → skipping push watch_progress');
|
||||
return;
|
||||
}
|
||||
} catch {}
|
||||
const userId = user.id;
|
||||
const unsynced = await storageService.getUnsyncedProgress();
|
||||
logger.log(`[Sync] push watch_progress rows=${unsynced.length}`);
|
||||
|
|
@ -746,6 +761,13 @@ class SyncService {
|
|||
private async softDeleteWatchProgress(type: string, id: string, episodeId?: string): Promise<void> {
|
||||
const user = await accountService.getCurrentUser();
|
||||
if (!user) return;
|
||||
// When Trakt is authenticated, do not propagate deletes to account server for watch progress
|
||||
try {
|
||||
if (await traktService.isAuthenticated()) {
|
||||
logger.log('[Sync] Trakt active → skipping softDelete watch_progress');
|
||||
return;
|
||||
}
|
||||
} catch {}
|
||||
try {
|
||||
const { error } = await supabase
|
||||
.from('watch_progress')
|
||||
|
|
|
|||
1
src/types/svg.d.ts
vendored
1
src/types/svg.d.ts
vendored
|
|
@ -1,3 +1,4 @@
|
|||
import * as React from 'react';
|
||||
declare module '*.svg' {
|
||||
import { SvgProps } from 'react-native-svg';
|
||||
const content: React.FC<SvgProps>;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,16 @@
|
|||
"jsx": "react-jsx",
|
||||
"esModuleInterop": true,
|
||||
"target": "es2017",
|
||||
"downlevelIteration": true
|
||||
}
|
||||
"downlevelIteration": true,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./src/types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"App.tsx",
|
||||
"index.ts",
|
||||
"assets/**/*.svg"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue