|
1 |
| -/** |
2 |
| - * Sample React Native App |
3 |
| - * https://github.com/facebook/react-native |
4 |
| - * |
5 |
| - * @format |
6 |
| - * @flow |
7 |
| - */ |
| 1 | +import React, { Component } from 'react'; |
| 2 | +import { FlatList, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; |
| 3 | +import { BrightcovePlayer, BrightcovePlayerPoster, BrightcovePlayerUtil } from 'react-native-brightcove-player'; |
8 | 4 |
|
9 |
| -import React from 'react'; |
10 |
| -import { |
11 |
| - SafeAreaView, |
12 |
| - StyleSheet, |
13 |
| - ScrollView, |
14 |
| - View, |
15 |
| - Text, |
16 |
| - StatusBar, |
17 |
| -} from 'react-native'; |
| 5 | +const ACCOUNT_ID = '5434391461001'; |
| 6 | +const POLICY_KEY = |
| 7 | + 'BCpkADawqM0T8lW3nMChuAbrcunBBHmh4YkNl5e6ZrKQwPiK_Y83RAOF4DP5tyBF_ONBVgrEjqW6fbV0nKRuHvjRU3E8jdT9WMTOXfJODoPML6NUDCYTwTHxtNlr5YdyGYaCPLhMUZ3Xu61L'; |
| 8 | +const PLAYLIST_REF_ID = 'brightcove-native-sdk-plist'; |
18 | 9 |
|
19 |
| -import { |
20 |
| - Header, |
21 |
| - LearnMoreLinks, |
22 |
| - Colors, |
23 |
| - DebugInstructions, |
24 |
| - ReloadInstructions, |
25 |
| -} from 'react-native/Libraries/NewAppScreen'; |
| 10 | +export default class App extends Component { |
| 11 | + state = { |
| 12 | + videos: [], |
| 13 | + offlineVideos: [], |
| 14 | + playback: { |
| 15 | + referenceId: null, |
| 16 | + videoToken: null |
| 17 | + } |
| 18 | + }; |
26 | 19 |
|
27 |
| -const App: () => React$Node = () => { |
28 |
| - return ( |
29 |
| - <> |
30 |
| - <StatusBar barStyle="dark-content" /> |
31 |
| - <SafeAreaView> |
32 |
| - <ScrollView |
33 |
| - contentInsetAdjustmentBehavior="automatic" |
34 |
| - style={styles.scrollView}> |
35 |
| - <Header /> |
36 |
| - {global.HermesInternal == null ? null : ( |
37 |
| - <View style={styles.engine}> |
38 |
| - <Text style={styles.footer}>Engine: Hermes</Text> |
39 |
| - </View> |
40 |
| - )} |
41 |
| - <View style={styles.body}> |
42 |
| - <View style={styles.sectionContainer}> |
43 |
| - <Text style={styles.sectionTitle}>Step One</Text> |
44 |
| - <Text style={styles.sectionDescription}> |
45 |
| - Edit <Text style={styles.highlight}>App.js</Text> to change this |
46 |
| - screen and then come back to see your edits. |
47 |
| - </Text> |
48 |
| - </View> |
49 |
| - <View style={styles.sectionContainer}> |
50 |
| - <Text style={styles.sectionTitle}>See Your Changes</Text> |
51 |
| - <Text style={styles.sectionDescription}> |
52 |
| - <ReloadInstructions /> |
53 |
| - </Text> |
54 |
| - </View> |
55 |
| - <View style={styles.sectionContainer}> |
56 |
| - <Text style={styles.sectionTitle}>Debug</Text> |
57 |
| - <Text style={styles.sectionDescription}> |
58 |
| - <DebugInstructions /> |
59 |
| - </Text> |
60 |
| - </View> |
61 |
| - <View style={styles.sectionContainer}> |
62 |
| - <Text style={styles.sectionTitle}>Learn More</Text> |
63 |
| - <Text style={styles.sectionDescription}> |
64 |
| - Read the docs to discover what to do next: |
65 |
| - </Text> |
66 |
| - </View> |
67 |
| - <LearnMoreLinks /> |
68 |
| - </View> |
69 |
| - </ScrollView> |
70 |
| - </SafeAreaView> |
71 |
| - </> |
72 |
| - ); |
73 |
| -}; |
| 20 | + componentDidMount() { |
| 21 | + BrightcovePlayerUtil.getPlaylistWithReferenceId( |
| 22 | + ACCOUNT_ID, |
| 23 | + POLICY_KEY, |
| 24 | + PLAYLIST_REF_ID |
| 25 | + ) |
| 26 | + .then(videos => { |
| 27 | + this.setState({ |
| 28 | + videos |
| 29 | + }); |
| 30 | + }) |
| 31 | + .catch(console.warn); |
| 32 | + BrightcovePlayerUtil.getOfflineVideoStatuses(ACCOUNT_ID, POLICY_KEY) |
| 33 | + .then(offlineVideos => { |
| 34 | + this.setState({ |
| 35 | + offlineVideos |
| 36 | + }); |
| 37 | + }) |
| 38 | + .catch(console.warn); |
| 39 | + this.disposer = BrightcovePlayerUtil.addOfflineNotificationListener( |
| 40 | + offlineVideos => { |
| 41 | + this.setState({ |
| 42 | + offlineVideos |
| 43 | + }); |
| 44 | + } |
| 45 | + ); |
| 46 | + } |
| 47 | + |
| 48 | + requestDownload(videoId) { |
| 49 | + BrightcovePlayerUtil.requestDownloadVideoWithVideoId( |
| 50 | + ACCOUNT_ID, |
| 51 | + POLICY_KEY, |
| 52 | + videoId |
| 53 | + ).catch(() => {}); |
| 54 | + } |
| 55 | + |
| 56 | + play(item) { |
| 57 | + const downloadStatus = this.state.offlineVideos.find( |
| 58 | + video => video.videoId === item.videoId |
| 59 | + ); |
| 60 | + this.setState({ |
| 61 | + playback: |
| 62 | + downloadStatus && downloadStatus.downloadProgress === 1 |
| 63 | + ? { |
| 64 | + videoToken: downloadStatus.videoToken |
| 65 | + } |
| 66 | + : { |
| 67 | + referenceId: item.referenceId |
| 68 | + } |
| 69 | + }); |
| 70 | + } |
| 71 | + |
| 72 | + delete(videoToken) { |
| 73 | + BrightcovePlayerUtil.deleteOfflineVideo( |
| 74 | + ACCOUNT_ID, |
| 75 | + POLICY_KEY, |
| 76 | + videoToken |
| 77 | + ).catch(console.warn); |
| 78 | + } |
| 79 | + |
| 80 | + componentWillUnmount() { |
| 81 | + this.disposer && this.disposer(); |
| 82 | + } |
| 83 | + |
| 84 | + render() { |
| 85 | + return ( |
| 86 | + <View style={styles.container}> |
| 87 | + <StatusBar barStyle="light-content" /> |
| 88 | + <BrightcovePlayer |
| 89 | + style={styles.video} |
| 90 | + accountId={ACCOUNT_ID} |
| 91 | + policyKey={POLICY_KEY} |
| 92 | + autoPlay |
| 93 | + {...this.state.playback} |
| 94 | + /> |
| 95 | + <FlatList |
| 96 | + style={styles.list} |
| 97 | + extraData={this.state.offlineVideos} |
| 98 | + data={this.state.videos} |
| 99 | + keyExtractor={item => item.referenceId} |
| 100 | + renderItem={({ item }) => { |
| 101 | + const downloadStatus = this.state.offlineVideos.find( |
| 102 | + video => video.videoId === item.videoId |
| 103 | + ); |
| 104 | + return ( |
| 105 | + <View style={styles.listItem}> |
| 106 | + <TouchableOpacity |
| 107 | + style={styles.mainButton} |
| 108 | + onPress={() => this.play(item)} |
| 109 | + > |
| 110 | + <BrightcovePlayerPoster |
| 111 | + style={styles.poster} |
| 112 | + accountId={ACCOUNT_ID} |
| 113 | + policyKey={POLICY_KEY} |
| 114 | + referenceId={item.referenceId} |
| 115 | + /> |
| 116 | + <View style={styles.body}> |
| 117 | + <Text style={styles.name}>{item.name}</Text> |
| 118 | + <Text>{item.description}</Text> |
| 119 | + {downloadStatus ? ( |
| 120 | + <Text style={styles.offlineBanner}> |
| 121 | + {downloadStatus.downloadProgress === 1 |
| 122 | + ? 'OFFLINE PLAYBACK' |
| 123 | + : `DOWNLOADING: ${Math.floor( |
| 124 | + downloadStatus.downloadProgress * 100 |
| 125 | + )}%`} |
| 126 | + </Text> |
| 127 | + ) : null} |
| 128 | + <Text style={styles.duration}> |
| 129 | + {`0${Math.floor(item.duration / 60000) % 60}`.substr(-2)}: |
| 130 | + {`0${Math.floor(item.duration / 1000) % 60}`.substr(-2)} |
| 131 | + </Text> |
| 132 | + </View> |
| 133 | + </TouchableOpacity> |
| 134 | + <TouchableOpacity |
| 135 | + style={styles.downloadButton} |
| 136 | + onPress={() => { |
| 137 | + if (!downloadStatus) { |
| 138 | + this.requestDownload(item.videoId); |
| 139 | + } else { |
| 140 | + this.delete(downloadStatus.videoToken); |
| 141 | + } |
| 142 | + }} |
| 143 | + > |
| 144 | + <Text> |
| 145 | + {!downloadStatus |
| 146 | + ? '💾' |
| 147 | + : downloadStatus.downloadProgress === 1 |
| 148 | + ? '🗑' |
| 149 | + : '⏳'} |
| 150 | + </Text> |
| 151 | + </TouchableOpacity> |
| 152 | + </View> |
| 153 | + ); |
| 154 | + }} |
| 155 | + /> |
| 156 | + </View> |
| 157 | + ); |
| 158 | + } |
| 159 | +} |
74 | 160 |
|
75 | 161 | const styles = StyleSheet.create({
|
76 |
| - scrollView: { |
77 |
| - backgroundColor: Colors.lighter, |
| 162 | + container: { |
| 163 | + flex: 1, |
| 164 | + flexDirection: 'column' |
78 | 165 | },
|
79 |
| - engine: { |
80 |
| - position: 'absolute', |
81 |
| - right: 0, |
| 166 | + video: { |
| 167 | + width: '100%', |
| 168 | + height: 260 |
82 | 169 | },
|
83 |
| - body: { |
84 |
| - backgroundColor: Colors.white, |
| 170 | + list: { |
| 171 | + flex: 1 |
| 172 | + }, |
| 173 | + listItem: { |
| 174 | + flexDirection: 'row', |
| 175 | + borderBottomWidth: 1, |
| 176 | + borderBottomColor: 'lightgray' |
85 | 177 | },
|
86 |
| - sectionContainer: { |
87 |
| - marginTop: 32, |
88 |
| - paddingHorizontal: 24, |
| 178 | + mainButton: { |
| 179 | + flex: 1, |
| 180 | + flexDirection: 'row' |
89 | 181 | },
|
90 |
| - sectionTitle: { |
91 |
| - fontSize: 24, |
92 |
| - fontWeight: '600', |
93 |
| - color: Colors.black, |
| 182 | + body: { |
| 183 | + flex: 1, |
| 184 | + padding: 10, |
| 185 | + flexDirection: 'column' |
94 | 186 | },
|
95 |
| - sectionDescription: { |
96 |
| - marginTop: 8, |
97 |
| - fontSize: 18, |
98 |
| - fontWeight: '400', |
99 |
| - color: Colors.dark, |
| 187 | + name: { |
| 188 | + fontSize: 14, |
| 189 | + fontWeight: 'bold' |
100 | 190 | },
|
101 |
| - highlight: { |
102 |
| - fontWeight: '700', |
| 191 | + offlineBanner: { |
| 192 | + fontSize: 10, |
| 193 | + fontWeight: 'bold', |
| 194 | + color: 'white', |
| 195 | + alignSelf: 'flex-start', |
| 196 | + padding: 3, |
| 197 | + backgroundColor: 'deepskyblue' |
103 | 198 | },
|
104 |
| - footer: { |
105 |
| - color: Colors.dark, |
106 |
| - fontSize: 12, |
107 |
| - fontWeight: '600', |
108 |
| - padding: 4, |
109 |
| - paddingRight: 12, |
110 |
| - textAlign: 'right', |
| 199 | + duration: { |
| 200 | + marginTop: 'auto', |
| 201 | + opacity: 0.5 |
111 | 202 | },
|
| 203 | + poster: { |
| 204 | + width: 100, |
| 205 | + height: 100, |
| 206 | + backgroundColor: 'black' |
| 207 | + }, |
| 208 | + downloadButton: { |
| 209 | + padding: 16, |
| 210 | + marginLeft: 'auto', |
| 211 | + alignSelf: 'center' |
| 212 | + } |
112 | 213 | });
|
113 |
| - |
114 |
| -export default App; |
|
0 commit comments