Ver Fonte

重构APP:重构iOS端原生项目
NodeJS:v12.22.1 → v16.20.2
React:v17.0.1 → v18.2.0
ReactNative:v0.64.4 → v0.72.4
Ruby:v2.6.0 → 2.6.10
Gem:v2.2.0.1 → v3.0.3.1
Cocoapods:v1.12 → v1.12.1

vbea há 2 anos atrás
pai
commit
ecac07833c

+ 6 - 5
Strides-APP/README.md

@@ -103,7 +103,7 @@ Application ID: com.strides.chargeco
 [动画库-Reanimated](https://docs.swmansion.com/react-native-reanimated/docs/)   
 [矢量图标集](https://oblador.github.io/react-native-vector-icons/)  
 [React Native常用库查询](https://reactnative.directory/)  
-[React Native教程集合](https://github.com/reactnativecn/react-native-guide)
+[React Native教程集合](https://github.com/reactnativecn/react-native-guide)  
 [React Native Firebase](https://rnfirebase.io/)
 
 ## Library Used
@@ -136,7 +136,7 @@ Application ID: com.strides.chargeco
 [RNWebView](https://github.com/react-native-webview/react-native-webview)  
 [react-native-device-info](https://github.com/react-native-device-info/react-native-device-info)  
 [微软热更新react-native-code-push](https://learn.microsoft.com/zh-cn/appcenter/distribution/codepush/)  
-[国际化react-native-i18n](https://github.com/AlexanderZaytsev/react-native-i18n)
+[国际化react-native-i18n](https://github.com/AlexanderZaytsev/react-native-i18n)  
 
 ## 文章
 https://blog.csdn.net/first_helloword/article/details/109903486  
@@ -149,15 +149,16 @@ https://stackoverflow.com/questions/36685372/how-to-zoom-in-out-in-react-native-
 https://stackoverflow.com/questions/57227291/victory-native-events-props-not-working-in-react-native-event-not-firing-in/57723808  
 https://www.jianshu.com/p/0a51624dee2f  
 https://www.jianshu.com/p/8f75eb58b030  
-https://www.cnblogs.com/sundaysgarden/p/10357051.html
+https://www.cnblogs.com/sundaysgarden/p/10357051.html  
 
 ## 踩坑记
 [疑难杂症之module map file not found](https://blog.csdn.net/weixin_43883776/article/details/106793263)  
 
 ## iOS16专题
-https://github.com/facebook/react-native/issues/32496
-https://stackoverflow.com/questions/71597475/symbols-not-found-for-architecture-arm64-xcode
+https://github.com/facebook/react-native/issues/32496  
+https://stackoverflow.com/questions/71597475/symbols-not-found-for-architecture-arm64-xcode  
 
 ## RN 0.72踩坑记
 https://stackoverflow.com/questions/71702392/viewproptypes-will-be-removed-from-react-native-migrate-to-viewproptypes-export  
 https://stackoverflow.com/questions/55664673/require-cycles-are-allowed-but-can-result-in-uninitialized-values-consider-ref  
+https://www.jianshu.com/p/dd7c5d002303  

+ 6 - 2
Strides-APP/app/components/Dropdown.js

@@ -148,8 +148,8 @@ export default Dropdown = ({
         onPress={() => showList()}>
         { showText && 
           ( selected 
-            ? <TextView style={[textStyle, ui.flex1]} numberOfLines={1}>{selected}</TextView>
-            : <TextView style={[placeholderStyle, ui.flex1]} numberOfLines={1}>{placeholder}</TextView>
+            ? <TextView style={[textStyle, styles.textView]} numberOfLines={1}>{selected}</TextView>
+            : <TextView style={[placeholderStyle, styles.textView]} numberOfLines={1}>{placeholder}</TextView>
           )
         }
         { showIcon && (isIOS
@@ -238,5 +238,9 @@ const styles = StyleSheet.create({
   },
   iconStyle: {
     marginLeft: 8
+  },
+  textView: {
+    flex: 1,
+    flexDirection: 'column'
   }
 });

+ 16 - 10
Strides-APP/app/components/TextView.js

@@ -5,7 +5,7 @@
 import React from 'react';
 import { Text, View } from 'react-native';
 
-const getRadius = (style) => {
+const getRadius = (style, fixedAlign) => {
   let s = undefined;
   if (Array.isArray(style)) {
     let res = {}
@@ -52,22 +52,28 @@ const getRadius = (style) => {
     }
     view[name] = s[name];
   }
-  //修复RN0.7x+渲染中文无法对齐
-  if (text.fontSize) {
-    text.lineHeight = text.fontSize * 1.3;
-  } else {
-    text.fontSize = 14;
-    text.lineHeight = 18.2;
+  if (fixedAlign) {
+    //修复RN0.7x+渲染中文无法对齐
+    if (view.alignItems == undefined && view.flexDirection == undefined && text.textAlign == undefined) {
+      view.alignItems = "center";
+      view.flexDirection = "row";
+    }
+    if (text.fontSize) {
+      text.lineHeight = text.fontSize * 1.3;
+    } else {
+      text.fontSize = 14;
+      text.lineHeight = 18.2;
+    }
+    text.includeFontPadding = false;
   }
-  text.includeFontPadding = false;
   return {
     view: view,
     text: text
   }
 }
 
-const TextView = ({style, ellipsizeMode, numberOfLines, allowFontScaling=false, onPress, onLongPress, children}) => {
-  const styles = getRadius(style);
+const TextView = ({style, ellipsizeMode, numberOfLines, allowFontScaling=false, onPress, onLongPress, fixedAlign=true, children}) => {
+  const styles = getRadius(style, fixedAlign);
   return (
     <View style={styles.view}>
       <Text

+ 31 - 75
Strides-APP/app/pages/home/Drawer.js

@@ -209,10 +209,10 @@ const DrawerContent = ({isLogin, userInfo, onLogout, notificationCount=0, naviga
               source={require('../../images/user/ic-avatar-default.png')}/>
           </TouchableWithoutFeedback>
         }
-        <Pressable
+        <Button
           style={styles.nickView}
-          android_ripple={ripple}
-          onPress={() => startPage(isLogin ? PageList.profile : PageList.login)}>
+          viewStyle={styles.nickViewStyle}
+          onClick={() => startPage(isLogin ? PageList.profile : PageList.login)}>
           <TextView
             style={styles.nickname}
             ellipsizeMode='tail'
@@ -228,46 +228,9 @@ const DrawerContent = ({isLogin, userInfo, onLogout, notificationCount=0, naviga
             size={24}
             color='#999'
             name='angle-right'/>
-        </Pressable>
+        </Button>
       </View> 
       <View style={styles.divideLogin}></View>
-      {/* isLogin
-        ? <Button
-            style={styles.itemButton}
-            viewStyle={styles.itemView}
-            onClick={() => {
-              startPage(PageList.profile)
-            }}>
-            <Image
-              style={styles.icon}
-              source={require('../../images/icon/draw-user.png')}/>
-            <Text style={styles.label}>Profile Settings</Text>
-          </Button>
-        : <Button
-            style={styles.itemButton}
-            viewStyle={styles.itemView}
-            onClick={() => {
-              startPage(PageList.login); 
-            }}>
-            <Image
-              style={styles.icon}
-              source={require('../../images/icon/draw-user.png')}/>
-            <Text style={styles.label}>Sign In</Text>
-          </Button>
-      */}
-
-      {/* <Button
-        style={styles.itemButton}
-        viewStyle={styles.itemView}
-        onClick={() => {
-          navigation.toggleDrawer();
-        }}>
-        <Image
-          style={styles.icon}
-          source={require('../../images/icon/draw-home.png')}/>
-        <Text style={styles.label}>Home</Text>
-      </Button> */}
-
       { isLogin
         ? <Button
             style={styles.itemButton}
@@ -298,26 +261,6 @@ const DrawerContent = ({isLogin, userInfo, onLogout, notificationCount=0, naviga
             <TextView style={styles.disable}>{$t('drawer.charging')}</TextView>
           </View>
       }
-      {/* isLogin
-        ? <Button
-            style={styles.itemButton}
-            viewStyle={styles.itemView}
-            onClick={() => {
-              startPage(PageList.wallet);
-            }}>
-            <Image
-              style={styles.icon}
-              source={require('../../images/icon/draw-transaction.png')}/>
-            <Text style={styles.label}>{$t('drawer.wallet')}</Text>
-          </Button>
-        : <View
-            style={styles.disableItem}>
-            <Image
-              style={styles.icon}
-              source={require('../../images/icon/draw-transaction-no.png')}/>
-            <Text style={styles.disable}>{$t('drawer.wallet')}</Text>
-          </View>
-      */}
       {
         isLogin && <>
         <Button
@@ -341,7 +284,7 @@ const DrawerContent = ({isLogin, userInfo, onLogout, notificationCount=0, naviga
             name={"wallet-outline"}
             color={colorDark}/>
           <TextView style={styles.label}>{$t('drawer.topup')}</TextView>
-          <TextView style={styles.balanceText2}>{userInfo.creditStr}</TextView>
+          <Text style={styles.balanceText2}>{userInfo.creditStr}</Text>
         </Button></>
       }
 
@@ -361,8 +304,13 @@ const DrawerContent = ({isLogin, userInfo, onLogout, notificationCount=0, naviga
           <TextView style={styles.label}>{$t('route.notifications')}</TextView>
           { notificationCount > 0 && (
             notificationCount < 100
-            ? <Text style={styles.bridgeText} allowFontScaling={false}>{notificationCount}</Text>
-            : <Text style={styles.bridgeText2} allowFontScaling={false}>99+</Text>)
+            ? <TextView
+                style={styles.bridgeText}
+                fixedAlign={false}>{notificationCount}</TextView>
+            : <TextView
+                style={styles.bridgeText2}
+                fixedAlign={false}>99+</TextView>
+            )
           }
         </Button>
       }
@@ -598,7 +546,7 @@ const styles = StyleSheet.create({
   },
   loginView: {
     paddingTop: 16,
-    paddingBottom: 8
+    paddingBottom: 4
   },
   avatar: {
     width: 66,
@@ -609,9 +557,15 @@ const styles = StyleSheet.create({
     borderColor: colorLight,
   },
   nickView: {
-    marginTop: 4,
+    marginTop: 6,
+    borderRadius: 0,
+    backgroundColor: colorLight
+  },
+  nickViewStyle: {
+    flex: 1,
+    alignItems: 'center',
     flexDirection: 'row',
-    ...$padding(12, 16)
+    ...$padding(12, 24, 12, 16),
   },
   nickname: {
     flex: 1,
@@ -623,7 +577,7 @@ const styles = StyleSheet.create({
   divideLogin: {
     height: 1,
     marginTop: 4,
-    marginRight: 32,
+    marginRight: 22,
     marginBottom: 12,
     backgroundColor: '#E5E5E5'
   },
@@ -714,18 +668,19 @@ const styles = StyleSheet.create({
   balanceText2: {
     color: textCancel,
     fontSize: 14,
-    marginRight: 32
+    marginRight: 20
   },
   bridgeText: {
     width: 20,
     height: 20,
     color: textLight,
     fontSize: 12,
-    lineHeight: 19,
     marginRight: 16,
-    borderRadius: 20,
+    borderRadius: 30,
     fontWeight: 'bold',
-    textAlign: 'center',
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
     backgroundColor: "#FF3B30"
   },
   bridgeText2: {
@@ -733,11 +688,12 @@ const styles = StyleSheet.create({
     height: 22,
     color: textLight,
     fontSize: 10,
-    lineHeight: 22,
     marginRight: 16,
-    borderRadius: 22,
+    borderRadius: 30,
     fontWeight: 'bold',
-    textAlign: 'center',
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
     backgroundColor: "#FF3B30"
   }
 });

+ 2 - 0
Strides-APP/app/pages/home/maps/Cluster.js

@@ -11,6 +11,7 @@ export const MyMarker = ({id, coordinate, onPress}) => {
   return (
     <Marker
       key={id}
+      zIndex={1}
       coordinate={coordinate}
       onPress={onPress}>
       { coordinate.favorite
@@ -43,6 +44,7 @@ export const MyCluster = (props) => {
       key={id}
       style={{ zIndex: pointCount + 1 }}
       coordinate={location}
+      zIndex={pointCount + 1}
       onPress={() => onOpen ? onOpen(location) : onPress()}>
       <ClusterView pointCount={pointCount} available={available}/>
     </Marker>

+ 119 - 45
Strides-APP/app/pages/my/EditAddress.js

@@ -1,35 +1,68 @@
 import React, { Component } from 'react';
-import { View, Text, StyleSheet, TextInput } from 'react-native';
+import { View, Text, StyleSheet, TextInput, ScrollView } from 'react-native';
 import Button from '../../components/Button';
+import { CountryDropCode, GetCountryList } from '../../components/CountryIcon';
+import Dropdown from '../../components/Dropdown';
 
 export default class EditAddress extends Component {
   constructor(props) {
     super(props);
     this.state = {
-      addressDto: userInfo.address ?? {}
+      addressDto: {
+        countryCode: "",
+        city: "",
+        street: "",
+        zipCode: "",
+        houseNumber: ""
+      }
     };
   }
 
   componentDidMount() {
+    const address = userInfo.address ?? {}
+    if (!address.countryCode) {
+      address.countryCode = "SG"
+    }
+    this.setState({
+      addressDto: address,
+      countryList: [],
+    })
     userInfo.editAddress = false;
+    GetCountryList(list => {
+      this.setState({
+        countryList: list
+      })
+    })
+  }
+
+  changeCountry(value, index) {
+    this.state.addressDto.countryCode = value;
+    this.setState({
+      addressDto: this.state.addressDto
+    })
   }
 
   saveInfo() {
     const dto = this.state.addressDto
+    if (!dto.city) {
+      toastShort($t('profile.plsInputCity'));
+      return;
+    }
     if (!dto.street) {
-      toastShort('Please input street');
+      toastShort($t('profile.plsInputStreet'));
       return;
     }
     if (!dto.houseNumber) {
-      toastShort('Please input unit number');
+      toastShort($t('profile.plsInputUnitNo'));
       return;
     }
     if (!dto.zipCode) {
-      toastShort('Please input postal code');
+      toastShort($t('profile.plsInputPostal'));
       return;
     }
     userInfo.address = dto;
     userInfo.addressLine = dto.houseNumber + ', ' + dto.street + ', ' + dto.zipCode
+    console.log(userInfo.addressLine);
     userInfo.editAddress = true;
     goBack();
   }
@@ -37,43 +70,74 @@ export default class EditAddress extends Component {
   render() {
     return (
       <View style={styles.container}>
-        <View style={styles.formView}>
-          <Text style={styles.label}>Street</Text>
-          <TextInput
-            style={styles.formInput}
-            placeholder='Street name and number'
-            placeholderTextColor={textPlacehoder}
-            maxLength={50}
-            defaultValue={this.state.addressDto?.street}
-            onChangeText={text => this.state.addressDto.street = text}
-          />
-        </View>
-        <View style={styles.formView}>
-          <Text style={styles.label}>Unit Number</Text>
-          <TextInput
-            style={styles.formInput}
-            placeholder='Unit number'
-            placeholderTextColor={textPlacehoder}
-            maxLength={15}
-            defaultValue={this.state.addressDto?.houseNumber}
-            onChangeText={text => this.state.addressDto.houseNumber = text}
-          />
-        </View>
-        <View style={styles.formView}>
-          <Text style={styles.label}>Postal Code</Text>
-          <TextInput
-            style={styles.formInput}
-            placeholder='Postal Code'
-            placeholderTextColor={textPlacehoder}
-            maxLength={10}
-            defaultValue={this.state.addressDto?.zipCode}
-            onChangeText={text => this.state.addressDto.zipCode = text}
-          />
-        </View>
-        <Text style={ui.flex1}></Text>
+        <ScrollView style={ui.flex1}>
+          <View style={styles.formView}>
+            <Text style={styles.label}>{$t('sign.labelCountry')}</Text>
+            <Dropdown
+              style={styles.selectView}
+              title={$t('sign.labelCountry')}
+              list={this.state.countryList}
+              value={this.state.addressDto.countryCode}
+              nameKey='countryName'
+              valueKey='countryCode'
+              onChange={(value, index)=> this.changeCountry(value, index)}
+              customerItemView={
+                (item, index, onClick) => 
+                <CountryDropCode
+                  key={index} 
+                  country={item}
+                  value={this.state.addressDto.countryCode}
+                  onClick={onClick}/>
+              }/>
+          </View>
+          <View style={styles.formView}>
+            <Text style={styles.label}>{$t('profile.labelCity')}</Text>
+            <TextInput
+              style={styles.formInput}
+              placeholder={$t('profile.labelCity')}
+              maxLength={50}
+              placeholderTextColor={textPlacehoder}
+              defaultValue={this.state.addressDto?.city}
+              onChangeText={text => this.state.addressDto.city = text}
+            />
+          </View>
+          <View style={styles.formView}>
+            <Text style={styles.label}>{$t('profile.street')}</Text>
+            <TextInput
+              style={styles.formInput}
+              placeholder={$t('profile.hintStreet')}
+              maxLength={50}
+              placeholderTextColor={textPlacehoder}
+              defaultValue={this.state.addressDto?.street}
+              onChangeText={text => this.state.addressDto.street = text}
+            />
+          </View>
+          <View style={styles.formView}>
+            <Text style={styles.label}>{$t('profile.unitNumber')}</Text>
+            <TextInput
+              style={styles.formInput}
+              placeholder={$t('profile.hintUnitNo')}
+              maxLength={15}
+              placeholderTextColor={textPlacehoder}
+              defaultValue={this.state.addressDto?.houseNumber}
+              onChangeText={text => this.state.addressDto.houseNumber = text}
+            />
+          </View>
+          <View style={styles.formView}>
+            <Text style={styles.label}>{$t('profile.postalCode')}</Text>
+            <TextInput
+              style={styles.formInput}
+              placeholder={$t('profile.hintPostal')}
+              maxLength={10}
+              placeholderTextColor={textPlacehoder}
+              defaultValue={this.state.addressDto?.zipCode}
+              onChangeText={text => this.state.addressDto.zipCode = text}
+            />
+          </View>
+        </ScrollView>
         <View style={styles.buttonView}>
           <Button
-            text='Save'
+            text={$t('common.save')}
             elevation={1.5}
             onClick={() => {
               this.saveInfo();
@@ -87,7 +151,7 @@ export default class EditAddress extends Component {
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    backgroundColor: 'white'
+    backgroundColor: pageBackground
   },
   formView: {
     paddingTop: 16,
@@ -95,19 +159,29 @@ const styles = StyleSheet.create({
     paddingRight: 16,
     paddingBottom: 4
   },
+  selectView: {
+    marginTop: 4,
+    marginBottom: -8,
+    ...$padding(8, 0, 8, 4),
+    alignItems: 'center',
+    flexDirection: 'row',
+    borderBottomColor: '#EEE',
+    borderBottomWidth: 1
+  },
   label: {
-    color: '#333',
+    color: textPrimary,
     fontSize: 14
   },
   formInput: {
-    color: '#333',
+    color: textPrimary,
     fontSize: 14,
+    height: 44,
     paddingBottom: 2,
     borderBottomColor: '#EEE',
     borderBottomWidth: 1
   },
   buttonView: {
     padding: 16,
-    marginBottom: 16
-  },
+    marginBottom: 4
+  }
 })

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

@@ -441,6 +441,7 @@ const styles = StyleSheet.create({
   nickInput: {
     flex: 1,
     color: textPrimary,
+    minHeight: 43,
     fontSize: 14,
     paddingTop: 8,
     paddingLeft: 16,

+ 28 - 24
Strides-APP/app/pages/my/Feedback.js

@@ -74,7 +74,7 @@ export default class Feedback extends React.Component {
   noTypeDialog() {
     setTimeout(() => {
       if (this.pageShow) {
-        Dialog.showResultDialog('Can not fetch feedback type!', 'OK', back => {
+        Dialog.showResultDialog($t('feedback.errFetchType'), $t('nav.ok'), back => {
           goBack();
         });
       }
@@ -94,7 +94,7 @@ export default class Feedback extends React.Component {
     }, () => {
       setTimeout(() => {
         this.getChargeBox(searchId)
-      }, 400);
+      }, 300);
     });
   }
 
@@ -153,8 +153,9 @@ export default class Feedback extends React.Component {
             this.setState({
               imageUrl: imageUrl
             });
+            toastShort($t('common.uploadSuccess'));
           } else {
-            toastShort('Upload failed, please retry');
+            toastShort($t('common.uploadFailed'));
           }
         }).catch(err => {
           toastShort(err);
@@ -167,11 +168,11 @@ export default class Feedback extends React.Component {
 
   submitFeedback() {
     if (this.state.typeOfFeedback == '') {
-      toastShort('Please select type of feedback');
+      toastShort($t('feedback.errFeedbackType'));
       return;
     }
     if (this.state.feedback == '') {
-      toastShort('Please type feedback content');
+      toastShort($t('feedback.errFeednackContent'));
       return;
     }
     const params = {
@@ -186,7 +187,7 @@ export default class Feedback extends React.Component {
     Dialog.showProgressDialog();
     apiUser.feedback(params).then(res => {
       Dialog.dismissLoading();
-      Dialog.showResultDialog('Send feedback successfully!', 'OK', back => {
+      Dialog.showResultDialog($t('feedback.sendSuccess'), $t('nav.ok'), back => {
         goBack();
       });
     }).catch(err => {
@@ -222,8 +223,8 @@ export default class Feedback extends React.Component {
         contentInsetAdjustmentBehavior='automatic'>
         <View style={styles.headerView}>
           <View style={ui.flex1}>
-            <Text style={styles.title}>Have something to tell us?</Text>
-            <Text style={styles.content}>Please let us know below!</Text>
+            <Text style={styles.title}>{$t('feedback.tipsSomething')}</Text>
+            <Text style={styles.content}>{$t('feedback.tipsLetKnow')}</Text>
           </View>
           <Image
             style={styles.headerImage}
@@ -232,32 +233,33 @@ export default class Feedback extends React.Component {
         </View>
         
         <View style={styles.contentView}>
-          <Text style={styles.typeTitle}>Type of Feedback</Text>
+          <Text style={styles.typeTitle}>{$t('feedback.typeOfFeedback')}</Text>
           <View style={styles.pickerView}>
             <Dropdown
               style={styles.pickerViewInfo}
-              title='Type of Feedback'
+              title={$t('feedback.typeOfFeedback')}
               list={this.state.typeList}
               value={this.state.typeOfFeedback}
               nameKey={'value'}
               valueKey={'key'}
-              placeholder='Select'
+              placeholder={$t('common.select')}
               onChange={(value, index) => this.changeType(value, index)}/>
           </View>
           
-          <Text style={styles.typeTitle}>Please fill in here (500 words)</Text>
+          <Text style={styles.typeTitle}>{$t('feedback.labelContent')}</Text>
           <TextInput
             style={styles.feedbackInput}
             multiline={true}
-            maxLength={1000}
             numberOfLines={8}
+            maxLength={1000}
             textAlignVertical='top'
             onChangeText={text => {
               this.setState({
                 feedback: text
               });
             }}/>
-          <Text style={styles.typeTitle}>Please upload relevant images</Text>
+          
+          <Text style={styles.typeTitle}>{$t('feedback.labelUpload')}</Text>
           <View
             style={styles.uploadGroup}>
             { this.state.imageUrl.map((item, index) => {
@@ -282,8 +284,9 @@ export default class Feedback extends React.Component {
               })
             }
           </View>
+
           {this.state.typeOfFeedback == "csf" && <>
-            <Text style={styles.typeTitle}>Which charging station?</Text>
+            <Text style={styles.typeTitle}>{$t('feedback.labelStation')}</Text>
             <Pressable
               style={[styles.pickerView, styles.stationView]}
               android_ripple={ripple}
@@ -295,20 +298,20 @@ export default class Feedback extends React.Component {
               />
               <Text style={styles.textStation}>{this.state.chargeBoxId}</Text>
             </Pressable>
-            <Text style={styles.typeTitle}>Which connecter?</Text>
+            <Text style={styles.typeTitle}>{$t('feedback.labelConnector')}</Text>
             <View style={styles.pickerView}>
               <Dropdown
                 style={styles.pickerViewInfo}
-                title="Select a Connecter"
+                title={$t('feedback.selectConnector')}
                 list={this.state.connectorList}
                 value={this.state.connectorId}
-                placeholder="Select"
+                placeholder={$t('common.select')}
                 onChange={value => this.changeConnector(value)}/>
             </View>
           </>}
           <Button
             style={styles.button}
-            text='Submit Feedback'
+            text={$t('feedback.submitFeedback')}
             elevation={1.5}
             onClick={() => {
               this.submitFeedback();
@@ -333,7 +336,7 @@ export default class Feedback extends React.Component {
               <TextInput
                 style={styles.inputView}
                 maxLength={50}
-                placeholder="Searching for ChargeBoxId"
+                placeholder={$t('feedback.searchingChargeBox')}
                 onChangeText={text => this.listChargeBox(text)}
               />
             </View>
@@ -348,7 +351,7 @@ export default class Feedback extends React.Component {
                 data={this.state.chargeBoxList}
                 keyExtractor={(item,index) => index}
                 renderItem={this.listItem}
-                ListEmptyComponent={<Text style={styles.noResult}>No Station</Text>}
+                ListEmptyComponent={<Text style={styles.noResult}>{$t('home.noSearch')}</Text>}
               />
             }
           </View>
@@ -442,7 +445,7 @@ const styles = StyleSheet.create({
   pickerViewInfo: {
     height: 44,
     paddingLeft: 16,
-    paddingRight: 32,
+    paddingRight: 8,
     alignItems: 'center',
     flexDirection: 'row'
   },
@@ -497,7 +500,8 @@ const styles = StyleSheet.create({
     fontSize: 15
   },
   seachingIcon: {
-    width: 100,
-    height: 100
+    width: 50,
+    height: 50,
+    marginTop: 20
   }
 })

+ 48 - 26
Strides-APP/ios/Podfile

@@ -4,8 +4,19 @@ require Pod::Executable.execute_command('node', ['-p',
     "react-native/scripts/react_native_pods.rb",
     {paths: [process.argv[1]]},
   )', __dir__]).strip
+require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
+def node_require(script)
+  # Resolve script with node to allow for hoisting
+  require Pod::Executable.execute_command('node', ['-p',
+    "require.resolve(
+      '#{script}',
+      {paths: [process.argv[1]]},
+  )", __dir__]).strip
+end
+node_require('react-native/scripts/react_native_pods.rb')
+node_require('react-native-permissions/scripts/setup.rb')
 
-platform :ios, min_ios_version_supported
+platform :ios, '13.0'
 prepare_react_native_project!
 
 # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
@@ -25,34 +36,41 @@ if linkage != nil
   use_frameworks! :linkage => linkage.to_sym
 end
 
+#权限处理
+setup_permissions([
+  'AppTrackingTransparency', #访问设备的广告标识符
+  # 'BluetoothPeripheral', #访问蓝牙
+  # 'Calendars', #访问日历
+  'Camera', #访问相机
+  # 'Contacts', #访问联系人
+  # 'FaceID', #访问FaceID
+  'LocationAccuracy', #访问高精度定位
+  # 'LocationAlways', #始终访问位置信息
+  'LocationWhenInUse', #在使用中访问位置信息
+  # 'MediaLibrary', #使用媒体库
+  # 'Microphone', #使用麦克风
+  # 'Motion', #运动权限
+  'Notifications', #使用通知
+  'PhotoLibrary', #使用照片库
+  'PhotoLibraryAddOnly', #添加照片
+  # 'Reminders',
+  # 'SpeechRecognition',
+  # 'StoreKit'
+])
+
 target 'Strides' do
   config = use_native_modules!
 
   # Flags change depending on the env values.
   flags = get_default_flags()
 
-  pod 'react-native-google-maps', :path => '../node_modules/react-native-maps'
-  #pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
-  permissions_path = '../node_modules/react-native-permissions/ios'
-  pod 'Permission-AppTrackingTransparency', :path => "#{permissions_path}/AppTrackingTransparency" #访问设备的广告标识符
-  #pod 'Permission-BluetoothPeripheral', :path => "#{permissions_path}/BluetoothPeripheral" #访问蓝牙
-  #pod 'Permission-Calendars', :path => "#{permissions_path}/Calendars" #访问日历
-  pod 'Permission-Camera', :path => "#{permissions_path}/Camera"  #访问相机
-  #pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts"  #访问联系人
-  #pod 'Permission-FaceID', :path => "#{permissions_path}/FaceID"  #访问FaceID
-  pod 'Permission-LocationAccuracy', :path => "#{permissions_path}/LocationAccuracy" #访问高精度定位
-  pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways" #始终访问位置信息
-  pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse" #在使用中访问位置信息
-  #pod 'Permission-MediaLibrary', :path => "#{permissions_path}/MediaLibrary" #使用媒体库
-  pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone"  #使用麦克风
-  #pod 'Permission-Motion', :path => "#{permissions_path}/Motion"  #运动权限
-  pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications" #使用通知
-  pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary" #使用照片库
-  pod 'Permission-PhotoLibraryAddOnly', :path => "#{permissions_path}/PhotoLibraryAddOnly" #添加照片
-  #pod 'Permission-Reminders', :path => "#{permissions_path}/Reminders"
-  #pod 'Permission-Siri', :path => "#{permissions_path}/Siri"
-  #pod 'Permission-SpeechRecognition', :path => "#{permissions_path}/SpeechRecognition"
-  #pod 'Permission-StoreKit', :path => "#{permissions_path}/StoreKit"
+  # 谷歌地图服务
+  pod 'Google-Maps-iOS-Utils', :git => 'https://github.com/Simon-TechForm/google-maps-ios-utils.git', :branch => 'feat/support-apple-silicon'
+  rn_maps_path = '../node_modules/react-native-maps'
+  pod 'react-native-google-maps', :path => rn_maps_path
+  # pod 'GoogleMaps', '3.5.0'
+  # pod 'Google-Maps-iOS-Utils', '2.1.0'
+
   #谷歌通知启用
   pod 'Firebase/Core', '9.4.0', :modular_headers => true
   pod 'Firebase/Analytics', '9.4.0', :modular_headers => true
@@ -87,8 +105,8 @@ target 'Strides' do
   #
   # Note that if you have use_frameworks! enabled, Flipper will not work and
   # you should disable the next line.
-  #use_flipper!()
-  #use_flipper!('Flipper' => '0.75.1', 'Flipper-Folly' => '2.5.3', 'Flipper-RSocket' => '1.3.1')
+  # use_flipper!()
+  # use_flipper!({'Flipper' => '0.182.0', 'Flipper-Folly' => '2.6.10', 'Flipper-RSocket' => '1.3.1'})
 
   #post_install do |installer|
   #  react_native_post_install(installer)
@@ -109,6 +127,11 @@ target 'Strides' do
       config[:reactNativePath],
       :mac_catalyst_enabled => false
     )
+    fix_library_search_paths(installer)
+    installer.pods_project.build_configurations.each do |config|
+      config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
+      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = "16.4"
+    end
     __apply_Xcode_12_5_M1_post_install_workaround(installer)
   end
 end
@@ -146,5 +169,4 @@ def fix_library_search_paths(installer)
     end
     project.save()
   end
-
 end

+ 4 - 24
Strides-APP/ios/Strides.xcodeproj/project.pbxproj

@@ -8,7 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		00E356F31AD99517003FC87E /* StridesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* StridesTests.m */; };
-		13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
+		13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
 		38066FC426DE16BF00271DFA /* main.jsbundle in Resources */ = {isa = PBXBuildFile; fileRef = 38066FC226DE16BF00271DFA /* main.jsbundle */; };
@@ -583,7 +583,7 @@
 		0B4312F6F31A03C548D2D34E /* Pods-Strides.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Strides.release.xcconfig"; path = "Target Support Files/Pods-Strides/Pods-Strides.release.xcconfig"; sourceTree = "<group>"; };
 		13B07F961A680F5B00A75B9A /* Strides.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Strides.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Strides/AppDelegate.h; sourceTree = "<group>"; };
-		13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Strides/AppDelegate.m; sourceTree = "<group>"; };
+		13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.mm; path = Strides/AppDelegate.m; sourceTree = "<group>"; };
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Strides/Images.xcassets; sourceTree = "<group>"; };
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Strides/Info.plist; sourceTree = "<group>"; };
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Strides/main.m; sourceTree = "<group>"; };
@@ -646,7 +646,7 @@
 				38066FC226DE16BF00271DFA /* main.jsbundle */,
 				38066FC126DDDB0700271DFA /* Strides.entitlements */,
 				13B07FAF1A68108700A75B9A /* AppDelegate.h */,
-				13B07FB01A68108700A75B9A /* AppDelegate.m */,
+				13B07FB01A68108700A75B9A /* AppDelegate.mm */,
 				13B07FB51A68108700A75B9A /* Images.xcassets */,
 				13B07FB61A68108700A75B9A /* Info.plist */,
 				3869FBE7299B96AE00B54A73 /* AppCenter-Config.plist */,
@@ -1580,7 +1580,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
+				13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
 				13B07FC11A68108700A75B9A /* main.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -1643,12 +1643,6 @@
 					"@loader_path/Frameworks",
 				);
 				OTHER_CFLAGS = (
-					"$(inherited)",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/FBLPromises/PromisesObjC.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/GoogleUtilities/GoogleUtilities.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/React/React-Core.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/yoga/Yoga.modulemap\"",
 					"$(inherited)",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_MOBILE=1",
@@ -1689,13 +1683,6 @@
 				);
 				MARKETING_VERSION = 2.4.5;
 				OTHER_CFLAGS = (
-					"$(inherited)",
-					"-fmodule-map-file=\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/FBLPromises/PromisesObjC.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/GoogleUtilities/GoogleUtilities.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/React/React-Core.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/yoga/Yoga.modulemap\"",
 					"$(inherited)",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_MOBILE=1",
@@ -1741,13 +1728,6 @@
 				);
 				MARKETING_VERSION = 2.4.5;
 				OTHER_CFLAGS = (
-					"$(inherited)",
-					"-fmodule-map-file=\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/FBLPromises/PromisesObjC.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/GoogleUtilities/GoogleUtilities.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/React/React-Core.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/SSZipArchive/SSZipArchive.modulemap\"",
-					"-fmodule-map-file=\"${PODS_ROOT}/Headers/Public/yoga/Yoga.modulemap\"",
 					"$(inherited)",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_MOBILE=1",

+ 2 - 1
Strides-APP/ios/Strides/AppDelegate.h

@@ -1,6 +1,7 @@
 #import <RCTAppDelegate.h>
 #import <UIKit/UIKit.h>
+#import <UserNotifications/UNUserNotificationCenter.h>
 
-@interface AppDelegate : RCTAppDelegate
+@interface AppDelegate : RCTAppDelegate <UNUserNotificationCenterDelegate>
 
 @end

+ 2 - 14
Strides-APP/ios/Strides/AppDelegate.mm

@@ -61,12 +61,6 @@ static void InitializeFlipper(UIApplication *application) {
           // ...
         }];
   [application registerForRemoteNotifications];
-
-  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
-  UIViewController *rootViewController = [UIViewController new];
-  rootViewController.view = rootView;
-  self.window.rootViewController = rootViewController;
-  [self.window makeKeyAndVisible];
   //return YES;
   return [super application:application didFinishLaunchingWithOptions:launchOptions];
 }
@@ -97,13 +91,7 @@ static void InitializeFlipper(UIApplication *application) {
 //Required for the register event.
 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
 {
-//  NSMutableString *hexString = [NSMutableString string];
-//  NSUInteger deviceTokenLength = deviceToken.length;
-//  const unsigned char *bytes = deviceToken.bytes;
-//  for (NSUInteger i = 0; i < deviceTokenLength; i++) {
-//    [hexString appendFormat:@"%02x", bytes[i]];
-//  }
-//  NSLog(@"APNs registration token: %@", hexString);
+  // NSLog(@"APNs registration token: %@", hexString);
   if ([FIRMessaging messaging].FCMToken != nil) {
     [FIRMessaging messaging].APNSToken = deviceToken;
     //NSLog(@"FIRMessaging token: %@", [FIRMessaging messaging].FCMToken);
@@ -135,7 +123,7 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
          withCompletionHandler:(void (^)(void))completionHandler
 {
   [RNCPushNotificationIOS didReceiveNotificationResponse:response];
-  completionHandler();
+  //completionHandler();
 }
 
 - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge

+ 3 - 4
Strides-APP/package.json

@@ -30,7 +30,7 @@
     "@react-native-community/art": "^1.2.0",
     "@react-native-community/checkbox": "^0.5.10",
     "@react-native-community/geolocation": "^3.0.5",
-    "@react-native-community/push-notification-ios": "^1.8.0",
+    "@react-native-community/push-notification-ios": "^1.11.0",
     "@react-native-masked-view/masked-view": "^0.2.9",
     "@react-navigation/drawer": "^6.6.3",
     "@react-navigation/material-top-tabs": "^6.6.3",
@@ -49,11 +49,11 @@
     "react-native-image-crop-picker": "^0.40.0",
     "react-native-map-clustering": "^3.4.2",
     "react-native-map-link": "^2.7.27",
-    "react-native-maps": "^2.0.0-beta.8",
+    "react-native-maps": "2.0.0-beta.8",
     "react-native-modal": "^13.0.1",
     "react-native-modal-datetime-picker": "^17.1.0",
     "react-native-pager-view": "^6.2.0",
-    "react-native-permissions": "3.8.4",
+    "react-native-permissions": "^3.9.0",
     "react-native-progress": "^4.1.2",
     "react-native-push-notification": "^8.1.1",
     "react-native-qrcode-scanner": "^1.5.4",
@@ -69,7 +69,6 @@
     "react-native-view-shot": "^3.1.2",
     "react-native-web": "0.19.8",
     "react-native-webview": "^13.3.1",
-    "supercluster": "^8.0.1",
     "vbe-cluster-map": "https://gitee.com/vbes/vbe-cluster-map.git",
     "victory-native": "^36.6.11"
   },