Skip to content

Commit 40cf8b4

Browse files
committed
allow configuring the radio view source
1 parent c70b493 commit 40cf8b4

File tree

4 files changed

+150
-107
lines changed

4 files changed

+150
-107
lines changed

source/views/streaming/index.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// @flow
22

3+
import * as React from 'react'
34
import {TabNavigator} from '../components/tabbed-view'
5+
import {TabBarIcon} from '../components/tabbar-icon'
46

5-
import {KSTOView} from './radio'
7+
import {RadioControllerView} from './radio'
68
// import WeeklyMovieView from './movie'
79
import {WebcamsView} from './webcams'
810
import {StreamListView} from './streams'
@@ -13,7 +15,29 @@ export default TabNavigator(
1315
{
1416
StreamingView: {screen: StreamListView},
1517
LiveWebcamsView: {screen: WebcamsView},
16-
KSTORadioView: {screen: KSTOView},
18+
KSTORadioView: {
19+
screen: ({navigation}) => (
20+
<RadioControllerView
21+
image={require('../../../images/streaming/ksto.png')}
22+
navigation={navigation}
23+
playerUrl="https://www.stolaf.edu/multimedia/play/embed/ksto.html"
24+
scheduleViewName="KSTOScheduleView"
25+
source={{
26+
useEmbeddedPlayer: true,
27+
embeddedPlayerUrl:
28+
'https://www.stolaf.edu/multimedia/play/embed/ksto.html',
29+
streamSourceUrl: '',
30+
}}
31+
stationName="KSTO 93.1 FM"
32+
stationNumber="+15077863602"
33+
title="St. Olaf College Radio"
34+
/>
35+
),
36+
navigationOptions: {
37+
tabBarLabel: 'KSTO',
38+
tabBarIcon: TabBarIcon('radio'),
39+
},
40+
},
1741
// WeeklyMovieView: {screen: WeeklyMovieView},
1842
},
1943
{

source/views/streaming/radio/controller.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
} from 'react-native'
1313
import noop from 'lodash/noop'
1414
import * as c from '../../components/colors'
15-
import {TabBarIcon} from '../../components/tabbar-icon'
1615
import {callPhone} from '../../components/call-phone'
1716
import {Row} from '../../components/layout'
1817
import type {TopLevelViewPropsType} from '../../types'
@@ -21,11 +20,19 @@ import type {PlayState, HtmlAudioError, Viewport} from './types'
2120
import {ActionButton, ShowCalendarButton, CallButton} from './buttons'
2221
import {openUrl} from '../../components/open-url'
2322

24-
const image = require('../../../../images/streaming/ksto/ksto-logo.png')
25-
const stationNumber = '+15077863602'
26-
const kstoLiveUrl = 'https://www.stolaf.edu/multimedia/play/embed/ksto.html'
27-
28-
type Props = TopLevelViewPropsType
23+
type Props = TopLevelViewPropsType & {
24+
image: number,
25+
playerUrl: string,
26+
stationNumber: string,
27+
title: string,
28+
scheduleViewName: string,
29+
stationName: string,
30+
source: {
31+
useEmbeddedPlayer: boolean,
32+
embeddedPlayerUrl: string,
33+
streamSourceUrl: string,
34+
},
35+
}
2936

3037
type State = {
3138
playState: PlayState,
@@ -34,12 +41,7 @@ type State = {
3441
viewport: Viewport,
3542
}
3643

37-
export class KSTOView extends React.PureComponent<Props, State> {
38-
static navigationOptions = {
39-
tabBarLabel: 'KSTO',
40-
tabBarIcon: TabBarIcon('radio'),
41-
}
42-
44+
export class RadioControllerView extends React.PureComponent<Props, State> {
4345
state = {
4446
playState: 'paused',
4547
streamError: null,
@@ -84,15 +86,15 @@ export class KSTOView extends React.PureComponent<Props, State> {
8486
}
8587

8688
openSchedule = () => {
87-
this.props.navigation.navigate('KSTOScheduleView')
89+
this.props.navigation.navigate(this.props.scheduleViewName)
8890
}
8991

9092
callStation = () => {
91-
callPhone(stationNumber)
93+
callPhone(this.props.stationNumber)
9294
}
9395

9496
openStreamWebsite = () => {
95-
openUrl(kstoLiveUrl)
97+
openUrl(this.props.playerUrl)
9698
}
9799

98100
renderPlayButton = (state: PlayState) => {
@@ -156,18 +158,18 @@ export class KSTOView extends React.PureComponent<Props, State> {
156158
<View style={[styles.logoWrapper, sideways && landscape.logoWrapper]}>
157159
<Image
158160
resizeMode="contain"
159-
source={image}
161+
source={this.props.image}
160162
style={[styles.logo, logoSize]}
161163
/>
162164
</View>
163165

164166
<View style={styles.container}>
165167
<View style={styles.titleWrapper}>
166168
<Text selectable={true} style={styles.heading}>
167-
St. Olaf College Radio
169+
{this.props.title}
168170
</Text>
169171
<Text selectable={true} style={styles.subHeading}>
170-
KSTO 93.1 FM
172+
{this.props.stationName}
171173
</Text>
172174

173175
{error}
@@ -183,14 +185,17 @@ export class KSTOView extends React.PureComponent<Props, State> {
183185

184186
{Platform.OS !== 'android' ? (
185187
<StreamPlayer
188+
embeddedPlayerUrl={this.props.source.embeddedPlayerUrl}
186189
onEnded={this.handleStreamEnd}
187190
// onWaiting={this.handleStreamWait}
188191
onError={this.handleStreamError}
189192
// onStalled={this.handleStreamStall}
190193
onPause={this.handleStreamPause}
191194
onPlay={this.handleStreamPlay}
192195
playState={this.state.playState}
196+
streamSourceUrl={this.props.source.streamSourceUrl}
193197
style={styles.webview}
198+
useEmbeddedPlayer={this.props.source.useEmbeddedPlayer}
194199
/>
195200
) : null}
196201
</View>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// @flow
22

3-
export {KSTOView} from './controller'
3+
export {RadioControllerView} from './controller'
44
export {KSTOScheduleView} from './schedule'

source/views/streaming/radio/player.js

Lines changed: 100 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import * as React from 'react'
44
import {WebView} from 'react-native'
55
import type {PlayState, HtmlAudioError} from './types'
66

7-
const kstoEmbed = 'https://www.stolaf.edu/multimedia/play/embed/ksto.html'
8-
97
type Props = {
108
playState: PlayState,
119
onWaiting?: () => any,
@@ -15,6 +13,9 @@ type Props = {
1513
onPause?: () => any,
1614
onError?: HtmlAudioError => any,
1715
style: any,
16+
useEmbeddedPlayer: boolean,
17+
embeddedPlayerUrl: string,
18+
streamSourceUrl: string,
1819
}
1920

2021
type HtmlAudioState =
@@ -99,98 +100,111 @@ export class StreamPlayer extends React.PureComponent<Props> {
99100

100101
setRef = (ref: WebView) => (this._webview = ref)
101102

102-
js = `
103-
function ready(fn) {
104-
if (document.readyState !== 'loading') {
105-
fn();
106-
} else if (document.addEventListener) {
107-
document.addEventListener('DOMContentLoaded', fn);
108-
} else {
109-
document.attachEvent('onreadystatechange', function () {
110-
if (document.readyState !== 'loading') {
111-
fn();
112-
}
113-
});
114-
}
115-
};
116-
117-
ready(function () {
118-
var player = document.querySelector('audio');
119-
120-
/*******
121-
*******/
122-
123-
document.addEventListener('message', function (event) {
124-
switch (event.data) {
125-
case 'play':
126-
player.muted = false;
127-
player.play().catch(error);
128-
break;
129-
130-
case 'pause':
131-
player.pause();
132-
break;
133-
}
134-
});
135-
136-
/*******
137-
*******/
138-
139-
function message(data) {
140-
window.postMessage(JSON.stringify(data));
141-
}
142-
143-
function send(event) {
144-
message({type: event.type});
145-
}
146-
147-
function error(event) {
148-
message({
149-
type: event.type,
150-
error: 'error',
151-
});
152-
}
153-
154-
/*******
155-
*******/
156-
157-
/* "waiting" is fired when playback has stopped because of a temporary
158-
* lack of data. */
159-
player.addEventListener('waiting', send);
160-
161-
/* "ended" is fired when playback or streaming has stopped because the
162-
* end of the media was reached or because no further data is
163-
* available. */
164-
player.addEventListener('ended', send);
165-
166-
/* "stalled" is fired when the user agent is trying to fetch media data,
167-
* but data is unexpectedly not forthcoming. */
168-
player.addEventListener('stalled', send);
169-
170-
/* "playing" is fired when playback is ready to start after having been
171-
* paused or delayed due to lack of data. */
172-
player.addEventListener('playing', send);
173-
174-
/* "pause" is fired when playback has been paused. */
175-
player.addEventListener('pause', send);
176-
177-
/* "play" is fired when playback has begun. */
178-
player.addEventListener('play', send);
179-
180-
/* "error" is fired when an error occurs. */
181-
player.addEventListener('error', error);
182-
});
183-
`
103+
html = (url: string) => `
104+
<style>body {background-color: white;}</style>
105+
<title>Radio Stream</title>
106+
107+
<audio id="player" webkit-playsinline playsinline>
108+
<source src="${url}" />
109+
</audio>
110+
`
111+
112+
js = (selector: string = 'audio') => `
113+
function ready(fn) {
114+
if (document.readyState !== 'loading') {
115+
fn();
116+
} else if (document.addEventListener) {
117+
document.addEventListener('DOMContentLoaded', fn);
118+
} else {
119+
document.attachEvent('onreadystatechange', function () {
120+
if (document.readyState !== 'loading') {
121+
fn();
122+
}
123+
});
124+
}
125+
};
126+
127+
ready(function () {
128+
var player = document.querySelector('${selector}');
129+
130+
/*******
131+
*******/
132+
133+
document.addEventListener('message', function (event) {
134+
switch (event.data) {
135+
case 'play':
136+
player.muted = false;
137+
player.play().catch(error);
138+
break;
139+
140+
case 'pause':
141+
player.pause();
142+
break;
143+
}
144+
});
145+
146+
/*******
147+
*******/
148+
149+
function message(data) {
150+
window.postMessage(JSON.stringify(data));
151+
}
152+
153+
function send(event) {
154+
message({type: event.type});
155+
}
156+
157+
function error(event) {
158+
message({
159+
type: event.type,
160+
error: 'error',
161+
});
162+
}
163+
164+
/*******
165+
*******/
166+
167+
/* "waiting" is fired when playback has stopped because of a temporary
168+
* lack of data. */
169+
player.addEventListener('waiting', send);
170+
171+
/* "ended" is fired when playback or streaming has stopped because the
172+
* end of the media was reached or because no further data is
173+
* available. */
174+
player.addEventListener('ended', send);
175+
176+
/* "stalled" is fired when the user agent is trying to fetch media data,
177+
* but data is unexpectedly not forthcoming. */
178+
player.addEventListener('stalled', send);
179+
180+
/* "playing" is fired when playback is ready to start after having been
181+
* paused or delayed due to lack of data. */
182+
player.addEventListener('playing', send);
183+
184+
/* "pause" is fired when playback has been paused. */
185+
player.addEventListener('pause', send);
186+
187+
/* "play" is fired when playback has begun. */
188+
player.addEventListener('play', send);
189+
190+
/* "error" is fired when an error occurs. */
191+
player.addEventListener('error', error);
192+
});
193+
`
184194

185195
render() {
186196
return (
187197
<WebView
188198
ref={this.setRef}
189199
allowsInlineMediaPlayback={true}
190-
injectedJavaScript={this.js}
200+
injectedJavaScript={this.js()}
191201
mediaPlaybackRequiresUserAction={false}
192202
onMessage={this.handleMessage}
193-
source={{uri: kstoEmbed}}
203+
source={
204+
this.props.useEmbeddedPlayer
205+
? {uri: this.props.embeddedPlayerUrl}
206+
: {html: this.html(this.props.streamSourceUrl)}
207+
}
194208
style={this.props.style}
195209
/>
196210
)

0 commit comments

Comments
 (0)