Fullscreen scrubber #205
6 changed files with 138 additions and 15 deletions
app/src
src/main/java/io/lbry/browser
|
@ -41,7 +41,8 @@ class MediaPlayer extends React.PureComponent {
|
|||
controlsTimeout: -1,
|
||||
seekerOffset: 0,
|
||||
seekerPosition: 0,
|
||||
firstPlay: true
|
||||
firstPlay: true,
|
||||
seekTimeout: -1
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -175,6 +176,9 @@ class MediaPlayer extends React.PureComponent {
|
|||
|
||||
onPanResponderGrant: (evt, gestureState) => {
|
||||
this.clearControlsTimeout();
|
||||
if (this.state.seekTimeout > 0) {
|
||||
clearTimeout(this.state.seekTimeout);
|
||||
}
|
||||
this.setState({ seeking: true });
|
||||
},
|
||||
|
||||
|
@ -190,7 +194,7 @@ class MediaPlayer extends React.PureComponent {
|
|||
this.onEnd();
|
||||
} else {
|
||||
this.seekTo(time);
|
||||
this.setState({ seeking: false });
|
||||
this.setState({ seekTimeout: setTimeout(() => { this.setState({ seeking: false }); }, 100) });
|
||||
}
|
||||
this.hidePlayerControls();
|
||||
}
|
||||
|
@ -258,7 +262,7 @@ class MediaPlayer extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { backgroundPlayEnabled, fileInfo, thumbnail, style } = this.props;
|
||||
const { backgroundPlayEnabled, fileInfo, thumbnail, onLayout, style } = this.props;
|
||||
const completedWidth = this.getCurrentTimePercentage() * this.seekerWidth;
|
||||
const remainingWidth = this.seekerWidth - completedWidth;
|
||||
let styles = [this.state.fullscreenMode ? mediaPlayerStyle.fullscreenContainer : mediaPlayerStyle.container];
|
||||
|
@ -274,7 +278,7 @@ class MediaPlayer extends React.PureComponent {
|
|||
mediaPlayerStyle.fullscreenTrackingControls : mediaPlayerStyle.containedTrackingControls];
|
||||
|
||||
return (
|
||||
<View style={styles}>
|
||||
<View style={styles} onLayout={onLayout}>
|
||||
<Video source={{ uri: 'file:///' + fileInfo.download_path }}
|
||||
ref={(ref: Video) => { this.video = ref }}
|
||||
resizeMode={this.state.resizeMode}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
ActivityIndicator,
|
||||
Alert,
|
||||
Button,
|
||||
Dimensions,
|
||||
NativeModules,
|
||||
ScrollView,
|
||||
StatusBar,
|
||||
|
@ -25,12 +26,17 @@ import MediaPlayer from '../../component/mediaPlayer';
|
|||
import UriBar from '../../component/uriBar';
|
||||
import Video from 'react-native-video';
|
||||
import filePageStyle from '../../styles/filePage';
|
||||
import uriBarStyle from '../../styles/uriBar';
|
||||
|
||||
class FilePage extends React.PureComponent {
|
||||
static navigationOptions = {
|
||||
title: ''
|
||||
};
|
||||
|
||||
playerBackground = null;
|
||||
|
||||
player = null;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -39,7 +45,10 @@ class FilePage extends React.PureComponent {
|
|||
fullscreenMode: false,
|
||||
showImageViewer: false,
|
||||
showWebView: false,
|
||||
imageUrls: null
|
||||
imageUrls: null,
|
||||
playerBgHeight: 0,
|
||||
playerHeight: 0,
|
||||
isLandscape: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -56,6 +65,9 @@ class FilePage extends React.PureComponent {
|
|||
if (NativeModules.Mixpanel) {
|
||||
NativeModules.Mixpanel.track('Open File Page', { Uri: uri });
|
||||
}
|
||||
if (NativeModules.UtilityModule) {
|
||||
NativeModules.UtilityModule.keepAwakeOn();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
|
@ -88,7 +100,8 @@ class FilePage extends React.PureComponent {
|
|||
// fullscreen, so change orientation to landscape mode
|
||||
NativeModules.ScreenOrientation.lockOrientationLandscape();
|
||||
} else {
|
||||
NativeModules.ScreenOrientation.unlockOrientation();
|
||||
// Switch back to portrait mode when the media is not fullscreen
|
||||
NativeModules.ScreenOrientation.lockOrientationPortrait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +138,9 @@ class FilePage extends React.PureComponent {
|
|||
StatusBar.setHidden(false);
|
||||
if (NativeModules.ScreenOrientation) {
|
||||
NativeModules.ScreenOrientation.unlockOrientation();
|
||||
}
|
||||
if (NativeModules.UtilityModule) {
|
||||
NativeModules.UtilityModule.keepAwakeOff();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,6 +180,24 @@ class FilePage extends React.PureComponent {
|
|||
return linkifiedContent;
|
||||
}
|
||||
|
||||
checkOrientation = () => {
|
||||
if (this.state.fullscreenMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const screenDimension = Dimensions.get('window');
|
||||
const screenWidth = screenDimension.width;
|
||||
const screenHeight = screenDimension.height;
|
||||
const isLandscape = screenWidth > screenHeight;
|
||||
this.setState({ isLandscape });
|
||||
|
||||
if (isLandscape) {
|
||||
this.playerBackground.setNativeProps({ height: screenHeight - StyleSheet.flatten(uriBarStyle.uriContainer).height });
|
||||
} else if (this.state.playerBgHeight > 0) {
|
||||
this.playerBackground.setNativeProps({ height: this.state.playerBgHeight });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
claim,
|
||||
|
@ -212,8 +246,9 @@ class FilePage extends React.PureComponent {
|
|||
const channelClaimId =
|
||||
value && value.publisherSignature && value.publisherSignature.certificateId;
|
||||
|
||||
const playerStyle = [filePageStyle.player, this.state.fullscreenMode ?
|
||||
filePageStyle.fullscreenPlayer : filePageStyle.containedPlayer];
|
||||
const playerStyle = [filePageStyle.player,
|
||||
this.state.isLandscape ? filePageStyle.containedPlayerLandscape :
|
||||
(this.state.fullscreenMode ? filePageStyle.fullscreenPlayer : filePageStyle.containedPlayer)];
|
||||
const playerBgStyle = [filePageStyle.playerBackground, this.state.fullscreenMode ?
|
||||
filePageStyle.fullscreenPlayerBackground : filePageStyle.containedPlayerBackground];
|
||||
// at least 2MB (or the full download) before media can be loaded
|
||||
|
@ -251,7 +286,8 @@ class FilePage extends React.PureComponent {
|
|||
renderIndicator={() => null} />}
|
||||
|
||||
{!this.state.showWebView && (
|
||||
<View style={filePageStyle.innerPageContainer}>
|
||||
<View style={this.state.fullscreenMode ? filePageStyle.innerPageContainerFsMode : filePageStyle.innerPageContainer}
|
||||
onLayout={this.checkOrientation}>
|
||||
<View style={filePageStyle.mediaContainer}>
|
||||
{(canOpen || (!fileInfo || (isPlayable && !canLoadMedia))) &&
|
||||
<FileItemMedia style={filePageStyle.thumbnail} title={title} thumbnail={metadata.thumbnail} />}
|
||||
|
@ -264,13 +300,25 @@ class FilePage extends React.PureComponent {
|
|||
onPlay={() => this.setState({ autoPlayMedia: true })} />}
|
||||
{!fileInfo && <FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />}
|
||||
</View>
|
||||
{canLoadMedia && <View style={playerBgStyle} />}
|
||||
{canLoadMedia && <View style={playerBgStyle} ref={(ref) => { this.playerBackground = ref; }}
|
||||
onLayout={(evt) => {
|
||||
if (!this.state.playerBgHeight) {
|
||||
this.setState({ playerBgHeight: evt.nativeEvent.layout.height });
|
||||
}
|
||||
}} />}
|
||||
{canLoadMedia && <MediaPlayer fileInfo={fileInfo}
|
||||
ref={(ref) => { this.player = ref; }}
|
||||
uri={uri}
|
||||
style={playerStyle}
|
||||
autoPlay={this.state.autoPlayMedia}
|
||||
onFullscreenToggled={this.handleFullscreenToggle}
|
||||
onMediaLoaded={() => { this.setState({ mediaLoaded: true }); }}/>}
|
||||
onMediaLoaded={() => { this.setState({ mediaLoaded: true }); }}
|
||||
onLayout={(evt) => {
|
||||
if (!this.state.playerHeight) {
|
||||
this.setState({ playerHeight: evt.nativeEvent.layout.height });
|
||||
}
|
||||
}}
|
||||
/>}
|
||||
|
||||
{ showActions &&
|
||||
<View style={filePageStyle.actions}>
|
||||
|
@ -293,7 +341,7 @@ class FilePage extends React.PureComponent {
|
|||
</View>
|
||||
)}
|
||||
|
||||
<UriBar value={uri} navigation={navigation} />
|
||||
{!this.state.fullscreenMode && <UriBar value={uri} navigation={navigation} />}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ const filePageStyle = StyleSheet.create({
|
|||
flex: 1,
|
||||
marginBottom: 60
|
||||
},
|
||||
innerPageContainerFsMode: {
|
||||
flex: 1,
|
||||
marginBottom: 0
|
||||
},
|
||||
mediaContainer: {
|
||||
alignItems: 'center',
|
||||
width: screenWidth,
|
||||
|
@ -76,12 +80,17 @@ const filePageStyle = StyleSheet.create({
|
|||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
zIndex: 101
|
||||
zIndex: 301,
|
||||
elevation: 21
|
||||
},
|
||||
containedPlayer: {
|
||||
width: '100%',
|
||||
height: 220,
|
||||
},
|
||||
containedPlayerLandscape: {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
},
|
||||
fullscreenPlayer: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
@ -92,7 +101,8 @@ const filePageStyle = StyleSheet.create({
|
|||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
zIndex: 100,
|
||||
zIndex: 300,
|
||||
elevation: 20,
|
||||
backgroundColor: Colors.Black
|
||||
},
|
||||
containedPlayerBackground: {
|
||||
|
|
|
@ -36,4 +36,12 @@ public class ScreenOrientationModule extends ReactContextBaseJavaModule {
|
|||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void lockOrientationPortrait() {
|
||||
Activity activity = getCurrentActivity();
|
||||
if (activity != null) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package io.lbry.browser.reactmodules;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
public class UtilityModule extends ReactContextBaseJavaModule {
|
||||
private Context context;
|
||||
|
||||
public UtilityModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.context = reactContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "UtilityModule";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void keepAwakeOn() {
|
||||
final Activity activity = getCurrentActivity();
|
||||
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void keepAwakeOff() {
|
||||
final Activity activity = getCurrentActivity();
|
||||
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import io.lbry.browser.reactmodules.FirstRunModule;
|
|||
import io.lbry.browser.reactmodules.MixpanelModule;
|
||||
import io.lbry.browser.reactmodules.ScreenOrientationModule;
|
||||
import io.lbry.browser.reactmodules.VersionInfoModule;
|
||||
import io.lbry.browser.reactmodules.UtilityModule;;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -31,8 +32,9 @@ public class LbryReactPackage implements ReactPackage {
|
|||
modules.add(new FirstRunModule(reactContext));
|
||||
modules.add(new MixpanelModule(reactContext));
|
||||
modules.add(new ScreenOrientationModule(reactContext));
|
||||
modules.add(new UtilityModule(reactContext));
|
||||
modules.add(new VersionInfoModule(reactContext));
|
||||
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue