Explorar o código

sync code with juice+

vbea %!s(int64=3) %!d(string=hai) anos
pai
achega
32753aa528

+ 75 - 0
.gitignore

@@ -0,0 +1,75 @@
+dist
+node_modules
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+bundle/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+
+# Android/IntelliJ
+#
+build/
+.gradle
+local.properties
+*.iml
+*.ipa
+*.apk
+npm-debug.log
+yarn-error.log
+
+# BUCK
+buck-out/
+\.buckd/
+*.keystore
+
+*/fastlane/report.xml
+*/fastlane/Preview.html
+*/fastlane/screenshots
+
+# Bundle artifact
+*.jsbundle
+
+# CocoaPods
+Pods
+*.lock
+.idea
+*.iml
+.gradle
+release
+.DS_Store
+build
+/captures
+.externalNativeBuild
+.cxx
+cert.properties
+Others

+ 3 - 0
Strides-APP/app/api/apiUser.js

@@ -62,5 +62,8 @@ export default user = {
   },
   getCountryList: () => {
     return get('devicesApi/base/getCountries')
+  },
+  deleteAccount: () => {
+    return get(prefix + 'delUser')
   }
 }

+ 7 - 4
Strides-APP/app/components/Dropdown.js

@@ -14,8 +14,11 @@ export default Dropdown = ({
     onChange,
     nameKey,
     valueKey,
-    extraText='',
+    prefixText='',//前缀
+    suffixText='',//后缀
     itemHeight=50,
+    prefixList='',//列表前缀
+    suffixList='',//列表后缀
     rippleStyle,
     style = styles.valueView,
     textStyle = styles.valueText,
@@ -38,7 +41,7 @@ export default Dropdown = ({
         for (var i = 0; i < list.length; i++) {
           let item = list[i];
           if (item[valueKey] == value) {
-            changeValue(extraText+item[nameKey]);
+            changeValue(prefixText+item[nameKey]+suffixText);
             if (list.length > 20) {
               setCurrent(i > 5 ? i - 4 : 0);
             }
@@ -46,7 +49,7 @@ export default Dropdown = ({
           }
         }
       } else {
-        changeValue(extraText+value);
+        changeValue(prefixText+value+suffixText);
       }
     }
   }, [value, []]);
@@ -92,7 +95,7 @@ export default Dropdown = ({
     } else {
       return (
         <Button
-          text={nameKey ? item[nameKey] : item}
+          text={prefixList + (nameKey ? item[nameKey] : item) + suffixList}
           style={styles.itemView}
           textStyle={styles.itemText}
           onClick={() => {

+ 5 - 0
Strides-APP/app/pages/Router.js

@@ -37,6 +37,7 @@ import ResetPassword from './sign/ResetPassword';
 import PaymentMethod from './payment/PaymentMethod';
 import PayPerUse from './payment/PayPerUse';
 import PaymentWeb from './payment/PaymentWeb';
+import Settings from './Settings';
 
 export var PageList = {
   'splash': {
@@ -157,6 +158,10 @@ export var PageList = {
   },
   'forgotPassword': {
     component: ResetPassword
+  },
+  'settings': {
+    title: 'Settings',
+    component: Settings
   }
 }
 

+ 166 - 0
Strides-APP/app/pages/Settings.js

@@ -0,0 +1,166 @@
+/**
+ * 设置页面
+ * @邠心vbe on 2022/12/9
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, Switch } from 'react-native';
+import { Value } from 'react-native-reanimated';
+import Button from '../components/Button';
+import Dropdown from '../components/Dropdown';
+import storage from '../utils/storage';
+
+export const SETTINGS_KEY = 'CHARGE_SETTINGS'
+export const SettingUtil = {
+  getSettings: (back) => {
+    if (!global.settingsInfo) {
+      storage.getStorage(SETTINGS_KEY).then(sto => {
+        if (sto) {
+          const res = JSON.parse(sto);
+          global.settingsInfo = res;
+          back(global.settingsInfo)
+        } else {
+          back({
+            alwaysLocation: true,
+            refreshInterval: 10
+          })
+        }
+      })
+    } else {
+      back(global.settingsInfo)
+    }
+  }
+}
+
+export default class Settings extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      settings: {
+        alwaysLocation: true,
+        refreshInterval: 10
+      },
+      intervalList: [10, 15, 20, 30, 60, 90, 120]
+    };
+  }
+
+  componentDidMount() {
+    this.props.navigation.addListener('blur', () => {
+      //console.log("保存设置");
+      global.settingsInfo = this.state.settings
+      storage.setStorageJson(SETTINGS_KEY, this.state.settings)
+    });
+    SettingUtil.getSettings(res => {
+      const info = this.state.settings;
+      for (let item in info) {
+        if (res[item] !== undefined) {
+          info[item] = res[item]
+        }
+      }
+      this.setState({
+        settings: info
+      })
+    })
+  }
+
+  changeSwitch(key, value) {
+    this.state.settings[key] = value
+    //console.log('changeSwitch', item);
+    this.setState({
+      settings: this.state.settings
+    })
+  }
+
+  changeSettings(key, value) {
+    this.state.settings[key] = value
+    this.setState({
+      settings: this.state.settings
+    })
+  }
+
+  render() {
+    return (
+      <View style={ui.flex1}>
+        <Text style={styles.title}>Maps</Text>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => this.changeSwitch('alwaysLocation', !this.state.settings.alwaysLocation)}>
+          <Text style={styles.buttonText}>Always show my locations</Text>
+          <Switch
+            value={this.state.settings.alwaysLocation}
+            trackColor={isIOS ? { false: "#B2B2B2", true: colorAccent } : null}
+            onValueChange={v => {
+              this.changeSwitch('alwaysLocation', v);
+            }}/>
+        </Button>
+        <View style={{height: 56}}>
+          <View style={styles.dropdownView}>
+            <Text style={styles.buttonText}>Auto refresh interval</Text>
+            <Text style={styles.settingText}>{this.state.settings.refreshInterval}s</Text>
+          </View>
+          <Dropdown
+            style={styles.hideItem}
+            list={this.state.intervalList}
+            title="Refresh interval"
+            suffixList="s"
+            value={this.state.settings.refreshInterval}
+            rippleStyle={ripple}
+            onChange={v => this.changeSettings("refreshInterval", v)}
+          />
+        </View>
+        
+      </View>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  title: {
+    color: '#888',
+    fontSize: 12,
+    ...$padding(8, 16, 4),
+    backgroundColor: 'white'
+  },
+  itemButton: {
+    borderRadius: 0,
+    backgroundColor: 'white'
+  },
+  itemView: {
+    flex: 1,
+    height: 56,
+    paddingLeft: 16,
+    paddingRight: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  buttonText: {
+    flex: 1,
+    color: '#333',
+    fontSize: 16
+  },
+  settingText: {
+    color: '#666',
+    fontSize: 15
+  },
+  dropdownView: {
+    top: 0,
+    left: 0,
+    right: 0,
+    height: 56,
+    paddingLeft: 16,
+    paddingRight: 16,
+    position: 'absolute',
+    alignItems: 'center',
+    flexDirection: 'row',
+    backgroundColor: 'white'
+  },
+  hideItem: {
+    flex: 1,
+    height: 56,
+    opacity: 0,
+    paddingLeft: 16,
+    paddingRight: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  }
+})

+ 13 - 0
Strides-APP/app/pages/home/Drawer.js

@@ -326,6 +326,19 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
         />
         <Text style={styles.label}>FAQs</Text>
       </Button>
+      <Button
+        style={styles.itemButton}
+        viewStyle={styles.itemView}
+        onClick={() => {
+          startPage(PageList.settings);
+        }}>
+        <Ionicons
+          style={styles.icon2}
+          name="settings-outline"
+          color="#333"
+          size={24}/>
+        <Text style={styles.label}>Settings</Text>
+      </Button>
       <Button
         style={styles.itemButton}
         viewStyle={styles.itemView}

+ 21 - 8
Strides-APP/app/pages/home/Home.js

@@ -10,6 +10,7 @@ import Dialog from '../../components/Dialog';
 import { Styles } from '../../components/Toolbar';
 import utils from '../../utils/utils';
 import { PageList } from '../Router';
+import { SettingUtil } from '../Settings';
 import Maps from './maps/Maps';
 import MapTool from './maps/MapTool';
 import TopInfo from './maps/TopInfo';
@@ -32,6 +33,7 @@ export default class HomePage extends Component {
     this.denied = true;
     this.backSeconds = 0;
     this.refreshTime = 0;
+    this.settingInfo = {}
     this.filter = {
       parkingFee: 'ALL',
       connectorType: ''
@@ -45,7 +47,12 @@ export default class HomePage extends Component {
       this.setState({
         stationInfo: {}
       });
-      this.checkPermission2Geo();
+      SettingUtil.getSettings(set => {
+        console.log("获取设置信息", set);
+        this.settingInfo = set;
+        this.checkPermission2Geo();
+      })
+      
     });
 
     navigation.addListener('blur', () => {
@@ -87,8 +94,12 @@ export default class HomePage extends Component {
     });
   }
 
-  checkPermission2Geo() {
+  checkPermission2Geo(refresh) {
     if (this.state.hasPermission) {
+      if (refresh) {
+        //避免关闭自动移动地图后无法点击按钮移动地图
+        this.state.stopList = []
+      }
       this.infoGeoLocation();
       return;
     }
@@ -164,10 +175,12 @@ export default class HomePage extends Component {
         //console.log("getGeoLocation", region);
         //if (this.state.stopList.length == 0) { //只加载一次
         let time = new Date().getTime();
-        if (this.state.stopList.length == 0 || time - this.refreshTime > 10000) { //一分钟(10秒)加载一次
-          this.getStationList(region);
+        let interval = this.settingInfo.refreshInterval * 1000;
+        let first = this.state.stopList.length == 0;
+        if (first || time - this.refreshTime > interval) { //一分钟(10秒)加载一次
+          this.getStationList(region, first);
           this.refreshTime = time;
-        } else {
+        } else if (this.settingInfo.alwaysLocation) {
           this.setState({
             region: region
           });
@@ -188,7 +201,7 @@ export default class HomePage extends Component {
     this.getStationList();
   }
 
-  getStationList(region) {
+  getStationList(region, first) {
     Dialog.showProgressDialog('Loading...');
     apiStation.getAllStation(this.filter).then(res => {
       Dialog.dismissLoading();
@@ -218,7 +231,7 @@ export default class HomePage extends Component {
         this.setState({
           stopList: list
         });
-        if (region) {
+        if (region && (this.settingInfo.alwaysLocation || first)) {
           setTimeout(() => {
             this.setState({
               region: region
@@ -318,7 +331,7 @@ export default class HomePage extends Component {
             count={this.state.stopList.length}
             mapReady={this.state.mapReady}
             onFilter={data => this.findFilter(data)}
-            onLocation={() => this.checkPermission2Geo()}
+            onLocation={() => this.checkPermission2Geo(true)}
           />
         </View>
         <View style={styles.drawerLeftTouchView}></View>

+ 1 - 1
Strides-APP/app/pages/my/EditProfile.js

@@ -76,7 +76,7 @@ const EditDialog = ({visible, title, value, keyType, countryList, areaNo, showCa
           { showCalling &&
             <Dropdown
               title='Country'
-              extraText="+"
+              prefixText="+"
               list={countryList}
               value={callingCode}   
               nameKey='countryNum'

+ 38 - 0
Strides-APP/app/pages/my/Profile.js

@@ -7,6 +7,7 @@ import { View, Text, StyleSheet, Image, ScrollView, Switch, Pressable } from 're
 import apiUser from '../../api/apiUser';
 import { host } from '../../api/http';
 import Button, { ElevationObject } from '../../components/Button';
+import Dialog from '../../components/Dialog';
 import { StationBack } from '../../components/Toolbar';
 import utils from '../../utils/utils';
 import { PageList } from '../Router';
@@ -85,6 +86,33 @@ export default class Profile extends Component {
     apiUser.setNotifySwitch(userInfo);
   }
 
+  deleteAccount() {
+    Dialog.showDialog({
+      title: 'Delete My Account',
+      message: 'Are you sure you want to delete your account? This operation cannot be revoke.',
+      ok: 'CONFIRM',
+      callback: button => {
+        if (button == Dialog.BUTTON_OK) {
+          this.deleteMyAccount();
+        }
+      }
+    })
+  }
+
+  deleteMyAccount() {
+    Dialog.showProgressDialog();
+    apiUser.deleteAccount().then(res => {
+      toastShort('Successfully deleted!')
+      Dialog.dismissLoading();
+      setTimeout(() => {
+        startPage(PageList.login);
+      }, 500);
+    }).catch(err => {
+      Dialog.dismissLoading();
+      toastShort(err)
+    })
+  }
+
   render() {
     return (
       <ScrollView style={styles.container}>
@@ -235,6 +263,12 @@ export default class Profile extends Component {
               }}/>
           </Pressable>
         </View>
+        <Button
+          style={styles.deleteButton}
+          text="DELETE MY ACCOUNT"
+          textColor="#fff"
+          onClick={() => this.deleteAccount()}
+        />
       </ScrollView>
     );
   }
@@ -376,5 +410,9 @@ const styles = StyleSheet.create({
   divide: {
     borderTopWidth: 1,
     borderTopColor: '#eee'
+  },
+  deleteButton: {
+    ...$margin(32, 16, 16),
+    backgroundColor: '#EA0A2A'
   }
 })

+ 2 - 1
Strides-APP/app/pages/sign/Login.js

@@ -126,7 +126,8 @@ export default class Login extends React.Component {
         } else {
           setStorageJson('loginData', {});
         }
-        this.props.navigation.goBack();
+        startPage(PageList.home);
+        //this.props.navigation.goBack();
       } else {
         toastShort(res.msg);
         Dialog.dismissLoading();

+ 1 - 1
Strides-APP/app/pages/sign/Register.js

@@ -340,7 +340,7 @@ export default class Register extends React.Component {
                   <Dropdown
                     style={styles.dropLayer}
                     title='Country'
-                    extraText="+"
+                    prefixText="+"
                     list={this.state.countryNums}
                     value={this.state.countryNum}
                     nameKey='countryNum'