55 */
66
77import React from 'react'
8- import { StyleSheet , View , Text , FlatList , Image , Platform } from 'react-native'
8+ import {
9+ StyleSheet ,
10+ View ,
11+ Text ,
12+ ScrollView ,
13+ Image ,
14+ Platform ,
15+ Dimensions ,
16+ } from 'react-native'
917import delay from 'delay'
1018import { reportNetworkProblem } from '../../lib/report-network-problem'
1119import { TabBarIcon } from '../components/tabbar-icon'
@@ -15,6 +23,8 @@ import * as defaultData from '../../../docs/webcams.json'
1523import { webcamImages } from '../../../images/webcam-images'
1624import { trackedOpenUrl } from '../components/open-url'
1725import LinearGradient from 'react-native-linear-gradient'
26+ import { Column } from '../components/layout'
27+ import { partitionByIndex } from '../../lib/partition-by-index'
1828
1929const transparentPixel = require ( '../../../images/transparent.png' )
2030const GITHUB_URL = 'https://stodevx.github.io/AAO-React-Native/webcams.json'
@@ -32,6 +42,7 @@ type WebcamType = {
3242type Props = { }
3343
3444type State = {
45+ width : number ,
3546 webcams : Array < WebcamType > ,
3647 loading : boolean ,
3748 refreshing : boolean ,
@@ -44,15 +55,25 @@ export class WebcamsView extends React.PureComponent<void, Props, State> {
4455 }
4556
4657 state = {
58+ width : Dimensions . get ( 'window' ) . width ,
4759 webcams : defaultData . data ,
4860 loading : false ,
4961 refreshing : false ,
5062 }
5163
5264 componentWillMount ( ) {
65+ Dimensions . addEventListener ( 'change' , this . handleResizeEvent )
5366 this . fetchData ( )
5467 }
5568
69+ componentWillUnmount ( ) {
70+ Dimensions . removeEventListener ( 'change' , this . handleResizeEvent )
71+ }
72+
73+ handleResizeEvent = ( event : { window : { width : number } } ) => {
74+ this . setState ( ( ) => ( { width : event . window . width } ) )
75+ }
76+
5677 refresh = async ( ) => {
5778 const start = Date . now ( )
5879 this . setState ( ( ) => ( { refreshing : true } ) )
@@ -83,32 +104,33 @@ export class WebcamsView extends React.PureComponent<void, Props, State> {
83104 this . setState ( ( ) => ( { webcams, loading : false } ) )
84105 }
85106
86- renderItem = ( { item} : { item : WebcamType } ) = >
87- < StreamThumbnail key = { item . name } webcam = { item } />
88-
89- keyExtractor = ( item : WebcamType ) => item . name
90-
91107 render ( ) {
108+ const columns = partitionByIndex ( this . state . webcams )
109+
92110 return (
93- < FlatList
94- keyExtractor = { this . keyExtractor }
95- renderItem = { this . renderItem }
96- refreshing = { this . state . refreshing }
97- onRefresh = { this . refresh }
98- data = { this . state . webcams }
99- numColumns = { 2 }
100- columnWrapperStyle = { styles . row }
101- contentContainerStyle = { styles . container }
102- />
111+ < ScrollView contentContainerStyle = { styles . container } >
112+ { columns . map ( ( contents , i ) =>
113+ < Column key = { i } style = { styles . column } >
114+ { contents . map ( webcam =>
115+ < StreamThumbnail
116+ key = { webcam . name }
117+ webcam = { webcam }
118+ viewportWidth = { this . state . width }
119+ /> ,
120+ ) }
121+ </ Column > ,
122+ ) }
123+ </ ScrollView >
103124 )
104125 }
105126}
106127
107- class StreamThumbnail extends React . PureComponent {
108- props: {
109- webcam : WebcamType ,
110- }
128+ type ThumbnailProps = {
129+ webcam : WebcamType ,
130+ viewportWidth : number ,
131+ }
111132
133+ class StreamThumbnail extends React . PureComponent < void , ThumbnailProps , void > {
112134 handlePress = ( ) => {
113135 const { streamUrl, name, pageUrl} = this . props . webcam
114136 if ( Platform . OS === 'ios' ) {
@@ -121,18 +143,17 @@ class StreamThumbnail extends React.PureComponent {
121143 }
122144
123145 render ( ) {
124- const {
125- name,
126- thumbnail,
127- accentColor,
128- textColor,
129- thumbnailUrl,
130- } = this . props . webcam
146+ const { viewportWidth , webcam} = this . props
147+ const { name , thumbnail , accentColor , textColor , thumbnailUrl } = webcam
131148
132149 const [ r , g , b ] = accentColor
133150 const baseColor = `rgba(${ r } , ${ g } , ${ b } , 1)`
134151 const startColor = `rgba(${ r } , ${ g } , ${ b } , 0.1)`
135152
153+ const width = viewportWidth / 2 - CELL_MARGIN * 1.5
154+ const cellRatio = 2.15625
155+ const height = width / cellRatio
156+
136157 const img = thumbnailUrl
137158 ? { uri : thumbnailUrl }
138159 : webcamImages . hasOwnProperty ( thumbnail )
@@ -145,9 +166,8 @@ class StreamThumbnail extends React.PureComponent {
145166 underlayColor = { baseColor }
146167 activeOpacity = { 0.7 }
147168 onPress = { this . handlePress }
148- containerStyle = { styles . cell }
149169 >
150- < Image source = { img } style = { styles . image } >
170+ < Image source = { img } style = { [ styles . image , { width , height } ] } >
151171 < View style = { styles . titleWrapper } >
152172 < LinearGradient
153173 colors = { [ startColor , baseColor ] }
@@ -168,27 +188,16 @@ const CELL_MARGIN = 10
168188
169189const styles = StyleSheet . create ( {
170190 container : {
171- marginVertical : CELL_MARGIN / 2 ,
191+ padding : CELL_MARGIN / 2 ,
192+ flexDirection : 'row' ,
172193 } ,
173- row : {
174- justifyContent : 'center' ,
175- marginHorizontal : CELL_MARGIN / 2 ,
176- } ,
177- cell : {
194+ column : {
178195 flex : 1 ,
179- overflow : 'hidden' ,
180- margin : CELL_MARGIN / 2 ,
181- justifyContent : 'center' ,
182-
183- elevation : 2 ,
184-
185- // TODO: Android doesn't currently (0.42) respect both
186- // overflow:hidden and border-radius.
187- borderRadius : Platform . OS === 'android' ? 0 : 6 ,
196+ alignItems : 'center' ,
188197 } ,
189198 image : {
190- width : '100%' ,
191- height : '100%' ,
199+ margin : CELL_MARGIN / 2 ,
200+ borderRadius : 6 ,
192201 } ,
193202 titleWrapper : {
194203 flex : 1 ,
0 commit comments