player UI update

This commit is contained in:
tapframe 2025-11-16 15:46:46 +05:30
parent 09e35d5a0c
commit 34f110f16a
2 changed files with 78 additions and 65 deletions

View file

@ -285,8 +285,12 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
tapToSeek={Platform.OS === 'ios'} tapToSeek={Platform.OS === 'ios'}
/> />
<View style={[styles.timeDisplay, { paddingHorizontal: 14 }]}> <View style={[styles.timeDisplay, { paddingHorizontal: 14 }]}>
<Text style={styles.duration}>{formatTime(currentTime)}</Text> <View style={styles.timeContainer}>
<Text style={styles.duration}>{formatTime(duration)}</Text> <Text style={styles.duration}>{formatTime(currentTime)}</Text>
</View>
<View style={styles.timeContainer}>
<Text style={styles.duration}>{formatTime(duration)}</Text>
</View>
</View> </View>
</View> </View>
@ -368,7 +372,7 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
styles.buttonCircle, styles.buttonCircle,
{ {
opacity: backwardPressAnim, opacity: backwardPressAnim,
width: seekButtonSize * 0.6, // 60% of seek button width: seekButtonSize * 0.6,
height: seekButtonSize * 0.6, height: seekButtonSize * 0.6,
borderRadius: (seekButtonSize * 0.6) / 2, borderRadius: (seekButtonSize * 0.6) / 2,
} }
@ -381,7 +385,7 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
styles.seekNumber, styles.seekNumber,
{ {
fontSize: seekNumberSize, fontSize: seekNumberSize,
marginLeft: 7, // Opposite offset for flipped icon marginLeft: 7,
transform: [{ translateX: backwardSlideAnim }] transform: [{ translateX: backwardSlideAnim }]
} }
]}> ]}>
@ -426,9 +430,9 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
styles.playPressCircle, styles.playPressCircle,
{ {
opacity: playPressAnim, opacity: playPressAnim,
width: playButtonSize * 0.85, // ← 85% of button size width: playButtonSize * 0.85,
height: playButtonSize * 0.85, height: playButtonSize * 0.85,
borderRadius: (playButtonSize * 0.85) / 2, // ← Half of width/height for circle borderRadius: (playButtonSize * 0.85) / 2,
} }
]} /> ]} />
<Animated.View style={{ <Animated.View style={{
@ -466,7 +470,7 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
styles.buttonCircle, styles.buttonCircle,
{ {
opacity: forwardPressAnim, opacity: forwardPressAnim,
width: seekButtonSize * 0.6, // 60% of seek button width: seekButtonSize * 0.6,
height: seekButtonSize * 0.6, height: seekButtonSize * 0.6,
borderRadius: (seekButtonSize * 0.6) / 2, borderRadius: (seekButtonSize * 0.6) / 2,
} }
@ -525,81 +529,56 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
style={styles.bottomGradient} style={styles.bottomGradient}
> >
<View style={styles.bottomControls}> <View style={styles.bottomControls}>
{/* Bottom Buttons Row */} {/* Center Buttons Container with rounded background - wraps all buttons */}
<View style={styles.bottomButtons}> <View style={styles.centerControlsContainer}>
{/* Aspect Ratio Button - uses official resize modes */} {/* Left Side: Aspect Ratio Button */}
<TouchableOpacity style={styles.bottomButton} onPress={cycleAspectRatio}> <TouchableOpacity style={styles.iconButton} onPress={cycleAspectRatio}>
<Ionicons name="resize" size={20} color="white" /> <Ionicons name="expand-outline" size={24} color="white" />
<Text style={[styles.bottomButtonText, { fontSize: 14, textAlign: 'center' }]}>
{currentResizeMode
? (currentResizeMode === 'none'
? 'Original'
: currentResizeMode.charAt(0).toUpperCase() + currentResizeMode.slice(1))
: 'Contain'}
</Text>
</TouchableOpacity> </TouchableOpacity>
{/* Playback Speed Button */} {/* Subtitle Button */}
<TouchableOpacity style={styles.bottomButton} onPress={() => setShowSpeedModal(true)}>
<Ionicons name="speedometer" size={20} color="white" />
<Text style={styles.bottomButtonText}>
Speed {currentPlaybackSpeed}x
</Text>
</TouchableOpacity>
{/* Audio Button - Updated to use ksAudioTracks */}
<TouchableOpacity <TouchableOpacity
style={styles.bottomButton} style={styles.iconButton}
onPress={() => setShowAudioModal(true)}
disabled={ksAudioTracks.length <= 1}
>
<Ionicons name="volume-high" size={20} color={ksAudioTracks.length <= 1 ? 'grey' : 'white'} />
<Text style={[styles.bottomButtonText, ksAudioTracks.length <= 1 && {color: 'grey'}]} numberOfLines={1}>
{(() => {
const trackName = getTrackDisplayName(
ksAudioTracks.find(t => t.id === selectedAudioTrack) || { id: -1, name: 'Default' }
);
// Truncate long audio track names to prevent UI cramping
const maxLength = 12; // Limit to 12 characters
return trackName.length > maxLength ? `${trackName.substring(0, maxLength)}...` : trackName;
})()}
</Text>
</TouchableOpacity>
{/* Subtitle Button - Always available for external subtitle search */}
<TouchableOpacity
style={styles.bottomButton}
onPress={() => setShowSubtitleModal(!isSubtitleModalOpen)} onPress={() => setShowSubtitleModal(!isSubtitleModalOpen)}
> >
<Ionicons name="text" size={20} color="white" /> <Ionicons name="text" size={24} color="white" />
<Text style={styles.bottomButtonText}>
Subtitles
</Text>
</TouchableOpacity> </TouchableOpacity>
{/* Change Source Button */} {/* Change Source Button */}
{setShowSourcesModal && ( {setShowSourcesModal && (
<TouchableOpacity <TouchableOpacity
style={styles.bottomButton} style={styles.iconButton}
onPress={() => setShowSourcesModal(true)} onPress={() => setShowSourcesModal(true)}
> >
<Ionicons name="swap-horizontal" size={20} color="white" /> <Ionicons name="cloud-outline" size={24} color="white" />
<Text style={styles.bottomButtonText}>
Change Source
</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
{/* Episodes Button */} {/* Playback Speed Button */}
<TouchableOpacity style={styles.iconButton} onPress={() => setShowSpeedModal(true)}>
<Ionicons name="speedometer-outline" size={24} color="white" />
</TouchableOpacity>
{/* Audio Button */}
<TouchableOpacity
style={styles.iconButton}
onPress={() => setShowAudioModal(true)}
disabled={ksAudioTracks.length <= 1}
>
<Ionicons
name="musical-notes-outline"
size={24}
color={ksAudioTracks.length <= 1 ? 'grey' : 'white'}
/>
</TouchableOpacity>
{/* Right Side: Episodes Button */}
{setShowEpisodesModal && ( {setShowEpisodesModal && (
<TouchableOpacity <TouchableOpacity
style={styles.bottomButton} style={styles.iconButton}
onPress={() => setShowEpisodesModal(true)} onPress={() => setShowEpisodesModal(true)}
> >
<Ionicons name="list" size={20} color="white" /> <Ionicons name="list" size={24} color="white" />
<Text style={styles.bottomButtonText}>
Episodes
</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
</View> </View>

View file

@ -26,7 +26,7 @@ const qualityTextFont = isTV ? 13 : isLargeTablet ? 12 : isTablet ? 11 : 11;
const controlsGap = isTV ? 56 : isLargeTablet ? 48 : isTablet ? 44 : 40; const controlsGap = isTV ? 56 : isLargeTablet ? 48 : isTablet ? 44 : 40;
const controlsTranslateY = isTV ? -48 : isLargeTablet ? -42 : isTablet ? -36 : -30; const controlsTranslateY = isTV ? -48 : isLargeTablet ? -42 : isTablet ? -36 : -30;
const skipTextFont = isTV ? 14 : isLargeTablet ? 13 : isTablet ? 12 : 12; const skipTextFont = isTV ? 14 : isLargeTablet ? 13 : isTablet ? 12 : 12;
const sliderBottom = isTV ? 80 : isLargeTablet ? 70 : isTablet ? 65 : 55; const sliderBottom = isTV ? 60 : isLargeTablet ? 50 : isTablet ? 45 : 35;
const progressTouchHeight = isTV ? 48 : isLargeTablet ? 44 : isTablet ? 40 : 40; const progressTouchHeight = isTV ? 48 : isLargeTablet ? 44 : isTablet ? 40 : 40;
const progressBarHeight = isTV ? 6 : isLargeTablet ? 5 : isTablet ? 5 : 4; const progressBarHeight = isTV ? 6 : isLargeTablet ? 5 : isTablet ? 5 : 4;
const progressThumbSize = isTV ? 24 : isLargeTablet ? 20 : isTablet ? 18 : 16; const progressThumbSize = isTV ? 24 : isLargeTablet ? 20 : isTablet ? 18 : 16;
@ -184,7 +184,7 @@ export const styles = StyleSheet.create({
fontWeight: '500', fontWeight: '500',
opacity: 1, opacity: 1,
textAlign: 'center', textAlign: 'center',
marginLeft: -7, // Adjusted for better centering with icon marginLeft: -7,
}, },
/* CloudStream Style - Play Button */ /* CloudStream Style - Play Button */
@ -303,6 +303,14 @@ export const styles = StyleSheet.create({
fontSize: durationFont, fontSize: durationFont,
fontWeight: '500', fontWeight: '500',
}, },
timeContainer: {
paddingHorizontal: 10,
paddingVertical: 4,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderRadius: 12,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.2)',
},
bottomButtons: { bottomButtons: {
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-around', justifyContent: 'space-around',
@ -317,6 +325,32 @@ export const styles = StyleSheet.create({
color: 'white', color: 'white',
fontSize: bottomButtonTextFont, fontSize: bottomButtonTextFont,
}, },
bottomIconRow: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
gap: 24,
paddingVertical: 8,
},
iconButton: {
padding: 10,
alignItems: 'center',
justifyContent: 'center',
},
centerControlsContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 8,
paddingHorizontal: 12,
paddingVertical: 6,
marginTop: 12,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderRadius: 24,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.2)',
alignSelf: 'center',
},
modalOverlay: { modalOverlay: {
flex: 1, flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.9)', backgroundColor: 'rgba(0, 0, 0, 0.9)',