Skip to content

Commit 0ad6b4c

Browse files
authored
Merge pull request #1174 from StoDevX/busview-cleanups
BusView cleanups
2 parents d1a843d + 1b1e45d commit 0ad6b4c

File tree

9 files changed

+443
-242
lines changed

9 files changed

+443
-242
lines changed

source/navigation.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
BuildingHoursProblemReportView,
2121
BuildingHoursScheduleEditorView,
2222
} from './views/building-hours'
23-
import TransportationView from './views/transportation'
23+
import TransportationView, {BusMapView} from './views/transportation'
2424
import SettingsView from './views/settings'
2525
import SISLoginView from './views/settings/login'
2626
import CreditsView from './views/settings/credits'
@@ -62,6 +62,7 @@ export const AppNavigator = StackNavigator(
6262
StudentOrgsDetailView: {screen: StudentOrgsDetailView},
6363
StudentOrgsView: {screen: StudentOrgsView},
6464
TransportationView: {screen: TransportationView},
65+
BusMapView: {screen: BusMapView},
6566
},
6667
{
6768
navigationOptions: {
Lines changed: 107 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
// @flow
22
import React from 'react'
3-
import {View, StyleSheet, Platform, Text} from 'react-native'
3+
import {View, Text, StyleSheet, Platform} from 'react-native'
44
import type {BusLineType, FancyBusTimeListType} from './types'
55
import {getScheduleForNow, getSetOfStopsForNow} from './lib'
66
import get from 'lodash/get'
77
import zip from 'lodash/zip'
88
import head from 'lodash/head'
99
import last from 'lodash/last'
10+
import Icon from 'react-native-vector-icons/Ionicons'
1011
import moment from 'moment-timezone'
1112
import * as c from '../../components/colors'
1213
import {Separator} from '../../components/separator'
1314
import {BusStopRow} from './bus-stop-row'
14-
import {ListRow, ListSectionHeader, Title} from '../../components/list'
15+
import {ListRow, ListSectionHeader, Title, Detail} from '../../components/list'
16+
import {Row, Column} from '../../components/layout'
1517

1618
const TIME_FORMAT = 'h:mma'
1719
const TIMEZONE = 'America/Winnipeg'
@@ -49,75 +51,114 @@ function makeSubtitle({now, moments, isLastBus}) {
4951
return lineDetail
5052
}
5153

52-
export function BusLine({line, now}: {line: BusLineType, now: moment}) {
53-
// grab the colors (with fallbacks) via _.get
54-
const barColor = get(barColors, line.line, c.black)
55-
const currentStopColor = get(stopColors, line.line, c.gray)
56-
const androidColor = Platform.OS === 'android' ? {color: barColor} : null
54+
const parseTime = (now: moment) => time => {
55+
// either pass `false` through or return a parsed time
56+
if (time === false) {
57+
return false
58+
}
59+
60+
return (
61+
moment
62+
// interpret in Central time
63+
.tz(time, TIME_FORMAT, true, TIMEZONE)
64+
// and set the date to today
65+
.dayOfYear(now.dayOfYear())
66+
)
67+
}
68+
69+
export class BusLine extends React.PureComponent {
70+
props: {line: BusLineType, now: moment, openMap: () => any}
71+
72+
render() {
73+
const {line, now} = this.props
74+
75+
// grab the colors (with fallbacks) via _.get
76+
const barColor = get(barColors, line.line, c.black)
77+
const currentStopColor = get(stopColors, line.line, c.gray)
78+
const androidColor = Platform.OS === 'android' ? {color: barColor} : null
79+
80+
const schedule = getScheduleForNow(line.schedules, now)
81+
if (!schedule) {
82+
return (
83+
<View>
84+
<ListSectionHeader title={line.line} titleStyle={androidColor} />
85+
<ListRow>
86+
<Title><Text>This line is not running today.</Text></Title>
87+
</ListRow>
88+
</View>
89+
)
90+
}
91+
92+
const scheduledMoments: FancyBusTimeListType[] = schedule.times.map(
93+
timeset => timeset.map(parseTime(now)),
94+
)
95+
96+
const moments: FancyBusTimeListType = getSetOfStopsForNow(
97+
scheduledMoments,
98+
now,
99+
)
100+
const pairs: [[string, moment]] = zip(schedule.stops, moments)
101+
102+
const timesIndex = scheduledMoments.indexOf(moments)
103+
const isLastBus = timesIndex === scheduledMoments.length - 1
104+
const subtitle = makeSubtitle({now, moments, isLastBus})
57105

58-
const schedule = getScheduleForNow(line.schedules, now)
59-
if (!schedule) {
60106
return (
61107
<View>
62-
<ListSectionHeader title={line.line} titleStyle={androidColor} />
63-
<ListRow>
64-
<Title><Text>This line is not running today.</Text></Title>
65-
</ListRow>
66-
</View>
67-
)
68-
}
108+
<ListSectionHeader
109+
title={line.line}
110+
subtitle={subtitle}
111+
titleStyle={androidColor}
112+
/>
69113

70-
const scheduledMoments: FancyBusTimeListType[] = schedule.times.map(
71-
timeset => {
72-
return timeset.map(
73-
time =>
74-
time === false
75-
? // either pass `false` through or return a parsed time
76-
false
77-
: moment
78-
// interpret in Central time
79-
.tz(time, TIME_FORMAT, true, TIMEZONE)
80-
// and set the date to today
81-
.dayOfYear(now.dayOfYear()),
82-
)
83-
},
84-
)
114+
{pairs.map(([placeTitle, moment], i, list) =>
115+
<View key={i}>
116+
<BusStopRow
117+
// get the arrival time for this stop from each bus loop after
118+
// the current time (as given by `now`)
119+
times={scheduledMoments.slice(timesIndex).map(set => set[i])}
120+
place={placeTitle}
121+
now={now}
122+
time={moment}
123+
barColor={barColor}
124+
currentStopColor={currentStopColor}
125+
isFirstRow={i === 0}
126+
isLastRow={i === list.length - 1}
127+
/>
128+
<Separator style={styles.separator} />
129+
</View>,
130+
)}
85131

86-
const moments: FancyBusTimeListType = getSetOfStopsForNow(
87-
scheduledMoments,
88-
now,
89-
)
90-
const pairs: [[string, moment]] = zip(schedule.stops, moments)
132+
<ListRow
133+
onPress={this.props.openMap}
134+
fullWidth={true}
135+
spacing={{left: 45}}
136+
>
137+
<Row alignItems="center">
138+
<Column alignItems="center" width={45} paddingRight={5}>
139+
<Icon
140+
name={
141+
Platform.OS === 'ios'
142+
? 'ios-navigate-outline'
143+
: 'md-navigate'
144+
}
145+
size={24}
146+
style={{color: c.iosDisabledText}}
147+
/>
148+
</Column>
91149

92-
const timesIndex = scheduledMoments.indexOf(moments)
93-
const isLastBus = timesIndex === scheduledMoments.length - 1
94-
const subtitle = makeSubtitle({now, moments, isLastBus})
150+
<Column>
151+
<Title>
152+
<Text>Open Map</Text>
153+
</Title>
95154

96-
return (
97-
<View>
98-
<ListSectionHeader
99-
title={line.line}
100-
subtitle={subtitle}
101-
titleStyle={androidColor}
102-
/>
103-
104-
{pairs.map(([placeTitle, moment], i, list) =>
105-
<View key={i}>
106-
<BusStopRow
107-
// get the arrival time for this stop from each bus loop after
108-
// the current time (as given by `now`)
109-
times={scheduledMoments.slice(timesIndex).map(set => set[i])}
110-
place={placeTitle}
111-
now={now}
112-
time={moment}
113-
barColor={barColor}
114-
currentStopColor={currentStopColor}
115-
isFirstRow={i === 0}
116-
isLastRow={i === list.length - 1}
117-
/>
118-
{i < list.length - 1 ? <Separator style={styles.separator} /> : null}
119-
</View>,
120-
)}
121-
</View>
122-
)
155+
<Detail>
156+
<Text>See the planned bus route on a map!</Text>
157+
</Detail>
158+
</Column>
159+
</Row>
160+
</ListRow>
161+
</View>
162+
)
163+
}
123164
}

source/views/transportation/bus/bus-stop-row.js

Lines changed: 80 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -26,79 +26,88 @@ const styles = StyleSheet.create({
2626
},
2727
})
2828

29-
export function BusStopRow({
30-
time,
31-
now,
32-
barColor,
33-
currentStopColor,
34-
place,
35-
times,
36-
isFirstRow,
37-
isLastRow,
38-
}: {
39-
time: moment,
40-
now: moment,
41-
barColor: string,
42-
currentStopColor: string,
43-
place: string,
44-
times: FancyBusTimeListType,
45-
isFirstRow: boolean,
46-
isLastRow: boolean,
47-
}) {
48-
const afterStop = time && now.isAfter(time, 'minute')
49-
const atStop = time && now.isSame(time, 'minute')
50-
const beforeStop = !afterStop && !atStop && time !== false
51-
const skippingStop = time === false
29+
export class BusStopRow extends React.PureComponent {
30+
props: {
31+
time: moment,
32+
now: moment,
33+
barColor: string,
34+
currentStopColor: string,
35+
place: string,
36+
times: FancyBusTimeListType,
37+
isFirstRow: boolean,
38+
isLastRow: boolean,
39+
}
5240

53-
return (
54-
<ListRow fullWidth={true} fullHeight={true}>
55-
<Row>
56-
<ProgressChunk
57-
{...{
58-
barColor,
59-
afterStop,
60-
beforeStop,
61-
atStop,
62-
skippingStop,
63-
currentStopColor,
64-
}}
65-
isFirstChunk={isFirstRow}
66-
isLastChunk={isLastRow}
67-
/>
41+
render() {
42+
const {
43+
time,
44+
now,
45+
barColor,
46+
currentStopColor,
47+
place,
48+
times,
49+
isFirstRow,
50+
isLastRow,
51+
} = this.props
6852

69-
<Column flex={1} style={styles.internalPadding}>
70-
<Title
71-
bold={false}
72-
style={[
73-
skippingStop && styles.skippingStopTitle,
74-
afterStop && styles.passedStopTitle,
75-
atStop && styles.atStopTitle,
76-
]}
77-
>
78-
{place}
79-
</Title>
80-
<Detail lines={1}>
81-
<ScheduleTimes {...{times, skippingStop}} />
82-
</Detail>
83-
</Column>
84-
</Row>
85-
</ListRow>
86-
)
53+
const afterStop = time && now.isAfter(time, 'minute')
54+
const atStop = time && now.isSame(time, 'minute')
55+
const beforeStop = !afterStop && !atStop && time !== false
56+
const skippingStop = time === false
57+
58+
return (
59+
<ListRow fullWidth={true} fullHeight={true}>
60+
<Row>
61+
<ProgressChunk
62+
{...{
63+
barColor,
64+
afterStop,
65+
beforeStop,
66+
atStop,
67+
skippingStop,
68+
currentStopColor,
69+
}}
70+
isFirstChunk={isFirstRow}
71+
isLastChunk={isLastRow}
72+
/>
73+
74+
<Column flex={1} style={styles.internalPadding}>
75+
<Title
76+
bold={false}
77+
style={[
78+
skippingStop && styles.skippingStopTitle,
79+
afterStop && styles.passedStopTitle,
80+
atStop && styles.atStopTitle,
81+
]}
82+
>
83+
{place}
84+
</Title>
85+
<Detail lines={1}>
86+
<ScheduleTimes {...{times, skippingStop}} />
87+
</Detail>
88+
</Column>
89+
</Row>
90+
</ListRow>
91+
)
92+
}
8793
}
8894

89-
const ScheduleTimes = ({
90-
times,
91-
skippingStop,
92-
}: {
93-
skippingStop: boolean,
94-
times: FancyBusTimeListType,
95-
}) => {
96-
return (
97-
<Text style={skippingStop && styles.skippingStopDetail}>
98-
{times
99-
// and format the times
100-
.map(time => (time === false ? 'None' : time.format(TIME_FORMAT)))
101-
.join(' • ')}
102-
</Text>
103-
)
95+
class ScheduleTimes extends React.PureComponent {
96+
props: {
97+
skippingStop: boolean,
98+
times: FancyBusTimeListType,
99+
}
100+
101+
render() {
102+
const {times, skippingStop} = this.props
103+
104+
return (
105+
<Text style={skippingStop && styles.skippingStopDetail}>
106+
{times
107+
// and format the times
108+
.map(time => (time === false ? 'None' : time.format(TIME_FORMAT)))
109+
.join(' • ')}
110+
</Text>
111+
)
112+
}
104113
}

0 commit comments

Comments
 (0)