mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
ui changes
This commit is contained in:
parent
426e936740
commit
daafdeedc2
4 changed files with 73 additions and 10 deletions
|
|
@ -57,15 +57,62 @@ const STATUS_BAR_HEIGHT = StatusBar.currentHeight || 0;
|
|||
const HERO_HEIGHT = height * 0.85;
|
||||
|
||||
// Animated Pagination Dot Component
|
||||
const PaginationDot: React.FC<{ isActive: boolean; onPress: () => void }> = React.memo(
|
||||
({ isActive, onPress }) => {
|
||||
const PaginationDot: React.FC<{
|
||||
isActive: boolean;
|
||||
isNext: boolean;
|
||||
dragProgress: SharedValue<number>;
|
||||
onPress: () => void;
|
||||
}> = React.memo(
|
||||
({ isActive, isNext, dragProgress, onPress }) => {
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
// Base values
|
||||
const activeWidth = 32;
|
||||
const inactiveWidth = 8;
|
||||
const activeOpacity = 0.9;
|
||||
const inactiveOpacity = 0.3;
|
||||
|
||||
// Calculate target width and opacity based on state
|
||||
let targetWidth = isActive ? activeWidth : inactiveWidth;
|
||||
let targetOpacity = isActive ? activeOpacity : inactiveOpacity;
|
||||
|
||||
// If this is the next dot during drag, interpolate between inactive and active
|
||||
if (isNext && dragProgress.value > 0) {
|
||||
targetWidth = interpolate(
|
||||
dragProgress.value,
|
||||
[0, 1],
|
||||
[inactiveWidth, activeWidth],
|
||||
Extrapolation.CLAMP
|
||||
);
|
||||
targetOpacity = interpolate(
|
||||
dragProgress.value,
|
||||
[0, 1],
|
||||
[inactiveOpacity, activeOpacity],
|
||||
Extrapolation.CLAMP
|
||||
);
|
||||
}
|
||||
|
||||
// If this is the current active dot during drag, interpolate from active to inactive
|
||||
if (isActive && dragProgress.value > 0) {
|
||||
targetWidth = interpolate(
|
||||
dragProgress.value,
|
||||
[0, 1],
|
||||
[activeWidth, inactiveWidth],
|
||||
Extrapolation.CLAMP
|
||||
);
|
||||
targetOpacity = interpolate(
|
||||
dragProgress.value,
|
||||
[0, 1],
|
||||
[activeOpacity, inactiveOpacity],
|
||||
Extrapolation.CLAMP
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
width: withTiming(isActive ? 32 : 8, {
|
||||
width: withTiming(targetWidth, {
|
||||
duration: 300,
|
||||
easing: Easing.out(Easing.cubic),
|
||||
}),
|
||||
opacity: withTiming(isActive ? 0.9 : 0.3, {
|
||||
opacity: withTiming(targetOpacity, {
|
||||
duration: 300,
|
||||
easing: Easing.out(Easing.cubic),
|
||||
}),
|
||||
|
|
@ -890,6 +937,8 @@ const AppleTVHero: React.FC<AppleTVHeroProps> = ({
|
|||
<PaginationDot
|
||||
key={index}
|
||||
isActive={index === currentIndex}
|
||||
isNext={index === nextIndex && nextIndex !== currentIndex}
|
||||
dragProgress={dragProgress}
|
||||
onPress={() => handleDotPress(index)}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ import { logger } from '../../utils/logger';
|
|||
import { TMDBService } from '../../services/tmdbService';
|
||||
import TrailerService from '../../services/trailerService';
|
||||
import TrailerPlayer from '../video/TrailerPlayer';
|
||||
import { HERO_HEIGHT, SCREEN_WIDTH as width, IS_TABLET as isTablet } from '../../constants/dimensions';
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
const isTablet = width >= 768;
|
||||
const { height } = Dimensions.get('window');
|
||||
|
||||
// Ultra-optimized animation constants
|
||||
const SCALE_FACTOR = 1.02;
|
||||
|
|
@ -1540,7 +1540,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
|||
buttonsTranslateY.value = 0;
|
||||
logoOpacity.value = 1;
|
||||
heroOpacity.value = 1;
|
||||
heroHeight.value = height * 0.6;
|
||||
heroHeight.value = HERO_HEIGHT;
|
||||
} catch (error) {
|
||||
logger.error('HeroSection', 'Error cleaning up animation values:', error);
|
||||
}
|
||||
|
|
|
|||
13
src/constants/dimensions.ts
Normal file
13
src/constants/dimensions.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Dimensions } from 'react-native';
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
// Hero section height - 85% of screen height (matching Apple TV style)
|
||||
export const HERO_HEIGHT = height * 0.70;
|
||||
|
||||
// Screen dimensions
|
||||
export const SCREEN_WIDTH = width;
|
||||
export const SCREEN_HEIGHT = height;
|
||||
|
||||
// Tablet detection
|
||||
export const IS_TABLET = width >= 768;
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
runOnUI,
|
||||
cancelAnimation,
|
||||
} from 'react-native-reanimated';
|
||||
import { HERO_HEIGHT } from '../constants/dimensions';
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
|
|
@ -40,7 +41,7 @@ export const useMetadataAnimations = (safeAreaTop: number, watchProgress: any) =
|
|||
// Combined hero animations
|
||||
const heroOpacity = useSharedValue(1);
|
||||
const heroScale = useSharedValue(1); // Start at 1 for Android compatibility
|
||||
const heroHeightValue = useSharedValue(height * 0.55);
|
||||
const heroHeightValue = useSharedValue(HERO_HEIGHT);
|
||||
|
||||
// Combined UI element animations
|
||||
const uiElementsOpacity = useSharedValue(1);
|
||||
|
|
@ -154,8 +155,8 @@ export const useMetadataAnimations = (safeAreaTop: number, watchProgress: any) =
|
|||
const rawScrollY = event.contentOffset.y;
|
||||
scrollY.value = rawScrollY;
|
||||
|
||||
// Single calculation for header threshold
|
||||
const threshold = height * 0.4 - safeAreaTop;
|
||||
// Single calculation for header threshold - show only when hero is fully scrolled
|
||||
const threshold = HERO_HEIGHT - safeAreaTop;
|
||||
const progress = rawScrollY > threshold ? 1 : 0;
|
||||
|
||||
// Use single progress value for all header animations
|
||||
|
|
|
|||
Loading…
Reference in a new issue