Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
music_secret.js
// @flow
import React from "react";
import {
Dimensions,
Image,
ImageBackground,
SafeAreaView,
Slider,
StyleSheet,
Text,
TouchableHighlight,
TouchableOpacity,
View
} from "react-native";
import { Asset, Audio, Font, Video, KeepAwake } from "expo";
import { MaterialIcons, Ionicons } from "@expo/vector-icons";
import { inject, observer } from "mobx-react";
import { observable } from "mobx";
import UserName from "../../store/mobxclass";
class Icon {
constructor(module, width, height) {
this.module = module;
this.width = width;
this.height = height;
Asset.fromModule(this.module).downloadAsync();
}
}
function concat(uri, user) {
var join = `${uri}${user}.mp3`;
console.log("join", join); // approx. 25000
return join;
}
class PlaylistItem {
constructor(uri, isVideo) {
this.uri = uri;
this.isVideo = isVideo;
}
}
const PLAYLIST = [
new PlaylistItem("http://assets.aflorithmic.com/0123456789_1__", false)
];
const ICON_THROUGH_EARPIECE = "speaker-phone";
const ICON_THROUGH_SPEAKER = "speaker";
const ICON_PLAY_BUTTON = new Icon(
require("../../../assets/images/play-64px-icon.png"),
34,
51
);
const ICON_PAUSE_BUTTON = new Icon(
require("../../../assets/images/pause-64px-icon.png"),
34,
51
);
const ICON_STOP_BUTTON = new Icon(
require("../../../assets/images/stop_button.png"),
22,
22
);
const ICON_LOOP_ALL_BUTTON = new Icon(
require("../../../assets/images/loop_all_button.png"),
77,
35
);
const ICON_LOOP_ONE_BUTTON = new Icon(
require("../../../assets/images/loop_one_button.png"),
77,
35
);
const ICON_MUTED_BUTTON = new Icon(
require("../../../assets/images/muted_button.png"),
67,
58
);
const ICON_UNMUTED_BUTTON = new Icon(
require("../../../assets/images/unmuted_button.png"),
67,
58
);
const ICON_TRACK_1 = new Icon(
require("../../../assets/images/track_1.png"),
166,
5
);
const ICON_THUMB_1 = new Icon(
require("../../../assets/images/thumb_1.png"),
18,
19
);
const ICON_THUMB_2 = new Icon(
require("../../../assets/images/thumb_2.png"),
15,
19
);
const LOOPING_TYPE_ALL = 0;
const LOOPING_TYPE_ONE = 1;
const LOOPING_TYPE_ICONS = { 0: ICON_LOOP_ALL_BUTTON, 1: ICON_LOOP_ONE_BUTTON };
const { width: DEVICE_WIDTH, height: DEVICE_HEIGHT } = Dimensions.get("window");
const BACKGROUND_COLOR = "rgba(0,0,0,0)";
const DISABLED_OPACITY = 0.5;
const FONT_SIZE = 14;
const LOADING_STRING = "... loading ...";
const RATE_SCALE = 3.0;
const VIDEO_CONTAINER_HEIGHT = (DEVICE_HEIGHT * 2.0) / 20.0 - FONT_SIZE * 4;
@inject("UserName")
@observer
class MusicScreen extends React.Component {
_isMounted = false;
constructor(props) {
super(props);
this.index = 0;
this.isSeeking = false;
this.shouldPlayAtEndOfSeek = false;
this.playbackInstance = null;
this.state = {
showVideo: false,
loopingType: LOOPING_TYPE_ALL,
muted: false,
playbackInstancePosition: null,
playbackInstanceDuration: null,
shouldPlay: true,
isPlaying: false,
isBuffering: false,
isLoading: true,
fontLoaded: false,
shouldCorrectPitch: true,
volume: 1.0,
rate: 1.0,
videoWidth: DEVICE_WIDTH,
videoHeight: VIDEO_CONTAINER_HEIGHT,
poster: false,
useNativeControls: false,
fullscreen: false,
throughEarpiece: false
};
}
componentDidMount() {
this._isMounted = true;
Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: false
});
(async () => {
await Font.loadAsync({
...MaterialIcons.font,
"cutive-mono-regular": require("../../../assets/fonts/CutiveMono-Regular.ttf"),
"Raleway-Regular": require("../../../assets/fonts/Raleway-Regular.otf")
});
this.setState({ fontLoaded: true });
})();
}
async _loadNewPlaybackInstance(playing) {
if (this.playbackInstance != null) {
await this.playbackInstance.unloadAsync();
this.playbackInstance.setOnPlaybackStatusUpdate(null);
this.playbackInstance = null;
}
const source = {
uri: concat(PLAYLIST[this.index].uri, this.props.UserName.username)
};
console.log("UserName", this.props.UserName.username);
console.log("source_string", source);
const initialStatus = {
shouldPlay: playing,
volume: this.state.volume,
isMuted: this.state.muted,
isLooping: this.state.loopingType === LOOPING_TYPE_ONE
// // UNCOMMENT THIS TO TEST THE OLD androidImplementation:
// androidImplementation: 'MediaPlayer',
};
if (PLAYLIST[this.index].isVideo) {
this._video.setOnPlaybackStatusUpdate(this._onPlaybackStatusUpdate);
await this._video.loadAsync(source, initialStatus);
this.playbackInstance = this._video;
} else {
const soundObject = new Audio.Sound();
try {
await soundObject.loadAsync(
source,
initialStatus,
this._onPlaybackStatusUpdate,
(downloadFirst = true)
);
//await soundObject.playAsync()
console.log("status async", soundObject.getStatusAsync());
this.playbackInstance = soundObject;
} catch (error) {
console.log("error_loading", error);
}
this._updateScreenForLoading(false);
}
}
_mountVideo = component => {
this._video = component;
this._loadNewPlaybackInstance(false);
};
_updateScreenForLoading(isLoading) {
if (isLoading) {
this.setState({
showVideo: false,
isPlaying: true,
playbackInstanceDuration: null,
AplaybackInstancePosition: null,
isLoading: true
});
} else {
this.setState({
showVideo: PLAYLIST[this.index].isVideo,
isLoading: false
});
}
}
_onPlaybackStatusUpdate = status => {
if (status.isLoaded) {
this.setState({
playbackInstancePosition: status.positionMillis,
playbackInstanceDuration: status.durationMillis,
shouldPlay: status.shouldPlay,
isPlaying: status.isPlaying,
isBuffering: status.isBuffering,
muted: status.isMuted,
volume: status.volume,
loopingType: status.isLooping ? LOOPING_TYPE_ONE : LOOPING_TYPE_ALL
});
if (status.didJustFinish && !status.isLooping) {
this._advanceIndex(true);
this._updatePlaybackInstanceForIndex(true);
}
} else {
if (status.error) {
console.log(`FATAL PLAYER ERROR: ${status.error}`);
}
}
};
_onLoadStart = () => {
console.log(`ON LOAD START`);
};
_onLoad = status => {
console.log(`ON LOAD : ${JSON.stringify(status)}`);
};
_onError = error => {
console.log(`ON ERROR : ${error}`);
};
_onReadyForDisplay = event => {
const widestHeight =
(DEVICE_WIDTH * event.naturalSize.height) / event.naturalSize.width;
if (widestHeight > VIDEO_CONTAINER_HEIGHT) {
this.setState({
videoWidth:
(VIDEO_CONTAINER_HEIGHT * event.naturalSize.width) /
event.naturalSize.height,
videoHeight: VIDEO_CONTAINER_HEIGHT
});
} else {
this.setState({
videoWidth: DEVICE_WIDTH,
videoHeight:
(DEVICE_WIDTH * event.naturalSize.height) / event.naturalSize.width
});
}
};
_onFullscreenUpdate = event => {
console.log(
`FULLSCREEN UPDATE : ${JSON.stringify(event.fullscreenUpdate)}`
);
};
_advanceIndex(forward) {
this.index =
(this.index + (forward ? 1 : PLAYLIST.length - 1)) % PLAYLIST.length;
}
async _updatePlaybackInstanceForIndex(playing) {
this._updateScreenForLoading(true);
this.setState({
videoWidth: DEVICE_WIDTH,
videoHeight: VIDEO_CONTAINER_HEIGHT
});
this._loadNewPlaybackInstance(playing);
}
_onPlayPausePressed = () => {
if (this.playbackInstance != null) {
if (this.state.isPlaying) {
this.playbackInstance.pauseAsync();
} else {
this.playbackInstance.playAsync();
}
}
};
_onStopPressed = () => {
if (this.playbackInstance != null) {
this.playbackInstance.stopAsync();
}
};
_onMutePressed = () => {
if (this.playbackInstance != null) {
this.playbackInstance.setIsMutedAsync(!this.state.muted);
}
};
_onLoopPressed = () => {
if (this.playbackInstance != null) {
this.playbackInstance.setIsLoopingAsync(
this.state.loopingType !== LOOPING_TYPE_ONE
);
}
};
_onVolumeSliderValueChange = value => {
if (this.playbackInstance != null) {
this.playbackInstance.setVolumeAsync(value);
}
};
_trySetRate = async (rate, shouldCorrectPitch) => {
if (this.playbackInstance != null) {
try {
await this.playbackInstance.setRateAsync(rate, shouldCorrectPitch);
} catch (error) {
// Rate changing could not be performed, possibly because the client's Android API is too old.
}
}
};
_onRateSliderSlidingComplete = async value => {
this._trySetRate(value * RATE_SCALE, this.state.shouldCorrectPitch);
};
_onPitchCorrectionPressed = async () => {
this._trySetRate(this.state.rate, !this.state.shouldCorrectPitch);
};
_onSeekSliderValueChange = () => {
if (this.playbackInstance != null && !this.isSeeking) {
this.isSeeking = true;
this.shouldPlayAtEndOfSeek = this.state.shouldPlay;
this.playbackInstance.pauseAsync();
}
};
_onSeekSliderSlidingComplete = async value => {
if (this.playbackInstance != null) {
this.isSeeking = false;
const seekPosition = value * this.state.playbackInstanceDuration;
if (this.shouldPlayAtEndOfSeek) {
this.playbackInstance.playFromPositionAsync(seekPosition);
} else {
this.playbackInstance.setPositionAsync(seekPosition);
}
}
};
_getSeekSliderPosition() {
if (
this.playbackInstance != null &&
this.state.playbackInstancePosition != null &&
this.state.playbackInstanceDuration != null
) {
return (
this.state.playbackInstancePosition /
this.state.playbackInstanceDuration
);
}
return 0;
}
_getMMSSFromMillis(millis) {
const totalSeconds = millis / 1000;
const seconds = Math.floor(totalSeconds % 60);
const minutes = Math.floor(totalSeconds / 60);
const padWithZero = number => {
const string = number.toString();
if (number < 10) {
return "0" + string;
}
return string;
};
return padWithZero(minutes) + ":" + padWithZero(seconds);
}
_getTimestamp() {
if (
this.playbackInstance != null &&
this.state.playbackInstancePosition != null &&
this.state.playbackInstanceDuration != null
) {
return `${this._getMMSSFromMillis(
this.state.playbackInstancePosition
)} / ${this._getMMSSFromMillis(this.state.playbackInstanceDuration)}`;
}
return "";
}
_onPosterPressed = () => {
this.setState({ poster: !this.state.poster });
};
_onUseNativeControlsPressed = () => {
this.setState({ useNativeControls: !this.state.useNativeControls });
};
_onFullscreenPressed = () => {
try {
this._video.presentFullscreenPlayer();
} catch (error) {
console.log(error.toString());
}
};
_onSpeakerPressed = () => {
this.setState(
state => {
return { throughEarpiece: !state.throughEarpiece };
},
({ throughEarpiece }) =>
Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: throughEarpiece
})
);
};
componentWillUnmount() {
this._isMounted = false;
}
render() {
return !this.state.fontLoaded ? (
<View style={styles.emptyContainer} />
) : (
<ImageBackground
source={require("../../../assets/images/backgroundMusic.jpg")}
style={styles.backgroundImageStyle}
>
<SafeAreaView />
<View style={styles.container}>
<View style={styles.statusBarImage}>
<TouchableOpacity
onPress={() => this.props.navigation.toggleDrawer()}
>
<View style={{ paddingHorizontal: 10 }}>
<Ionicons size={24} name="md-menu" style={{ color: "#fff" }} />
</View>
</TouchableOpacity>
<Image
source={require("../../../assets/images/whiteLogoName.png")}
style={{
alignSelf: "center",
width: "30%",
height: 130,
resizeMode: "contain"
}}
/>
<View style={{ alignSelf: "center", width: 20, height: 20 }} />
</View>
<View style={styles.container2}>
<Text style={styles.textDayStyle}>Day 1</Text>
<View style={styles.nameContainer} />
<View
style={[
styles.playbackContainer,
{
opacity: this.state.isLoading ? DISABLED_OPACITY : 1.0
}
]}
/>
<View style={styles.blueBackStyle}>
<View
style={[
{
opacity: this.state.isLoading ? DISABLED_OPACITY : 1.0
}
]}
>
<TouchableHighlight
underlayColor={BACKGROUND_COLOR}
style={styles.wrapper}
onPress={this._onPlayPausePressed}
disabled={this.state.isLoading}
>
<Image
style={styles.button}
source={
this.state.isPlaying
? ICON_PAUSE_BUTTON.module
: ICON_PLAY_BUTTON.module
}
/>
</TouchableHighlight>
</View>
{/*<TouchableHighlight*/}
{/*underlayColor={BACKGROUND_COLOR}*/}
{/*style={styles.wrapper}*/}
{/*onPress={this._onStopPressed}*/}
{/*disabled={this.state.isLoading}>*/}
{/*<Image style={styles.button} source={ICON_STOP_BUTTON.module} />*/}
{/*</TouchableHighlight>*/}
</View>
</View>
<View />
<View style={styles.nameContainer} />
<View style={styles.space} />
{/*<View style={styles.imageContainer}>*/}
{/*<Image*/}
{/*style={{ width: 400, height: 300 }}*/}
{/*source={require('../../.../../../assets/images/burning_candle.gif')} />*/}
{/*</View>*/}
<View style={styles.videoContainer}>
<KeepAwake />
<Video
ref={this._mountVideo}
style={[
styles.video,
{
opacity: this.state.showVideo ? 1.0 : 0.0,
width: this.state.videoWidth,
height: this.state.videoHeight
}
]}
resizeMode={Video.RESIZE_MODE_CONTAIN}
onPlaybackStatusUpdate={this._onPlaybackStatusUpdate}
onLoadStart={this._onLoadStart}
onLoad={this._onLoad}
onError={this._onError}
onFullscreenUpdate={this._onFullscreenUpdate}
onReadyForDisplay={this._onReadyForDisplay}
useNativeControls={this.state.useNativeControls}
/>
</View>
<View
style={[
styles.buttonsContainerBase,
styles.buttonsContainerMiddleRow
]}
>
{/*<View style={styles.volumeContainer}>*/}
{/*<TouchableHighlight*/}
{/*underlayColor={BACKGROUND_COLOR}*/}
{/*style={styles.wrapper}*/}
{/*onPress={this._onMutePressed}>*/}
{/*<Image*/}
{/*style={styles.button}*/}
{/*source={this.state.muted ? ICON_MUTED_BUTTON.module : ICON_UNMUTED_BUTTON.module}*/}
{/*/>*/}
{/*</TouchableHighlight>*/}
{/*<Slider*/}
{/*style={styles.volumeSlider}*/}
{/*trackImage={ICON_TRACK_1.module}*/}
{/*thumbImage={ICON_THUMB_2.module}*/}
{/*value={1}*/}
{/*onValueChange={this._onVolumeSliderValueChange}*/}
{/*/>*/}
{/*</View>*/}
{/*<TouchableHighlight*/}
{/*underlayColor={BACKGROUND_COLOR}*/}
{/*style={styles.wrapper}*/}
{/*onPress={this._onLoopPressed}>*/}
{/*<Image*/}
{/*style={styles.button}*/}
{/*source={LOOPING_TYPE_ICONS[this.state.loopingType].module}*/}
{/*/>*/}
{/*</TouchableHighlight>*/}
</View>
<View />
{this.state.showVideo ? (
<View>
<View
style={[
styles.buttonsContainerBase,
styles.buttonsContainerTextRow
]}
>
<View />
<TouchableHighlight
underlayColor={BACKGROUND_COLOR}
style={styles.wrapper}
onPress={this._onPosterPressed}
>
<View style={styles.button}>
<Text
style={[
styles.text,
{ fontFamily: "cutive-mono-regular" }
]}
>
Poster: {this.state.poster ? "yes" : "no"}
</Text>
</View>
</TouchableHighlight>
<View />
<TouchableHighlight
underlayColor={BACKGROUND_COLOR}
style={styles.wrapper}
onPress={this._onFullscreenPressed}
>
<View style={styles.button}>
<Text
style={[
styles.text,
{ fontFamily: "cutive-mono-regular" }
]}
>
Fullscreen
</Text>
</View>
</TouchableHighlight>
<View />
</View>
<View style={styles.space} />
<View
style={[
styles.buttonsContainerBase,
styles.buttonsContainerTextRow
]}
>
<View />
<TouchableHighlight
underlayColor={BACKGROUND_COLOR}
style={styles.wrapper}
onPress={this._onUseNativeControlsPressed}
>
<View style={styles.button}>
<Text
style={[
styles.text,
{ fontFamily: "cutive-mono-regular" }
]}
>
Native Controls:{" "}
{this.state.useNativeControls ? "yes" : "no"}
</Text>
</View>
</TouchableHighlight>
<View />
</View>
</View>
) : null}
</View>
</ImageBackground>
);
}
}
//
//export default withAuthenticator(App, { includeGreetings: true })
export default MusicScreen;
const styles = StyleSheet.create({
emptyContainer: {
alignSelf: "stretch",
backgroundColor: BACKGROUND_COLOR
},
container: {
flex: 1,
backgroundColor: BACKGROUND_COLOR
},
container2: {
justifyContent: "center",
alignItems: "center",
backgroundColor: BACKGROUND_COLOR
},
wrapper: {},
nameContainer: {
height: FONT_SIZE
},
space: {},
videoContainer: {
height: VIDEO_CONTAINER_HEIGHT
},
video: {
maxWidth: DEVICE_WIDTH
},
imageContainer: {
maxWidth: DEVICE_WIDTH
},
playbackContainer: {
flex: 1,
flexDirection: "column",
justifyContent: "space-between",
alignItems: "center",
alignSelf: "stretch",
minHeight: ICON_THUMB_1.height * 2.0,
maxHeight: ICON_THUMB_1.height * 2.0
},
timestampRow: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
alignSelf: "stretch",
minHeight: FONT_SIZE
},
text: {
fontSize: FONT_SIZE,
minHeight: FONT_SIZE
},
buffering: {
textAlign: "left",
paddingLeft: 20
},
timestamp: {
textAlign: "right",
paddingRight: 20
},
button: {
alignSelf: "center"
},
buttonsContainerBase: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between"
},
buttonsContainerTopRow: {
maxHeight: ICON_PLAY_BUTTON.height * 2.0,
minWidth: DEVICE_WIDTH / 2.0,
maxWidth: 25
},
buttonsContainerMiddleRow: {
maxHeight: ICON_MUTED_BUTTON.height,
alignSelf: "stretch",
paddingRight: 20
},
volumeContainer: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
minWidth: DEVICE_WIDTH / 2.0,
maxWidth: DEVICE_WIDTH / 2.0
},
volumeSlider: {
width: DEVICE_WIDTH / 2.0 - ICON_MUTED_BUTTON.width
},
buttonsContainerBottomRow: {
maxHeight: ICON_THUMB_1.height,
alignSelf: "stretch",
paddingRight: 20,
paddingLeft: 20
},
rateSlider: {
width: DEVICE_WIDTH / 2.0
},
buttonsContainerTextRow: {
maxHeight: FONT_SIZE,
alignItems: "center",
paddingRight: 20,
paddingLeft: 20,
minWidth: DEVICE_WIDTH,
maxWidth: DEVICE_WIDTH
},
statusBarImage: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
},
backgroundImageStyle: {
flex: 1,
height: "100%",
width: "100%",
resizeMode: "cover"
},
textDayStyle: {
fontWeight: "bold",
fontSize: 20,
padding: 10,
color: "#fff",
alignSelf: "center"
},
blueBackStyle: {
backgroundColor: "rgba(1,2,3,0.4)",
width: 110,
height: 110,
marginRight: 0,
borderRadius: 55,
opacity: 0.8,
justifyContent: "center",
alignItems: "center",
alignSelf: "center"
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.