diff options
Diffstat (limited to 'src/Components')
-rw-r--r-- | src/Components/Login.tsx | 20 | ||||
-rw-r--r-- | src/Components/Map.tsx | 121 | ||||
-rw-r--r-- | src/Components/MapObjects.tsx | 114 | ||||
-rw-r--r-- | src/Components/MapOverlay.tsx | 130 | ||||
-rw-r--r-- | src/Components/PortalPanel.tsx | 50 | ||||
-rw-r--r-- | src/Components/Settings.tsx | 46 |
6 files changed, 259 insertions, 222 deletions
diff --git a/src/Components/Login.tsx b/src/Components/Login.tsx index 6fe7957..fe20e09 100644 --- a/src/Components/Login.tsx +++ b/src/Components/Login.tsx @@ -8,20 +8,13 @@ import actions from '../Actions/actions'; const LOGIN_URL = "https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https://appengine.google.com/_ah/conflogin%3Fcontinue%3Dhttps://intel.ingress.com/"; const HOME_URL = "https://intel.ingress.com/"; -var styles = StyleSheet.create({ - container: { - flexGrow: 1, - } -}); - type Props = { - login(csrf: string, v: string): void + login(): void actions: any auth: any } type State = { - v: string onIngress: boolean } @@ -29,7 +22,7 @@ class Login extends Component<Props, State> { webview!: WebView; constructor(props: Props) { super(props); - this.state = { v: "", onIngress: false } + this.state = { onIngress: false } } onNavigationStateChange(navState: WebViewNavigation) { @@ -47,7 +40,7 @@ class Login extends Component<Props, State> { <> <WebView ref={r => r && (this.webview = r)} - automaticallyAdjustContentInsets={false} + automaticallyAdjustContentInsets={true} thirdPartyCookiesEnabled useWebKit style={styles.container} @@ -68,4 +61,11 @@ class Login extends Component<Props, State> { } } +var styles = StyleSheet.create({ + container: { + flex: 1, + } +}); + + export default connect({ 'auth': 'auth' }, actions)(Login)
\ No newline at end of file diff --git a/src/Components/Map.tsx b/src/Components/Map.tsx index 3e878f8..68698f4 100644 --- a/src/Components/Map.tsx +++ b/src/Components/Map.tsx @@ -20,67 +20,64 @@ const draggableRange = { type Props = any type State = any class Map extends Component<Props, State> { - refresh: number | undefined + static navigationOptions = ({ navigation }) => { + return { + title: 'Карта', + }; + }; + refreshTimer: number | undefined map!: MapView; constructor(props: Props) { super(props) this.state = { user: undefined, - followUser: true, - zoom: 15, region: null, - loading: false, - objects: { links: {}, fields: {}, portals: {}, loaded: false }, } } + componentDidMount() { + this.refreshTimer = setInterval(() => { + this.refresh() + }, 30000) + } + componentWillUnmount() { + clearInterval(this.refreshTimer) + } componentWillMount() { + const setPosition = (position) => { + this.setState({ + user: { + latitude: position.coords.latitude, + longitude: position.coords.longitude + }, + }); + } navigator.geolocation.getCurrentPosition( - position => { - this.setState({ - followUser: true, - }); - }, + setPosition, error => alert(error.message), { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } ); navigator.geolocation.watchPosition( - position => { - this.setState({ - user: { - latitude: position.coords.latitude, - longitude: position.coords.longitude - }, - }); - }, + setPosition, error => alert(error.message), { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } ) } onRegionChange = (region: Region) => { - const zoom = this.getZoomByRegion(width, region) - this.setState({ region, zoom }) + this.setState({ region }) setImmediate(() => this.load(false)) } - getZoomByRegion(width: number, region: Region): number { - return Math.ceil(Math.log2(360 * ((width / 256) / region.longitudeDelta))) + 1 + + refresh = () => { + setImmediate(() => this.load(true)) } + load = async (refresh: boolean) => { - if (this.state.region != null && this.props.entities.loading == 0) { + if (this.state.region != null) { this.props.actions.update(this.state.region, width, refresh) } return null } - refreshByTime = () => { - setTimeout(() => { - this.load(true).then(this.refreshByTime) - }, 30000) - } - - componentDidMount() { - this.refreshByTime() - } - onPortalClick = (guid: string, coords: LatLng) => { this.setState({ selectedPortal: { guid, coords } }) } @@ -93,23 +90,15 @@ class Map extends Component<Props, State> { this.props.navigation.dispatch(navigateAction); } + goToMe = () => { + this.map.animateToCoordinate(this.state.user) + } + render() { if (!this.state.user) { return <View style={styles.spinnerContainer}><ActivityIndicator size={'large'} /></View> } - const camera = { - center: this.state.user, - altitude: 1000, - heading: 0, - pitch: 30, - zoom: 15, - } - const goToMe = () => { - this.map.animateToCoordinate(this.state.user) - } - const refresh = () => { - setImmediate(() => this.load(true)) - } + return ( <> <MapView @@ -124,13 +113,13 @@ class Map extends Component<Props, State> { loadingEnabled type={'hybrid'} > - <MapObjects onPortalClick={this.onPortalClick} zoom={this.state.zoom} /> + <MapObjects onPortalClick={this.onPortalClick} /> {this.state.selectedPortal && <Marker coordinate={this.state.selectedPortal.coords} />} </MapView> <MapOverlay - goToMe={goToMe} - refresh={refresh} - loading={this.props.entities.loading} + goToMe={this.goToMe} + refresh={this.refresh} + loading={this.props.entities.loadQueue.length} selectedPortal={this.state.selectedPortal} onOpenPortal={this.onOpenPortal} /> @@ -143,38 +132,6 @@ const styles = StyleSheet.create({ container: { flex: 1, }, - spinnerContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - panel: { - flex: 1, - backgroundColor: '#fff', - position: 'relative', - borderTopLeftRadius: 20, - borderTopRightRadius: 20, - //ios - shadowOpacity: 0.3, - shadowRadius: 3, - shadowOffset: { - height: 0, - width: 0 - }, - //android - elevation: 1 - }, - panelHeader: { - height: 40, - alignItems: 'center', - justifyContent: 'center', - }, - dash: { - backgroundColor: 'rgba(200,200,200,0.9)', - height: 6, - width: 30, - borderRadius: 3 - } }); export default connect({ 'entities': 'entities' }, actions)(Map)
\ No newline at end of file diff --git a/src/Components/MapObjects.tsx b/src/Components/MapObjects.tsx index 1d2fb12..af0afec 100644 --- a/src/Components/MapObjects.tsx +++ b/src/Components/MapObjects.tsx @@ -1,4 +1,4 @@ -import React, { ReactChild } from 'react'; +import React, { PureComponent } from 'react'; import { View, StyleSheet, Text } from 'react-native'; import { Polyline, Polygon, Marker, Region } from 'react-native-maps'; import Icon from 'react-native-vector-icons/FontAwesome'; @@ -17,74 +17,64 @@ type Props = { links: { [guid: string]: Link } fields: { [guid: string]: Field } onPortalClick: Function - zoom: number } -const MapObjects = (props: Props) => { - const renderPortal = Object.keys(props.portals).map(guid => drawPortal(guid, props.portals[guid], props.zoom, props.onPortalClick)) - const renderField = Object.keys(props.fields).map(guid => drawField(guid, props.fields[guid])) - const renderLink = Object.keys(props.links).map(guid => drawLink(guid, props.links[guid])) +class MapObjects extends PureComponent<Props> { + render() { + const props = this.props + const renderPortal = Object.keys(props.portals).map(guid => this.drawPortal(guid, props.portals[guid], props.onPortalClick)) + const renderField = Object.keys(props.fields).map(guid => this.drawField(guid, props.fields[guid])) + const renderLink = Object.keys(props.links).map(guid => this.drawLink(guid, props.links[guid])) - if (props.zoom <= 14) { - return [...renderField, ...renderLink] - } else { - return [...renderField, ...renderLink, ...renderPortal] + if (props.zoom <= 14) { + return [...renderField, ...renderLink] + } else { + return [...renderField, ...renderLink, ...renderPortal] + } + } + drawPortal = (guid: string, entity: Portal, onPortalClick: Function) => { + const size = 20 + return (<Marker + key={guid} + coordinate={entity.coords} + onPress={() => onPortalClick(guid, entity.coords)} + > + {/* <Icon name={entity.fraction == "N" ? "circle-o" : "circle"} color={fillPortalColor[entity.fraction]} size={size} /> */} + <View style={{ + borderWidth: 2, + height: size, + width: size, + borderRadius: size / 2, + borderColor: COLORS_LVL[entity.level], + backgroundColor: fillPortalColor[entity.fraction], + justifyContent: 'center', + alignItems: 'center', + }}> + <Text style={{ fontWeight: 'bold' }}>{entity.level}</Text> + </View> + </Marker>); + } + drawField = (guid: string, entity: Field) => { + return <Polygon + key={guid} + coordinates={entity.coords} + fillColor={fieldColor[entity.fraction]} + strokeColor={fieldColor[entity.fraction]} + strokeWidth={StyleSheet.hairlineWidth} + /> + } + drawLink = (guid: string, entity: Link) => { + return <Polyline + key={guid} + coordinates={entity.coords} + strokeColor={fractColor[entity.fraction]} + strokeWidth={1} + /> } -} -const drawPortal = (guid: string, entity: Portal, zoom: number, onPortalClick: Function) => { - const size = (zoom) * 1.5 - return (<Marker - key={guid} - coordinate={entity.coords} - onPress={() => onPortalClick(guid, entity.coords)} - > - {/* <Icon name={entity.fraction == "N" ? "circle-o" : "circle"} color={fillPortalColor[entity.fraction]} size={size} /> */} - <View style={{ - borderWidth: 2, - height: size, - width: size, - borderRadius: size / 2, - borderColor: COLORS_LVL[entity.level], - backgroundColor: fillPortalColor[entity.fraction], - justifyContent: 'center', - alignItems: 'center', - }}> - <Text style={{ fontWeight: 'bold' }}>{entity.level}</Text> - </View> - </Marker>); -} -const drawField = (guid: string, entity: Field) => { - return <Polygon - key={guid} - coordinates={entity.coords} - fillColor={fieldColor[entity.fraction]} - strokeColor={fieldColor[entity.fraction]} - strokeWidth={StyleSheet.hairlineWidth} - /> -} -const drawLink = (guid: string, entity: Link) => { - return <Polyline - key={guid} - coordinates={entity.coords} - strokeColor={fractColor[entity.fraction]} - strokeWidth={1} - /> } - const styles = StyleSheet.create({ }); -export default connect((store) => { - const display = store.entities.display - const portals = {} - const fields = {} - const links = {} - display.portals.forEach(guid => { portals[guid] = store.entities.portals[guid] }) - display.fields.forEach(guid => { fields[guid] = store.entities.fields[guid] }) - display.links.forEach(guid => { links[guid] = store.entities.links[guid] }) - return { - portals, fields, links - } -}, {})(MapObjects)
\ No newline at end of file +export default connect((store) => ({ portals: store.entities.portals, fields: store.entities.fields, links: store.entities.links }), {})(MapObjects)
\ No newline at end of file diff --git a/src/Components/MapOverlay.tsx b/src/Components/MapOverlay.tsx index 30160c9..faf484e 100644 --- a/src/Components/MapOverlay.tsx +++ b/src/Components/MapOverlay.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator, Linking } from 'react-native'; import { FontAwesome } from '@expo/vector-icons'; -import { getStatusBarHeight } from '../helper'; +import { getStatusBarHeight, getBottomSpace } from '../helper'; import { LatLng } from '../Api/interfaces'; type Props = { @@ -13,72 +13,88 @@ type Props = { } export default (props: Props) => ( - <View style={styles.overlay}> - <View style={styles.button}> - <FontAwesome.Button - name={'crosshairs'} - onPress={props.goToMe} - iconStyle={styles.icon} - color={"#000"} - size={24} - backgroundColor={"#e3e3e3"} - /> - </View> - <View style={styles.button}> - <FontAwesome.Button - name={'refresh'} - onPress={props.refresh} - iconStyle={styles.icon} - color={"#000"} - size={24} - backgroundColor={"#e3e3e3"} - /> - </View> - {props.selectedPortal ? ( - <> - <View style={styles.button}> - <FontAwesome.Button - name={'info'} - onPress={() => { - props.onOpenPortal(props.selectedPortal.guid, props.selectedPortal.coords) - }} - iconStyle={styles.icon} - color={"#000"} - size={24} - backgroundColor={"#e3e3e3"} - /> - </View> - <View style={styles.button}> - <FontAwesome.Button - name={'location-arrow'} - onPress={() => Linking.openURL(`geo:${props.selectedPortal.coords.latitude},${props.selectedPortal.coords.longitude}`)} - iconStyle={styles.icon} - color={"#000"} - size={24} - backgroundColor={"#e3e3e3"} - /> + <> + <View style={styles.overlayLeft}> + {props.loading > 0 ? ( + <View style={styles.loader}> + <ActivityIndicator color={"#000"} /> </View> - </> - ) : null} - - <View style={styles.button}> - <Text>{props.loading}</Text> + ) : null} + {props.selectedPortal ? ( + <> + <View style={styles.buttonWrapper}> + <FontAwesome.Button + style={styles.button} + name={'info'} + onPress={() => { + props.onOpenPortal(props.selectedPortal.guid, props.selectedPortal.coords) + }} + iconStyle={styles.icon} + color={"#000"} + size={25} + backgroundColor={"#e3e3e3"} + /> + </View> + <View style={styles.buttonWrapper}> + <FontAwesome.Button + style={styles.button} + name={'location-arrow'} + onPress={() => Linking.openURL(`geo:${props.selectedPortal.coords.latitude},${props.selectedPortal.coords.longitude}`)} + iconStyle={styles.icon} + color={"#000"} + size={25} + backgroundColor={"#e3e3e3"} + /> + </View> + </> + ) : null} </View> - {props.loading > 0 ? ( - <View style={styles.loader}> - <ActivityIndicator color={"#000"} /> + + <View style={styles.overlayRight}> + <View style={styles.buttonWrapper}> + <FontAwesome.Button + style={styles.button} + name={'crosshairs'} + onPress={props.goToMe} + iconStyle={styles.icon} + color={"#000"} + size={25} + backgroundColor={"#e3e3e3"} + /> </View> - ) : null} - </View> + <View style={styles.buttonWrapper}> + <FontAwesome.Button + style={styles.button} + name={'refresh'} + onPress={props.refresh} + iconStyle={styles.icon} + color={"#000"} + size={25} + backgroundColor={"#e3e3e3"} + /> + </View> + </View> + </> ); const styles = StyleSheet.create({ - overlay: { + overlayLeft: { position: 'absolute', - top: 8 + getStatusBarHeight(true), + bottom: getBottomSpace(), + left: 8, + }, + overlayRight: { + position: 'absolute', + bottom: getBottomSpace(), right: 8, }, button: { + justifyContent: 'center', + alignItems: 'center', + height: 48, + width: 48, + }, + buttonWrapper: { margin: 8, }, icon: { diff --git a/src/Components/PortalPanel.tsx b/src/Components/PortalPanel.tsx index 6cf19c2..d49d88a 100644 --- a/src/Components/PortalPanel.tsx +++ b/src/Components/PortalPanel.tsx @@ -1,12 +1,12 @@ import React, { Component, PureComponent } from 'react'; -import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator } from 'react-native'; +import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator, Image } from 'react-native'; // import { Button } from 'react-native-vector-icons/FontAwesome'; -import Reactotron from 'reactotron-react-native' import { getStatusBarHeight } from '../helper'; import { connect } from 'react-redux'; import actions from '../Actions/actions'; import { Portal } from '../Api/types'; import { bindActionCreators } from 'redux'; +import { COLORS_FRACTION } from '../colors'; type Props = { guid: string @@ -16,18 +16,14 @@ type Props = { class PortalPanel extends PureComponent<Props> { static navigationOptions = ({ navigation }) => { return { - title: navigation.getParam('title', 'Загрузка...'), + title: 'Информация о портале', }; - }; - componentWillMount() { - this.props.navigation.setParams({title: this.props.portal.name}) - } + }; componentDidMount() { this.props.getPortalDetails(this.props.guid) } componentWillReceiveProps(next: Props) { if (next.guid != this.props.guid) { - this.props.navigation.setParams({title: this.props.portal.name}) this.props.getPortalDetails(next.guid) } } @@ -38,9 +34,28 @@ class PortalPanel extends PureComponent<Props> { } return ( <View style={styles.overlay}> - <Text style={styles.title}>{portal.name}</Text> - <Text style={styles.subtitle}>Уровeнь: {portal.level}, здоровье: {portal.power}</Text> - <Text>{JSON.stringify(this.props)}</Text> + <View style={styles.panelRow}> + <Image style={styles.photo} source={{ uri: portal.photo }} /> + <View style={styles.panelRight}> + <Text style={[styles.title, { color: COLORS_FRACTION[portal.fraction] }]}>{portal.name}</Text> + <Text style={styles.subtitle}>Уровeнь: {portal.level}, здоровье: {portal.power}</Text> + <Text style={styles.subtitle}>Владелец: <Text style={[styles.user, { color: COLORS_FRACTION[portal.fraction] }]}>{portal.owner || 'нет'}</Text></Text> + <Text style={styles.subtitle}>Дата: {portal.timestamp && (new Date(portal.timestamp)).toLocaleString()}</Text> + </View> + </View> + <Text style={styles.title}>Резонаторы</Text> + <View> + {portal.resonators && portal.resonators.map((r, idx) => + r ? (<Text style={styles.subtitle}>{idx + 1}: {r[1]} [{r[2]}] - {r[0]}</Text>) : (<Text style={styles.subtitle}>{idx + 1}: нет</Text>) + )} + {(!portal.resonators || portal.resonators.length == 0) && (<Text style={styles.subtitle}>нет</Text>)} + </View> + <Text style={styles.title}>Моды</Text> + <View> + {portal.mods && portal.mods.map((r, idx) => + r ? (<Text style={styles.subtitle}>{idx + 1}: {r[1]} [{r[2]}] - {r[0]}</Text>) : (<Text style={styles.subtitle}>{idx + 1}: нет</Text>) + )} + </View> </View> ); } @@ -59,6 +74,12 @@ const styles = StyleSheet.create({ flex: 1, padding: 8, }, + panelRow: { + flexDirection: 'row', + }, + panelRight: { + paddingLeft: 8 + }, title: { fontWeight: 'bold', fontSize: 22, @@ -66,5 +87,12 @@ const styles = StyleSheet.create({ subtitle: { fontWeight: 'normal', fontSize: 18, + }, + user: { + fontWeight: 'bold', + }, + photo: { + width: 100, + height: 195, } });
\ No newline at end of file diff --git a/src/Components/Settings.tsx b/src/Components/Settings.tsx new file mode 100644 index 0000000..daf3216 --- /dev/null +++ b/src/Components/Settings.tsx @@ -0,0 +1,46 @@ +import React, { Component, PureComponent } from 'react'; +import { StyleSheet, View, Text, GestureResponderEvent, ActivityIndicator } from 'react-native'; +// import { Button } from 'react-native-vector-icons/FontAwesome'; +import { getStatusBarHeight } from '../helper'; +import { connect } from 'react-redux'; +import actions from '../Actions/actions'; +import { Portal } from '../Api/types'; +import { bindActionCreators } from 'redux'; + +type Props = { + guid: string + portal?: Portal +} + +class Settings extends PureComponent<Props> { + static navigationOptions = ({ navigation }) => { + return { + title: 'Настройки', + }; + }; + + render() { + return ( + <View style={styles.overlay}> + <Text>{JSON.stringify(this.props)}</Text> + </View> + ); + } +} + +export default connect((store) => ({}), (dispatch) => bindActionCreators(actions, dispatch))(Settings) + +const styles = StyleSheet.create({ + overlay: { + flex: 1, + padding: 8, + }, + title: { + fontWeight: 'bold', + fontSize: 22, + }, + subtitle: { + fontWeight: 'normal', + fontSize: 18, + } +});
\ No newline at end of file |