mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-27 11:23:02 +00:00
player UI update
This commit is contained in:
parent
09e35d5a0c
commit
34f110f16a
2 changed files with 78 additions and 65 deletions
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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)',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue