Saturday, 28 March 2020
Friday, 27 March 2020
Monday, 23 March 2020
Sunday, 22 March 2020
Tuesday, 17 March 2020
buffalo trip
Expense:
March 17, 2020CRM course
2 hard drives
March 19
Taxi x 2
March 21
fuel x 2
March 22
fuel
hotel
March 23
car rental
March 24
hotel
hard drive
allen key
March 25
gas, tools, fuel
March 26
hotel, fuel
March 27
hotel
March 29
hotel
March 30
tool, hotel
March 31
hotel
April 1
hotel
April 2
hotel, fuel
April 4
taxi, fuel
April 6
taxi
Timesheet
March 19 ferry to Montreal 10h
March 20 install 10h
March 21 survey 12h
March 22 weather 8h
March 23 weather 8h
March 24 troubleshoot 8h
March 25 troubleshoot, survey 16h
March 26 weather 8h
March 27 survey 12h
March 28 weather 8h
March 29 weather 8h
March 30 weather 8h
March 31 weather 8h
April 1 survey 12h
April 2 weather 8h
April 3 weather 8h
April 4 ferry to Montreal 8h
April 5 fly back 8h
April 6 fly back 8h
March 20 install 10h
March 21 survey 12h
March 22 weather 8h
March 23 weather 8h
March 24 troubleshoot 8h
March 25 troubleshoot, survey 16h
March 26 weather 8h
March 27 survey 12h
March 28 weather 8h
March 29 weather 8h
March 30 weather 8h
March 31 weather 8h
April 1 survey 12h
April 2 weather 8h
April 3 weather 8h
April 4 ferry to Montreal 8h
April 5 fly back 8h
April 6 fly back 8h
Sunday, 15 March 2020
expo sensors
//device motion object
Object {
"acceleration": Object {
"x": 0.4774880111217499,
"y": 0.10282400250434875,
"z": -0.38873401284217834,
},
"accelerationIncludingGravity": Object {
"x": -3.1230223178863525,
"y": -8.132352828979492,
"z": -4.447468280792236,
},
"orientation": 0,
"rotation": Object {
"alpha": 2.700334310531616,
"beta": 0.9731265902519226,
"gamma": -0.6596294641494751,
},
"rotationRate": Object {
"alpha": -0.04015243425965309,
"beta": -0.03880959376692772,
"gamma": 0.08099979907274246,
},
}
--------------------------
//Magnetometer
Object {
"x": -15.711748123168945,
"y": -42.86347579956055,
"z": -14.824956893920898,
}
reference:
https://docs.expo.io/versions/latest/sdk/devicemotion/
Object {
"acceleration": Object {
"x": 0.4774880111217499,
"y": 0.10282400250434875,
"z": -0.38873401284217834,
},
"accelerationIncludingGravity": Object {
"x": -3.1230223178863525,
"y": -8.132352828979492,
"z": -4.447468280792236,
},
"orientation": 0,
"rotation": Object {
"alpha": 2.700334310531616,
"beta": 0.9731265902519226,
"gamma": -0.6596294641494751,
},
"rotationRate": Object {
"alpha": -0.04015243425965309,
"beta": -0.03880959376692772,
"gamma": 0.08099979907274246,
},
}
--------------------------
//Magnetometer
Object {
"x": -15.711748123168945,
"y": -42.86347579956055,
"z": -14.824956893920898,
}
reference:
https://docs.expo.io/versions/latest/sdk/devicemotion/
Saturday, 14 March 2020
expo gps3 export
project link: https://exp.host/@chuanshuoge/expo-location
standalone apk: https://github.com/chuanshuoge6/expo-location/blob/master/expo-location-6a2380c18118466d88e1dbb510e776b9-signed.apk
stop record after recording for a while
press show record
press export
txt file is in download folder
open it up
//gps.js
import { Clipboard, ShadowPropTypesIOS } from 'react-native';
import {
Container, Header, Title, Content, Footer,
FooterTab, Button, Left, Right, Body, Icon, Text,
Accordion, Card, CardItem, Thumbnail, ListItem,
CheckBox, DatePicker, DeckSwiper, Fab, View,
Badge, Form, Item, Input, Label, Picker, Textarea,
Switch, Radio, Spinner, Tab, Tabs, TabHeading,
ScrollableTab, H1, H2, H3, Drawer,
} from 'native-base';
import * as Font from 'expo-font'
import * as Location from 'expo-location'
import * as TaskManager from 'expo-task-manager'
import useInterval from 'react-useinterval'
import openMap from 'react-native-open-maps'
import { connect } from 'react-redux';
import { addLocations, deleteLocations } from './Redux/locationActions'
import * as MediaLibrary from 'expo-media-library'
import * as FileSystem from 'expo-file-system'
const LOCATION_TASK_NAME = 'background-location-task';
let background_location = null
function GPS(props) {
const [loadfont, setloadfont] = useState(true)
const [permission_status, setpermission_status] = useState('undetermined')
const [acc, setacc] = useState(-1)
const [altitude, setaltitude] = useState(-1)
const [heading, setheading] = useState(-1)
const [latitude, setlatitude] = useState(-1)
const [longitude, setlonggitude] = useState(-1)
const [speed, setspeed] = useState(-1)
const [time, settime] = useState('')
const [updatePeriod, setupdatePeriod] = useState(null)
const [address, setaddress] = useState(null)
const [card_collapse1, setcard_collapse1] = useState(false)
const [card_collapse2, setcard_collapse2] = useState(false)
const [record, setrecord] = useState(false)
const [storagePermission, setstoragePermission] = useState('denied')
useEffect(() => {
initializeApp()
return () => stop_update_location()
}, [])
initializeApp = async () => {
const { status } = await Location.requestPermissionsAsync()
setpermission_status(status)
const grantStorage = await MediaLibrary.requestPermissionsAsync()
setstoragePermission(grantStorage.status)
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf")
})
setloadfont(false)
}
useInterval(() => {
update_location()
if (record && time !== '') {
props.dispatch(addLocations({
latitude: latitude,
longitude: longitude,
time: time,
}))
}
}, updatePeriod);
update_location = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.High,
})
if (background_location) {
const e = background_location.coords
setacc(e.accuracy)
setaltitude(e.altitude)
setheading(e.heading)
setlatitude(e.latitude)
setlonggitude(e.longitude)
setspeed(e.speed)
settime(Date(background_location.timestamp).toLocaleString())
}
}
stop_update_location = async () => {
setupdatePeriod(null)
const taskRegistered = await TaskManager.isTaskRegisteredAsync(LOCATION_TASK_NAME)
if (taskRegistered) {
await TaskManager.unregisterTaskAsync(LOCATION_TASK_NAME)
}
}
search_address = async () => {
if (background_location) {
const _address = await Location.reverseGeocodeAsync(background_location.coords)
setaddress(_address[0])
}
}
open_map = () => {
if (background_location) {
const e = background_location.coords
openMap({ latitude: e.latitude, longitude: e.longitude })
}
}
write_to_clipboard = (text) => {
Clipboard.setString(text);
}
display_record = () => {
let text = ''
props.locations_store.map(item => {
text = text + item.time + ',' + item.latitude.toString() + ',' + item.longitude.toString() + '\n'
})
alert(text)
}
export_locations = async () => {
let text = ''
props.locations_store.map(item => {
text = text + item.time + ',' + item.latitude.toString() + ',' + item.longitude.toString() + '\n'
})
const fileUri = FileSystem.cacheDirectory + "location.txt";
await FileSystem.writeAsStringAsync(fileUri, text, { encoding: FileSystem.EncodingType.UTF8 });
const asset = await MediaLibrary.createAssetAsync(fileUri)
await MediaLibrary.createAlbumAsync("Download", asset, false)
alert('file exported to download folder')
}
if (permission_status !== 'granted' || storagePermission !== 'granted') {
<Container style={{ backgroundColor: '#1C2833' }}>
<Text>App needs location and storage permission granted</Text>
</Container>
}
if (loadfont) {
return <Container style={{ backgroundColor: '#1C2833' }}><Spinner /></Container>
}
return (
<Container style={{ backgroundColor: '#1C2833' }}>
<Content style={{ marginTop: 25 }}>
<Card style={{ backgroundColor: '#1C2833' }}>
<CardItem header bordered button style={{ backgroundColor: "#1C2833" }}
onPress={() => setcard_collapse1(!card_collapse1)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Realtime GPS</H3>
<H3 style={{ color: "#D0D3D4" }}>+</H3>
</View>
</CardItem>
{card_collapse1 ? null :
<CardItem bordered style={{ backgroundColor: '#1C2833' }}>
<Text style={{ color: "#D0D3D4", fontStyle: 'italic' }}>
Accuracy: {acc} Meters{'\n'}
Altitude: {altitude} Meters{'\n'}
Heading: {heading} Degree{'\n'}
Latitude: {latitude} Degree{'\n'}
Longitude: {longitude} Degree{'\n'}
Speed: {speed} M/S{'\n'}
Time: {time}
</Text>
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => { write_to_clipboard(latitude + ',' + longitude) }}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
<CardItem header bordered button style={{ backgroundColor: '#1C2833' }}
onPress={() => setcard_collapse2(!card_collapse2)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Address (update location first)</H3>
<H3 style={{ color: '#D0D3D4' }}>+</H3>
</View>
</CardItem>
{card_collapse2 ? null :
<CardItem style={{ backgroundColor: '#1C2833' }}>
{address ?
<Text style={{ color: '#D0D3D4' }}>
{address.name} {address.street} {'\n'}
{address.city} {address.region} {address.country} {address.postalCode}
</Text>
: <Text style={{ color: '#D0D3D4' }}>Waiting for GPS location</Text>}
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => {
write_to_clipboard(address.name + ' ' + address.street + ' ' +
address.city + ' ' + address.region + ' ' + address.country + ' ' + address.postalCode)
}}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
</Card>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => setupdatePeriod(1000)}>
<Text>Update Location</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => stop_update_location()}>
<Text>Stop Update</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => search_address()}>
<Text>Search Address</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => open_map()}>
<Text>Open Map</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => {
props.dispatch(deleteLocations()); setupdatePeriod(1000); setrecord(true)
}}>
<Text>New Record</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { setupdatePeriod(1000); setrecord(true) }}>
<Text>Continue Record</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { stop_update_location(); setrecord(false) }}>
<Text>Stop Record</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => display_record()}>
<Text>Show Record</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { export_locations() }}>
<Text>Export Locations</Text>
</Button>
</View>
</Content>
</Container>
);
}
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
// Error occurred - check `error.message` for more details.
console.log(error.message)
return;
}
if (data) {
const { locations } = data;
// do something with the locations captured in the background
background_location = locations[locations.length - 1]
}
});
export default connect(
(store) => {
return {
locations_store: store.locationReducer.locations,
};
}
)(GPS);
reference:
http://chuanshuoge2.blogspot.com/2020/03/expo-gps2-redux-persist.html
Friday, 13 March 2020
Thursday, 12 March 2020
Wednesday, 11 March 2020
expo gps2 redux persist
app opens click new record
press stop record, press show record
time, latitude, longitude are recorded
press continue record
data append to the existing
close app, reopen app, press show record
location data persist, didn't lose when app close
press continue record, list keep growing
//app.js
import React from 'react';
import { PersistGate } from 'redux-persist/integration/react';
import { Provider } from 'react-redux';
import GPS from './gps';
import { store, persistor } from './Redux/store';
import { View, ActivityIndicator } from 'react-native';
export default function App() {
renderLoading = () => {
return (
<View>
<ActivityIndicator size={"large"} />
</View>
);
};
return (
// Redux: Global Store
<Provider store={store}>
<PersistGate loading={() => renderLoading()} persistor={persistor}>
<GPS />
</PersistGate>
</Provider>
);
};
----------------------------------------------
//Redux/store.js
import createSecureStore from "redux-persist-expo-securestore";
import { createStore, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import reducers from "./reducers";
import { createLogger } from 'redux-logger';
// Secure storage
const storage = createSecureStore();
const config = {
key: "root",
storage
};
const persistedReducer = persistReducer(config, reducers);
const store = createStore(
persistedReducer,
applyMiddleware(createLogger())
);
const persistor = persistStore(store);
export { store, persistor }
//Redux/reducers/index.js
import { combineReducers } from 'redux';
import locationReducer from "./locationReducer";
export default combineReducers(
{
locationReducer
})
----------------------------
//Redux/reducers/locationReducer.js
export default function reducer(
state = {
locations: []
},
action
) {
switch (action.type) {
case "add": {
return { ...state, locations: state.locations.concat(action.payload) }
}
case "delete": {
return { ...state, locations: [] }
}
}
return state;
}
----------------------------
//Redux/locationActions.js
export function addLocations(locations) {
return {
type: 'add',
payload: locations
}
}
export function deleteLocations() {
return {
type: 'delete'
}
}
-----------------------------
//gps.js
import React, { useState, useEffect } from 'react';
import { Clipboard, ShadowPropTypesIOS } from 'react-native';
import {
Container, Header, Title, Content, Footer,
FooterTab, Button, Left, Right, Body, Icon, Text,
Accordion, Card, CardItem, Thumbnail, ListItem,
CheckBox, DatePicker, DeckSwiper, Fab, View,
Badge, Form, Item, Input, Label, Picker, Textarea,
Switch, Radio, Spinner, Tab, Tabs, TabHeading,
ScrollableTab, H1, H2, H3, Drawer,
} from 'native-base';
import * as Font from 'expo-font'
import * as Location from 'expo-location'
import * as TaskManager from 'expo-task-manager'
import useInterval from 'react-useinterval'
import openMap from 'react-native-open-maps'
import { connect } from 'react-redux';
import { addLocations, deleteLocations } from './Redux/locationActions'
const LOCATION_TASK_NAME = 'background-location-task';
let background_location = null
function GPS(props) {
const [loadfont, setloadfont] = useState(true)
const [permission_status, setpermission_status] = useState('undetermined')
const [acc, setacc] = useState(-1)
const [altitude, setaltitude] = useState(-1)
const [heading, setheading] = useState(-1)
const [latitude, setlatitude] = useState(-1)
const [longitude, setlonggitude] = useState(-1)
const [speed, setspeed] = useState(-1)
const [time, settime] = useState('')
const [updatePeriod, setupdatePeriod] = useState(null)
const [address, setaddress] = useState(null)
const [card_collapse1, setcard_collapse1] = useState(false)
const [card_collapse2, setcard_collapse2] = useState(false)
const [record, setrecord] = useState(false)
useEffect(() => {
initializeApp()
return () => stop_update_location()
}, [])
initializeApp = async () => {
const { status } = await Location.requestPermissionsAsync()
setpermission_status(status)
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf")
})
setloadfont(false)
}
useInterval(() => {
update_location()
if (record && time !== '') {
props.dispatch(addLocations({
latitude: latitude,
longitude: longitude,
time: time,
}))
}
}, updatePeriod);
update_location = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.High,
})
if (background_location) {
const e = background_location.coords
setacc(e.accuracy)
setaltitude(e.altitude)
setheading(e.heading)
setlatitude(e.latitude)
setlonggitude(e.longitude)
setspeed(e.speed)
settime(Date(background_location.timestamp).toLocaleString())
}
}
stop_update_location = async () => {
setupdatePeriod(null)
const taskRegistered = await TaskManager.isTaskRegisteredAsync(LOCATION_TASK_NAME)
if (taskRegistered) {
await TaskManager.unregisterTaskAsync(LOCATION_TASK_NAME)
}
}
search_address = async () => {
if (background_location) {
const _address = await Location.reverseGeocodeAsync(background_location.coords)
setaddress(_address[0])
}
}
open_map = () => {
if (background_location) {
const e = background_location.coords
openMap({ latitude: e.latitude, longitude: e.longitude })
}
}
write_to_clipboard = (text) => {
Clipboard.setString(text);
}
display_record = () => {
let text = ''
props.locations_store.map(item => {
text = text + item.time + ',' + item.latitude.toString() + ',' + item.longitude.toString() + '\n'
})
alert(text)
}
if (permission_status !== 'granted') {
<Container style={{ backgroundColor: '#1C2833' }}>
<Text>App needs location permission granted</Text>
</Container>
}
if (loadfont) {
return <Container style={{ backgroundColor: '#1C2833' }}><Spinner /></Container>
}
return (
<Container style={{ backgroundColor: '#1C2833' }}>
<Content style={{ marginTop: 25 }}>
<Card style={{ backgroundColor: '#1C2833' }}>
<CardItem header bordered button style={{ backgroundColor: "#1C2833" }}
onPress={() => setcard_collapse1(!card_collapse1)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Realtime GPS</H3>
<H3 style={{ color: "#D0D3D4" }}>+</H3>
</View>
</CardItem>
{card_collapse1 ? null :
<CardItem bordered style={{ backgroundColor: '#1C2833' }}>
<Text style={{ color: "#D0D3D4", fontStyle: 'italic' }}>
Accuracy: {acc} Meters{'\n'}
Altitude: {altitude} Meters{'\n'}
Heading: {heading} Degree{'\n'}
Latitude: {latitude} Degree{'\n'}
Longitude: {longitude} Degree{'\n'}
Speed: {speed} M/S{'\n'}
Time: {time}
</Text>
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => { write_to_clipboard(latitude + ',' + longitude) }}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
<CardItem header bordered button style={{ backgroundColor: '#1C2833' }}
onPress={() => setcard_collapse2(!card_collapse2)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Address (update location first)</H3>
<H3 style={{ color: '#D0D3D4' }}>+</H3>
</View>
</CardItem>
{card_collapse2 ? null :
<CardItem style={{ backgroundColor: '#1C2833' }}>
{address ?
<Text style={{ color: '#D0D3D4' }}>
{address.name} {address.street} {'\n'}
{address.city} {address.region} {address.country} {address.postalCode}
</Text>
: <Text style={{ color: '#D0D3D4' }}>Waiting for GPS location</Text>}
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => {
write_to_clipboard(address.name + ' ' + address.street + ' ' +
address.city + ' ' + address.region + ' ' + address.country + ' ' + address.postalCode)
}}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
</Card>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => setupdatePeriod(1000)}>
<Text>Update Location</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => stop_update_location()}>
<Text>Stop Update</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => search_address()}>
<Text>Search Address</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => open_map()}>
<Text>Open Map</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => {
props.dispatch(deleteLocations()); setupdatePeriod(1000); setrecord(true)
}}>
<Text>New Record</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { setupdatePeriod(1000); setrecord(true) }}>
<Text>Continue Record</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { stop_update_location(); setrecord(false) }}>
<Text>Stop Record</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => display_record()}>
<Text>Show Record</Text>
</Button>
</View>
</Content>
</Container>
);
}
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
// Error occurred - check `error.message` for more details.
console.log(error.message)
return;
}
if (data) {
const { locations } = data;
// do something with the locations captured in the background
background_location = locations[locations.length - 1]
}
});
export default connect(
(store) => {
return {
locations_store: store.locationReducer.locations,
};
}
)(GPS);
reference:
https://chuanshuoge2.blogspot.com/2018/05/react-redux.html
https://chuanshuoge2.blogspot.com/2020/03/expo-location.html
http://chuanshuoge2.blogspot.com/2020/03/expo-gps-1.html
Monday, 9 March 2020
expo gps 1
app opens, click update location
gps is turned on and updates every second
press stop update, press copy button beside gps info to copy location to clipboard
press search address
press Realtime GPS to collapse it, press open map
google map is the default map app, our location is at center
open offline gps app, paste copied location
offline gps finds our location
//app.jsimport React, { useState, useEffect } from 'react';
import { Clipboard } from 'react-native';
import {
Container, Header, Title, Content, Footer,
FooterTab, Button, Left, Right, Body, Icon, Text,
Accordion, Card, CardItem, Thumbnail, ListItem,
CheckBox, DatePicker, DeckSwiper, Fab, View,
Badge, Form, Item, Input, Label, Picker, Textarea,
Switch, Radio, Spinner, Tab, Tabs, TabHeading,
ScrollableTab, H1, H2, H3, Drawer,
} from 'native-base';
import * as Font from 'expo-font'
import * as Location from 'expo-location'
import * as TaskManager from 'expo-task-manager'
import useInterval from 'react-useinterval'
import openMap from 'react-native-open-maps'
const LOCATION_TASK_NAME = 'background-location-task';
let background_location = null
export default function App() {
const [loadfont, setloadfont] = useState(true)
const [permission_status, setpermission_status] = useState('undetermined')
const [acc, setacc] = useState(-1)
const [altitude, setaltitude] = useState(-1)
const [heading, setheading] = useState(-1)
const [latitude, setlatitude] = useState(-1)
const [longitude, setlonggitude] = useState(-1)
const [speed, setspeed] = useState(-1)
const [time, settime] = useState('')
const [updatePeriod, setupdatePeriod] = useState(null)
const [address, setaddress] = useState(null)
const [card_collapse1, setcard_collapse1] = useState(false)
const [card_collapse2, setcard_collapse2] = useState(false)
useEffect(() => {
initializeApp()
return () => stop_update_location()
}, [])
initializeApp = async () => {
const { status } = await Location.requestPermissionsAsync()
setpermission_status(status)
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf")
})
setloadfont(false)
}
useInterval(() => (
update_location()
), updatePeriod);
update_location = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.High,
})
if (background_location) {
const e = background_location.coords
setacc(e.accuracy)
setaltitude(e.altitude)
setheading(e.heading)
setlatitude(e.latitude)
setlonggitude(e.longitude)
setspeed(e.speed)
settime(Date(background_location.timestamp).toString())
}
}
stop_update_location = async () => {
setupdatePeriod(null)
const taskRegistered = await TaskManager.isTaskRegisteredAsync(LOCATION_TASK_NAME)
if (taskRegistered) {
await TaskManager.unregisterTaskAsync(LOCATION_TASK_NAME)
}
}
search_address = async () => {
if (background_location) {
const _address = await Location.reverseGeocodeAsync(background_location.coords)
setaddress(_address[0])
}
}
open_map = () => {
if (background_location) {
const e = background_location.coords
openMap({ latitude: e.latitude, longitude: e.longitude })
}
}
write_to_clipboard = (text) => {
Clipboard.setString(text);
}
if (permission_status !== 'granted') {
<Container style={{ backgroundColor: '#1C2833' }}>
<Text>App needs location permission granted</Text>
</Container>
}
if (loadfont) {
return <Container style={{ backgroundColor: '#1C2833' }}><Spinner /></Container>
}
return (
<Container style={{ backgroundColor: '#1C2833' }}>
<Content style={{ marginTop: 25 }}>
<Card style={{ backgroundColor: '#1C2833' }}>
<CardItem header bordered button style={{ backgroundColor: "#1C2833" }}
onPress={() => setcard_collapse1(!card_collapse1)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Realtime GPS</H3>
<H3 style={{ color: "#D0D3D4" }}>+</H3>
</View>
</CardItem>
{card_collapse1 ? null :
<CardItem bordered style={{ backgroundColor: '#1C2833' }}>
<Text style={{ color: "#D0D3D4", fontStyle: 'italic' }}>
Accuracy: {acc} Meters{'\n'}
Altitude: {altitude} Meters{'\n'}
Heading: {heading} Degree{'\n'}
Latitude: {latitude} Degree{'\n'}
Longitude: {longitude} Degree{'\n'}
Speed: {speed} M/S{'\n'}
Time: {time}
</Text>
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => { write_to_clipboard(latitude + ',' + longitude) }}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
<CardItem header bordered button style={{ backgroundColor: '#1C2833' }}
onPress={() => setcard_collapse2(!card_collapse2)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Address (update location first)</H3>
<H3 style={{ color: '#D0D3D4' }}>+</H3>
</View>
</CardItem>
{card_collapse2 ? null :
<CardItem style={{ backgroundColor: '#1C2833' }}>
{address ?
<Text style={{ color: '#D0D3D4' }}>
{address.name} {address.street} {'\n'}
{address.city} {address.region} {address.country} {address.postalCode}
</Text>
: <Text style={{ color: '#D0D3D4' }}>Waiting for GPS location</Text>}
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => {
write_to_clipboard(address.name + ' ' + address.street + ' ' +
address.city + ' ' + address.region + ' ' + address.country + ' ' + address.postalCode)
}}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
</Card>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => setupdatePeriod(1000)}>
<Text>Update Location</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => stop_update_location()}>
<Text>Stop Update</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => search_address()}>
<Text>Search Address</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => open_map()}>
<Text>Open Map</Text>
</Button>
</View>
</Content>
</Container>
);
}
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
// Error occurred - check `error.message` for more details.
console.log(error.message)
return;
}
if (data) {
const { locations } = data;
// do something with the locations captured in the background
background_location = locations[locations.length - 1]
}
});
reference:
http://chuanshuoge2.blogspot.com/2020/03/expo-location.html
Saturday, 7 March 2020
expo location
//location
Object {
"coords": Object {
"accuracy": 12,
"altitude": 1084.7,
"heading": 143.8192901611328,
"latitude": 51.0763851,
"longitude": -113.9689081,
"speed": 0.8038911819458008,
},
"mocked": false,
"timestamp": 1583619293000,
}
reference:
expo-location
https://docs.expo.io/versions/latest/sdk/location/
expo-task-manager
https://docs.expo.io/versions/latest/sdk/task-manager/
https://github.com/expo/expo/issues/3256
useInterval
https://chuanshuoge2.blogspot.com/2019/10/react-hooks-useinterval.html
expo-file-system read write string
https://stackoverflow.com/questions/54586216/how-to-create-text-file-in-react-native-expo
https://docs.expo.io/versions/latest/sdk/filesystem/#filesystemreadasstringasyncfileuri-options
https://forums.expo.io/t/append-content-to-file-expo-filesystem/4951
react native open map
https://www.npmjs.com/package/react-native-open-maps
react native map
https://medium.com/@rishi.vedpathak/react-native-map-with-real-time-location-selection-for-android-739c23f04930
write to clipboard
https://medium.com/the-react-native-log/react-native-basics-copy-to-clipboard-86023cda4175
redux persist store
https://itnext.io/react-native-why-you-should-be-using-redux-persist-8ad1d68fa48b
https://medium.com/survival-development/simple-redux-persist-configuration-in-react-native-expo-environment-5cae7c4a22
https://github.com/Cretezy/redux-persist-expo-securestore
Object {
"coords": Object {
"accuracy": 12,
"altitude": 1084.7,
"heading": 143.8192901611328,
"latitude": 51.0763851,
"longitude": -113.9689081,
"speed": 0.8038911819458008,
},
"mocked": false,
"timestamp": 1583619293000,
}
reference:
expo-location
https://docs.expo.io/versions/latest/sdk/location/
expo-task-manager
https://docs.expo.io/versions/latest/sdk/task-manager/
https://github.com/expo/expo/issues/3256
useInterval
https://chuanshuoge2.blogspot.com/2019/10/react-hooks-useinterval.html
expo-file-system read write string
https://stackoverflow.com/questions/54586216/how-to-create-text-file-in-react-native-expo
https://docs.expo.io/versions/latest/sdk/filesystem/#filesystemreadasstringasyncfileuri-options
https://forums.expo.io/t/append-content-to-file-expo-filesystem/4951
react native open map
https://www.npmjs.com/package/react-native-open-maps
react native map
https://medium.com/@rishi.vedpathak/react-native-map-with-real-time-location-selection-for-android-739c23f04930
write to clipboard
https://medium.com/the-react-native-log/react-native-basics-copy-to-clipboard-86023cda4175
redux persist store
https://itnext.io/react-native-why-you-should-be-using-redux-persist-8ad1d68fa48b
https://medium.com/survival-development/simple-redux-persist-configuration-in-react-native-expo-environment-5cae7c4a22
https://github.com/Cretezy/redux-persist-expo-securestore
Friday, 6 March 2020
Thursday, 5 March 2020
expo forex
code link: https://github.com/chuanshuoge6/forex
project link: https://expo.io/@chuanshuoge/expo-forex
standalone apk: https://github.com/chuanshuoge6/forex/blob/master/expo-forex-771bec8df58843c3a1974f3d932afa85-signed.apk
app opens, show today's exchange rate, default base 1000 CAD
tap on EU, change to 100 EUR
values of other currencies updates too
long press on EU, enter past 30 day rate, default base is CAD, tap on Canada
flag list opens, select US
base currency changed to USD. Tap on EU, select HongKong
graph shows USD VS. HKD now
import React, { useState, useEffect } from 'react';
import { ScrollView, Modal, Dimensions, Image } from 'react-native';
import axios from 'axios'
import * as Font from 'expo-font'
import {
Container, Header, Title, Content, Footer,
FooterTab, Button, Left, Right, Body, Icon, Text,
Accordion, Card, CardItem, Thumbnail, ListItem,
CheckBox, DatePicker, DeckSwiper, View, Fab,
Badge, Form, Item, Input, Label, Picker, Textarea,
Switch, Radio, Spinner, Tab, Tabs, TabHeading,
ScrollableTab, H1, H2, H3, Drawer,
} from 'native-base';
import { Col, Row, Grid } from "react-native-easy-grid";
import ForexListItem from './forexItem'
import { Ionicons } from '@expo/vector-icons';
import { LineChart } from 'react-native-chart-kit'
import { countryFlag } from './countryFlag'
import FlagList from './FlagList'
export default function App() {
const [loadfont, setloadfont] = useState(true)
const [data, setdata] = useState(null)
const [cad, setcad] = useState(1000)
const [show_amount, setshow_amount] = useState(false)
const [input_currency, setinput_currency] = useState('CAD')
const [input_amount, setinput_amount] = useState(1000)
const [btc_rate, setbtc_rate] = useState(null)
const [x, setx] = useState([])
const [y, sety] = useState([])
const [show_chart, setshow_chart] = useState(false)
const [base_currency, setbase_currency] = useState(null)
const [convert_currency, setconvert_currency] = useState(null)
const [base_or_conversion, setbase_or_conversion] = useState(false)
const [show_flags, setshow_flags] = useState(false)
useEffect(() => {
initializeApp()
}, [])
initializeApp = async () => {
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf")
});
setloadfont(false)
fetch_latest()
}
fetch_latest = () => {
axios({
method: 'get',
url: 'https://api.exchangeratesapi.io/latest?base=CAD',
})
.then(response => {
setdata(response.data.rates)
fetch_btc(response.data.rates.USD)
})
.catch(function (error) {
alert(error);
setTimeout(() => {
fetch_latest()
}, 5000);
});
}
fetch_btc = (CADUSD) => {
axios({
method: 'get',
url: 'https://api.coindesk.com/v1/bpi/currentprice.json',
})
.then(response => {
const rate = CADUSD / parseFloat(response.data.bpi.USD.rate.replace(',', ''))
setbtc_rate(rate)
})
.catch(function (error) {
alert(error);
setTimeout(() => {
fetch_btc(CADUSD)
}, 5000);
});
}
forex_button_press = (value, currency) => {
setshow_amount(true)
setinput_amount(value)
setinput_currency(currency)
}
exchange_button_press = () => {
setshow_amount(false)
input_currency === 'BTC' ?
setcad(input_amount / btc_rate)
: setcad(input_amount / data[input_currency])
}
load_history = (a, b) => {
setbase_currency(a)
setconvert_currency(b)
const d = new Date()
const end = d.toISOString().split('T')[0]
d.setDate(-30)
const start = d.toISOString().split('T')[0]
const url = 'https://api.exchangeratesapi.io/history?start_at=' + start
+ '&end_at=' + end + '&symbols=' + b + '&base=' + a
axios({
method: 'get',
url: url,
})
.then(response => {
const history = JSON.stringify(response.data.rates)
const history_clean = history.replace(/{/g, '').replace(/}/g, '')
.replace(/"/g, '').replace(/:/g, '').split(',')
let date = [], rate = []
history_clean.sort().map(item => {
const item_split = item.split(b)
date.push(item_split[0])
rate.push(parseFloat(item_split[1]))
})
setx(date)
sety(rate)
setshow_chart(true)
})
.catch(function (error) {
alert(error);
});
}
changeCountry = (currency) => {
base_or_conversion ?
load_history(base_currency, currency)
: load_history(currency, convert_currency)
}
if (loadfont || !data) {
return (<Container style={{ backgroundColor: '#1C2833' }}>
<Content><Spinner /></Content></Container>)
}
return (
<Container style={{ backgroundColor: '#1C2833', marginTop: 25 }}>
<Modal
animationType="slide"
transparent={true}
visible={show_amount}
>
<Content>
<Item style={{ backgroundColor: 'white' }}>
<Input
style={{ height: 100, fontSize: 30 }}
keyboardType="number-pad"
value={input_amount}
onChangeText={e => setinput_amount(e ? e.match(/^([0-9]+(\.[0-9]+)?)/g)[0] : '1')}
onSubmitEditing={() => exchange_button_press()} />
<Text style={{ fontSize: 30 }}>{input_currency}</Text>
<Button large transparent onPress={() => exchange_button_press()}>
<Icon active name='swap' style={{ fontSize: 50 }} />
</Button>
<Button large transparent onPress={() => setshow_amount(false)}>
<Icon active name='close' style={{ fontSize: 50 }} />
</Button>
</Item>
</Content>
</Modal>
<Modal
animationType="fade"
transparent={false}
visible={show_chart}
>
<Container style={{ backgroundColor: '#1C2833' }}>
<Header >
<Left>
<Button transparent onPress={() => setshow_chart(false)}>
<Ionicons name='ios-arrow-round-back' size={40} color="white"></Ionicons>
</Button>
</Left>
<Body style={{ alignItems: 'center' }}>
<Title>Last 30 Day Rate</Title>
</Body>
<Right>
</Right>
</Header>
<View style={{ flexDirection: 'row', width: '100%', justifyContent: 'space-around' }}>
{base_currency ?
<Button transparent onPress={() => { setbase_or_conversion(false); setshow_flags(true) }}>
<Image
style={{ width: 50, height: 40, marginTop: 5 }}
source={countryFlag[base_currency]}
/>
</Button>
: null}
{convert_currency ?
<Button transparent onPress={() => { setbase_or_conversion(true); setshow_flags(true) }}>
<Image
style={{ width: 50, height: 40, marginTop: 5 }}
source={countryFlag[convert_currency]}
/>
</Button>
: null}
</View>
<LineChart
data={{
labels: [x[0]],
datasets: [{
data: y
}]
}}
width={Dimensions.get('window').width} // from react-native
height={300}
chartConfig={{
backgroundColor: 'blue',
backgroundGradientFrom: 'green',
backgroundGradientTo: '#ffa726',
decimalPlaces: 3, // optional, defaults to 2dp
color: (opacity = 1) => `rgba(255, 255, 255, 0.7)`,
}}
bezier
style={{
marginVertical: 8,
borderRadius: 16
}}
/>
</Container>
</Modal>
<FlagList show={show_flags} close={() => setshow_flags(false)}
country_selection={(currency) => changeCountry(currency)}></FlagList>
<Content>
<ScrollView>
<Grid>
<Col style={{ alignItems: 'center' }}>
<Row style={{ height: 50 }}>
<ForexListItem currency='CAD' rate={data.CAD} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'CAD')}
buttonLongPress={() => { }}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='CNY' rate={data.CNY} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'CNY')}
buttonLongPress={() => load_history('CAD', 'CNY')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='AUD' rate={data.AUD} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'AUD')}
buttonLongPress={() => load_history('CAD', 'AUD')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='HKD' rate={data.HKD} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'HKD')}
buttonLongPress={() => load_history('CAD', 'HKD')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='ISK' rate={data.ISK} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'ISK')}
buttonLongPress={() => load_history('CAD', 'ISK')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='HUF' rate={data.HUF} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'HUF')}
buttonLongPress={() => load_history('CAD', 'HUF')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='SEK' rate={data.SEK} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'SEK')}
buttonLongPress={() => load_history('CAD', 'SEK')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='BRL' rate={data.BRL} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'BRL')}
buttonLongPress={() => load_history('CAD', 'BRL')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='MYR' rate={data.MYR} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'MYR')}
buttonLongPress={() => load_history('CAD', 'MYR')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='NOK' rate={data.NOK} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'NOK')}
buttonLongPress={() => load_history('CAD', 'NOK')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='MXN' rate={data.MXN} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'MXN')}
buttonLongPress={() => load_history('CAD', 'MXN')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='PLN' rate={data.PLN} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'PLN')}
buttonLongPress={() => load_history('CAD', 'PLN')}
></ForexListItem>
</Row>
</Col>
<Col>
<Row style={{ height: 50 }}>
<ForexListItem currency='USD' rate={data.USD} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'USD')}
buttonLongPress={() => load_history('CAD', 'USD')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='EUR' rate={data.EUR} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'EUR')}
buttonLongPress={() => load_history('CAD', 'EUR')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='GBP' rate={data.GBP} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'GBP')}
buttonLongPress={() => load_history('CAD', 'GBP')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='CHF' rate={data.CHF} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'CHF')}
buttonLongPress={() => load_history('CAD', 'CHF')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='PHP' rate={data.PHP} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'PHP')}
buttonLongPress={() => load_history('CAD', 'PHP')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='CZK' rate={data.CZK} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'CZK')}
buttonLongPress={() => load_history('CAD', 'CZK')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='IDR' rate={data.IDR} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'IDR')}
buttonLongPress={() => load_history('CAD', 'IDR')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='HRK' rate={data.HRK} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'HRK')}
buttonLongPress={() => load_history('CAD', 'HRK')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='BGN' rate={data.BGN} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'BGN')}
buttonLongPress={() => load_history('CAD', 'BGN')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='NZD' rate={data.NZD} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'NZD')}
buttonLongPress={() => load_history('CAD', 'NZD')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='SGD' rate={data.SGD} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'SGD')}
buttonLongPress={() => load_history('CAD', 'SGD')}
></ForexListItem>
</Row>
</Col>
<Col>
<Row style={{ height: 50 }}>
{btc_rate ?
<ForexListItem currency='BTC' rate={btc_rate} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'BTC')}
buttonLongPress={() => { }}
></ForexListItem> : <Spinner />
}
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='JPY' rate={data.JPY} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'JPY')}
buttonLongPress={() => load_history('CAD', 'JPY')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='RUB' rate={data.RUB} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'RUB')}
buttonLongPress={() => load_history('CAD', 'RUB')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='KRW' rate={data.KRW} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'KRW')}
buttonLongPress={() => load_history('CAD', 'KRW')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='DKK' rate={data.DKK} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'DKK')}
buttonLongPress={() => load_history('CAD', 'DKK')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='RON' rate={data.RON} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'RON')}
buttonLongPress={() => load_history('CAD', 'RON')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='INR' rate={data.INR} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'INR')}
buttonLongPress={() => load_history('CAD', 'INR')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='THB' rate={data.THB} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'THB')}
buttonLongPress={() => load_history('CAD', 'THB')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='TRY' rate={data.TRY} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'TRY')}
buttonLongPress={() => load_history('CAD', 'TRY')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='ZAR' rate={data.ZAR} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'ZAR')}
buttonLongPress={() => load_history('CAD', 'ZAR')}
></ForexListItem>
</Row>
<Row style={{ height: 50 }}>
<ForexListItem currency='ILS' rate={data.ILS} CAD={cad}
buttonPress={(value) => forex_button_press(value, 'ILS')}
buttonLongPress={() => load_history('CAD', 'ILS')}
></ForexListItem>
</Row>
</Col>
</Grid>
</ScrollView>
</Content>
</Container>
);
}
--------------------------
//forexItem.js
import React, { Component } from 'react';
import {
Container, Header, Title, Content, Footer,
FooterTab, Button, Left, Right, Body, Icon, Text,
Accordion, Card, CardItem, Thumbnail, ListItem,
CheckBox, DatePicker, DeckSwiper, View, Fab,
Badge, Form, Item, Input, Label, Picker, Textarea,
Switch, Radio, Spinner, Tab, Tabs, TabHeading,
ScrollableTab, H1, H2, H3, Drawer,
} from 'native-base';
import { Image } from 'react-native';
import { countryFlag } from './countryFlag'
export default class ForexListItem extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const { currency, rate, CAD, buttonPress, buttonLongPress } = this.props
const amount = currency === 'BTC' ? (rate * CAD).toFixed(4) : (rate * CAD).toFixed(2)
return (
<Button style={{ flex: 1, margin: 2, backgroundColor: 'rgba(255, 255, 255, 0.2)' }}
onPress={() => buttonPress(amount)}
onLongPress={() => buttonLongPress()}>
{currency ?
<Image
style={{ width: 50, height: 40 }}
source={countryFlag[currency]}
/>
: null}
<View style={{ alignItems: 'center', flex: 1 }}>
<Text style={{ color: 'white', fontSize: 12 }}>{amount}</Text>
<Text style={{ color: 'gold', fontSize: 12 }}>{currency}</Text>
</View>
</Button>
)
}
}
reference:
https://www.npmjs.com/package/react-native-chart-kit
https://chuanshuoge2.blogspot.com/2020/02/free-foreign-exchange-rates-api.html
http://chuanshuoge2.blogspot.com/2020/02/nativebase-forex_6.html
Subscribe to:
Posts (Atom)