Преглед изворни кода

add app/pages/charge/Charging.js

wudebin пре 6 месеци
родитељ
комит
56bdcf9116
1 измењених фајлова са 491 додато и 0 уклоњено
  1. 491 0
      Strides-SPAPP/app/pages/charge/Charging.js

+ 491 - 0
Strides-SPAPP/app/pages/charge/Charging.js

@@ -0,0 +1,491 @@
+/**
+ * 充电中的页面组件
+ * @邠心vbe on 2021/04/13
+ */
+import React, { useRef, useEffect, useState } from 'react';
+import { Animated, View, Easing, StyleSheet, Image, Text, ImageBackground, TextInput } from 'react-native';
+import VbeRadialGradient from '../../components/VbeRadialGradient';
+import Modal from 'react-native-modal';
+import { ModalProps } from '../../components/BottomModal';
+import ChargeItemSelect from '../../icons/ChargeItemSelect';
+import { DialogMaxWidth } from './InfoDialog';
+import { QRResult } from './QRScan';
+
+export const circleSize = $vw(50.66) < 300 ? $vw(50.66) : 300;
+
+const batterySize = 0.463 * circleSize;
+const batteryWidth = 0.659*batterySize;
+
+export const TypeImage = {
+  AC: require('../../images/charge/ic-type-ac.png'),
+  DC: require('../../images/charge/ic-type-dc.png'),
+  CHADEMO: require('../../images/charge/ic-type-chademo.png')
+}
+
+export const TypeImageList = [
+  {
+    name: "AC",
+    nameScope: 'charging.AC',
+    key: 'AC',
+    icon: require('../../images/charge/ic-type-ac.png')
+  }, {
+    name: "DC",
+    nameScope:'charging.DC',
+    key: 'DC',
+    icon: require('../../images/charge/ic-type-dc.png')
+  }, /*{
+    name: 'Chademo',
+    nameScope: 'charging.Chademo',
+    key: 'CHADEMO',
+    icon: require('../../images/charge/ic-type-chademo.png')
+  }*/
+]
+
+export const getConnectTypeByKey = (key) => {
+  for (let item of TypeImageList) {
+    if (item.key == key) {
+      return item;
+    }
+  }
+}
+
+export const CircleAnimate = ({isStart = false}) => {
+  var rotate = useRef(new Animated.Value(0)).current;
+
+  const spins = () => {
+    Animated.timing(rotate, {
+      toValue: 1,
+      duration: 10000,
+      easing: Easing.linear,
+      useNativeDriver: true
+    }).start(() => {
+      rotate.setValue(0);
+      spins();
+    });
+  }
+
+  useEffect(() => {
+    if (isStart) {
+      spins();
+    }
+  }, [rotate]);
+
+  const spin = rotate.interpolate({
+    inputRange: [0, 1],
+    outputRange: ['0deg', '360deg']
+  })
+
+  return (
+    <Animated.View
+      style={[
+        styles.chargeCircle, {
+          transform: [{ 
+            rotate: spin 
+          }]
+        }
+      ]}>
+      { isStart &&
+        <View style={{ width: 25, height: 25, marginTop: -11}}>
+          <VbeRadialGradient
+            x="50%" y="50%" rx="50%" ry="50%"
+            colorList={[
+              {offset: '0%', color: '#FFF', opacity: .8},
+              {offset: '40%', color: '#FFF', opacity: .5},
+              {offset: '70%', color: '#FFF', opacity: .3},
+              {offset: '100%', color: '#FFF', opacity: 0}
+            ]}/>
+        </View>
+      }
+    </Animated.View>
+  );
+}
+
+export const BatteryView = ({soc, isPending, isCharging}) => {
+  var [powerPercent, setPercent] = useState(-1);
+  /*var [powerText, setText] = useState(0);
+
+  const autoCharge = () => {
+    setTimeout(() => {
+      const p = powerPercent + 0.001
+      setPercent(Number(p.toFixed(4)))
+      setText((powerPercent * 100).toFixed(0))
+      if (powerPercent >= 1) {
+        onComplete();
+      }
+    }, 50 + powerPercent * 100);
+  }
+
+  useEffect(() => {
+    if (run && powerPercent <= 1) {
+      autoCharge();
+    }
+  }, [powerPercent])*/
+  useEffect(() => {
+    if (isCharging) {
+      try {
+        var s = '-1' + soc;
+        var d = '' + parseInt(s);
+        d = d.replace('-1', '');
+        if (d) {
+          setPercent(parseInt(d))
+        } else {
+          setPercent(-1);
+        }
+      } catch (e) {
+        setPercent(-1);
+      }
+    }
+  }, [soc]);
+
+  const getOpacity = (unit) => {
+    var op = 1 * (powerPercent + unit);
+    return op < 1 ? op : 1;
+  }
+
+  const getHeight = () => {
+    if (powerPercent > 1) {
+      return batterySize * powerPercent / 100;
+    } else if (powerPercent > 0) {
+      return batterySize * powerPercent;
+    } else {
+      return 0
+    }
+  }
+
+  return (
+    isCharging
+    ? <View style={ui.center}>
+        <ImageBackground
+          style={{
+            width: circleSize,
+            height: circleSize,
+            margin: 32,
+            padding: 32,
+            alignItems: 'center',
+            justifyContent: 'center'
+          }}
+          source={require('../../images/charge/ic-charge-circle.png')}>
+          <View style={styles.chargingView}>
+            <View style={styles.plusLeftView}>
+              <Image
+                style={[styles.plusMiddle, { opacity: getOpacity(0.5)}]}
+                source={require('../../images/charge/ic-plus-middle.png')}/>
+              <Image
+                style={[styles.plusSmall, { opacity: getOpacity(0.4)}]}
+                source={require('../../images/charge/ic-plus-small.png')}/>
+            </View>
+            <View style={styles.batteryView}>
+              <View style={[styles.batteryIcon]}>
+                <Image
+                  style={styles.batteryIcon}
+                  source={require('../../images/charge/ic-battery-0.png')}/>
+                <View style={[styles.batteryLayer, { height: getHeight() }]}>
+                  <Image
+                    style={[styles.batteryIcon]}
+                    source={require('../../images/charge/ic-battery-1.png')}/>
+                </View>
+              </View>
+              { isPending
+                ? <Text style={styles.batterySoc}>Initiating...</Text>
+                : powerPercent != -1
+                  ? <Text style={styles.batteryPercent}>{powerPercent}%</Text>
+                  : <Text style={styles.batterySoc}>{'In Charging'}</Text>
+              }
+            </View>
+            <View style={styles.plusRightView}>
+              <Image
+                style={[styles.plusLarge, { opacity: getOpacity(0.6)}]}
+                source={require('../../images/charge/ic-plus-large.png')}/>
+            </View>
+          </View>
+          <CircleAnimate isStart={true}/>
+        </ImageBackground>
+      </View>
+    : <View style={styles.completeView}>
+        <Image
+          style={styles.disconnectIcon}
+          source={require('../../images/charge/charge-complete.png')}/>
+        <Text style={styles.completeTip}>Please disconnect and return connector to charging station</Text>
+      </View>
+  );
+}
+
+export const EnterStationDialog = ({visible, stationId, onConfirm, onClose}) => {
+  var [inputStationId, setInput] = useState('')
+
+  const enterStatioinId= () => {
+    //console.log(inputStationId);
+    if (inputStationId) {
+      QRResult.applyInputStation(inputStationId, stationId, (success, err) => {
+        setInput('')
+        if (success) {
+          if (onConfirm) onConfirm()
+        } else if (err) {
+          toastShort(err)
+        }
+        if (onClose) onClose()
+      });
+    } else {
+      toastShort('Please input Station ID')
+    }
+  }
+
+  return (
+    <Modal
+      isVisible={visible}
+      {...ModalProps}
+      onBackdropPress={() => onClose}
+      onBackButtonPress={() => onClose}>
+      <View style={styles.stationDialog}>
+        <Text style={styles.stationInputTitle}>Enter Station ID</Text>
+        <TextInput
+          style={styles.stationInput}
+          defaultValue={inputStationId}
+          placeholder='e.g: EVCTD0002-1'
+          placeholderTextColor={textPlacehoder}
+          onChangeText={text => setInput(text)}
+        />
+        <View style={styles.dialogButtons}>
+          <Button
+            textSize={17}
+            style={styles.buttonCancel}
+            text='Close'
+            onClick={onClose}/>
+          <Button
+            textSize={17}
+            style={styles.buttonOK}
+            text='Confirm'
+            onClick={() => enterStatioinId()}/>
+        </View>
+      </View>
+    </Modal>
+  )
+}
+
+const styles = StyleSheet.create({
+  chargingView: {
+    width: circleSize,
+    height: circleSize,
+    flexDirection: 'row',
+    alignItems: 'center'
+  },
+  chargeCircle: {
+    top: 0,
+    left: 0,
+    zIndex: 10,
+    width: circleSize,
+    height: circleSize,
+    position: 'absolute',
+    alignItems: 'center',
+    borderRadius: circleSize
+  },
+  batteryView: {
+    paddingTop: 8,
+    paddingLeft: 12,
+    paddingRight: 12,
+    alignItems: 'center',
+    justifyContent: 'center'
+  },
+  batteryIcon: {
+    width: batteryWidth,
+    height: batterySize,
+    position: 'relative',
+    justifyContent: 'flex-end',
+  },
+  batteryLayer: {
+    left: 0,
+    right: 0,
+    height: 0,
+    width: batteryWidth,
+    overflow: 'hidden',
+    position: 'absolute',
+    justifyContent: 'flex-end',
+  },
+  batteryPercent: {
+    color: textPrimary,
+    fontSize: 22,
+    textAlign: 'center',
+    paddingTop: 10,
+    paddingBottom: 8
+  },
+  batterySoc: {
+    color: textPrimary,
+    fontSize: 18,
+    textAlign: 'center',
+    paddingTop: 10,
+    paddingBottom: 10
+  },
+  plusLeftView: {
+    flex: 1,
+    height: batterySize + 10,
+    marginBottom: 12,
+    alignItems: 'flex-end',
+    justifyContent: 'space-around'
+  },
+  plusRightView: {
+    flex: 1,
+    justifyContent: 'center'
+  },
+  plusLarge: {
+    width: 24,
+    height: 24
+  },
+  plusMiddle: {
+    width: 18,
+    height: 18
+  },
+  plusSmall: {
+    width: 12,
+    height: 12,
+    marginBottom: 8
+  },
+  selectView: {
+    position: 'relative'
+  },
+  selectIcon: {
+    width: 18,
+    height: 18
+  },
+  selectIconAbs: {
+    top: -2,
+    right: -4,
+    zIndex: 2,
+    position: 'absolute'
+  },
+  completeView: {
+    height: circleSize,
+    marginBottom: 16,
+    alignItems: 'center',
+    justifyContent: 'center'
+  },
+  disconnectIcon: {
+    width: 100,
+    height: 100
+  },
+  completeTip: {
+    width: circleSize,
+    color: textPrimary,
+    fontSize: 16,
+    paddingLeft: 16,
+    paddingRight: 16,
+    textAlign: 'center'
+  },
+  stationDialog: {
+    padding: 16,
+    marginLeft: 'auto',
+    marginRight: 'auto',
+    borderRadius: isIOS ? 20 : 3,
+    width: DialogMaxWidth,
+    backgroundColor: colorLight
+  },
+  stationInput: {
+    ...$padding(4, 10),
+    minHeight: 40,
+    borderRadius: 3,
+    backgroundColor: '#F0F0F0'
+  },
+  stationInputTitle: {
+    fontSize: 15,
+    textAlign: 'center',
+    paddingBottom: 16
+  },
+  dialogButtons: {
+    paddingTop: 16,
+    paddingBottom: 8,
+    flexDirection: 'row'
+  },
+  buttonOK: {
+    flex: 1,
+    marginLeft: 4,
+  },
+  buttonCancel: {
+    flex: 1,
+    backgroundColor: '#eee'
+  }
+});
+
+export const SelectableIcon = ({selected, children}) => {
+  return (
+    <View style={styles.selectView}>
+      {selected &&
+        <View style={[styles.selectIcon, children && styles.selectIconAbs]}>
+          <ChargeItemSelect size={18} selected={true}/>
+        </View>
+      }
+      {children}
+    </View>
+  );
+}
+
+export const ChargeStyle = StyleSheet.create({
+  stationInfoView: {
+    padding: 8,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'space-between'
+  },
+  infoGroup: {
+    ...$padding(4, 8),
+    alignItems: 'center'
+  },
+  infoTitle: {
+    color: '#999',
+    fontSize: 12
+  },
+  infoText: {
+    color: textPrimary,
+    fontSize: 12,
+    paddingTop: 4
+  },
+  infoBoldNumber: {
+    color: textPrimary,
+    fontSize: 14,
+    paddingTop: 3,
+    fontWeight: 'bold'
+  },
+  infoStatus: {
+    fontSize: 12,
+    borderRadius: 4,
+    ...$padding(4, 10)
+  },
+  infoIcon: {
+    width: 38,
+    height: 38
+  },
+  itemDivide: {
+    borderTopWidth: 1,
+    borderTopColor: '#eee'
+  },
+  statusSelected: {
+    color: textPrimary,
+    ...$padding(4, 11),
+    backgroundColor: colorAccent
+  },
+  statusAvailable: {
+    color: textLight,
+    backgroundColor: '#90DB0A'
+  },
+  statusUnavailable: {
+    color: '#999',
+    fontSize: 10,
+    ...$padding(5, 8),
+    backgroundColor: '#CCC'
+  },
+  statusWarning: {
+    color: textLight,
+    backgroundColor: colorAccent
+  },
+  rateText: {
+    color: textPrimary,
+    fontSize: 14,
+  },
+  ratePrice: {
+    color: '#000',
+    fontSize: 14,
+  },
+  authText: {
+    color: '#000',
+    fontSize: 12,
+    paddingTop: 2
+  }
+});