wudebin hai 6 meses
pai
achega
9a97fcce97

+ 79 - 0
Strides-SPAPP/app/components/Appbar.js

@@ -0,0 +1,79 @@
+import React from 'react';
+import { Image, Pressable, StyleSheet, View } from 'react-native';
+
+export const BackButton = ({navigation}) => {
+  return (
+    <Pressable
+      style={Styles.backIcon}
+      android_ripple = {{
+        color: '#909090',
+        radius: 22,
+        borderless: true
+      }}
+      onPress={() => {
+        goBack();
+      }}>
+      <BackIcon/>
+    </Pressable>
+  )
+}
+
+export const BackIcon = () => {
+  return <MaterialIcons name={isIOS ? 'arrow-back-ios' : 'arrow-back'} size={24} color={colorDark} />
+}
+
+export const StationBack = ({bottom}) => {
+  return (
+    <Image
+      style={{
+        right: 0,
+        bottom: bottom ?? 24,
+        width: 125.8,
+        height: 137.64,
+        zIndex: 0,
+        position: 'absolute'
+      }}
+      source={require('../images/charge/bg-top-station.png')}/>
+  );
+}
+
+export const Styles = StyleSheet.create({
+  toolbar: {
+    height: 56,
+    paddingLeft: 2,
+    paddingRight: 2,
+    alignItems: 'center',
+    flexDirection: 'row',
+    backgroundColor: colorPrimary
+  },
+  backIcon: {
+    width: 48,
+    height: 48,
+    alignItems: 'center',
+    justifyContent: 'center'
+  },
+  content: {
+    flex: 1,
+    paddingRight: 48,
+    alignItems: 'center'
+  },
+  logo: {
+    width: 123.8,
+    height: 38.95
+  }
+});
+
+export default Appbar = (props) => {
+  return (
+    <View style={Styles.toolbar}>
+      <BackButton {...props}/>
+      <View style={Styles.content}>
+        <Image
+          source={require('../images/tool-logo.png')}
+          style={Styles.logo}
+          resizeMode="contain"
+        />
+      </View>
+    </View>
+  )
+}

+ 63 - 0
Strides-SPAPP/app/components/BadgeSelectItem.js

@@ -0,0 +1,63 @@
+import React from 'react';
+import { Pressable } from 'react-native';
+import Svg, { Path } from 'react-native-svg';
+import app from '../../app.json';
+
+const BadgeSelectItem = ({
+  children,
+  style={},
+  checked=false,
+  onPress,
+  iconSize=28,
+  showBorder=true,
+  tintColor=colorAccent,
+  borderColor="transparent"
+}) => (
+  <Pressable 
+    onPress={onPress}
+    style={mergeStyle(style, checked ? tintColor : borderColor, showBorder)}>
+    {children}
+    { checked &&
+      <Svg 
+        width={iconSize}
+        height={iconSize}
+        viewBox="0 0 40 40"
+        style={{top: -1, right: -1, position: 'absolute'}}>
+        <Path
+          fill={tintColor}
+          d="M28 0H0L40 40V12C40 5.37258 34.6274 -30 28 0Z" />
+        { app.isLumiWhitelabel
+        ? <></>
+        : <Path
+            fill="white"
+            d="M34.8965 10.5142L27.1892 18.6408C27.0371 18.801 26.7733 18.7828 26.5999 18.6L26.0834 18.0554L22.63 14.4141C22.4567 14.2313 22.4567 13.935 22.63 13.7522L23.5718 12.7592C23.7451 12.5762 24.0262 12.5762 24.1996 12.7592L26.9138 15.6211L33.3268 8.8593C33.4789 8.69893 33.7426 8.71717 33.916 8.89998L34.8577 9.89294C35.0311 10.0759 35.0484 10.354 34.8965 10.5142Z"/>
+        }
+      </Svg>
+    }
+    { (checked && app.isLumiWhitelabel) &&
+      <Svg width={9} height={9} viewBox="0 0 8 8" fill="none" style={{top: 4, right: 3, position: 'absolute'}}>
+        <Path d="M3.89095 0.201172C2.05762 0.201172 0.557617 1.70117 0.557617 3.5345C0.557617 5.36784 2.05762 6.86784 3.89095 6.86784C5.72428 6.86784 7.22428 5.36784 7.22428 3.5345C7.22428 1.70117 5.72428 0.201172 3.89095 0.201172ZM3.89095 6.20117C2.42095 6.20117 1.22428 5.0045 1.22428 3.5345C1.22428 2.06451 2.42095 0.867839 3.89095 0.867839C5.36095 0.867839 6.55762 2.06451 6.55762 3.5345C6.55762 5.0045 5.36095 6.20117 3.89095 6.20117ZM5.42095 2.06117L3.22428 4.25784L2.36095 3.39784L1.89095 3.86784L3.22428 5.20117L5.89095 2.53451L5.42095 2.06117Z" fill="white"/>
+      </Svg>
+    }
+  </Pressable>
+);
+
+const mergeStyle = (style, color, showBorder) => {
+  const def = showBorder 
+              ? {borderColor: color, borderWidth: 1, borderRadius: 10, overflow: 'hidden'}
+              : {overflow: 'hidden'}
+  if (Array.isArray(style)) {
+    let res = {}
+    for (let s of style) {
+      res = {...res, ...s};
+    }
+    style = res;
+  }
+  var s = Object.assign(def, style);
+  if (color) {
+    s.borderColor = color;
+  }
+  return s;
+}
+
+export default BadgeSelectItem;

+ 49 - 0
Strides-SPAPP/app/components/BottomModal.js

@@ -0,0 +1,49 @@
+import React from 'react';
+import { StyleSheet, View } from 'react-native';
+import Modal from 'react-native-modal';
+
+export const ModalProps = {
+  avoidKeyboard: true,
+  animationIn: "fadeIn",
+  animationOut: "fadeOut",
+  propagateSwipe: true,
+  useNativeDriver: !isIOS,
+  statusBarTranslucent: true,
+  deviceHeight: $height + statusHeight,
+  hideModalContentWhileAnimating: true
+}
+
+export default BottomModal = ({
+  visible=false,
+  onHide,
+  children,
+  backdropOpacity=0.7,
+  style=styles.bottomModalView,
+  contentStyle=styles.bottomModalContent}) => {
+  return (
+    <Modal
+      isVisible={visible}
+      onBackButtonPress={onHide}
+      onBackdropPress={onHide}
+      useNativeDriver={!isIOS}
+      statusBarTranslucent={true}
+      backdropOpacity={backdropOpacity}
+      style={style}>
+      <View style={[contentStyle, {paddingBottom: navbarHeight}]}>
+        {children}
+      </View>
+    </Modal>
+  );
+}
+
+const styles = StyleSheet.create({
+  bottomModalView: {
+    margin: 0,
+    justifyContent: 'flex-end'
+  },
+  bottomModalContent: {
+    maxHeight: $vht(isIOS ? 92 : 96),
+    backgroundColor: pageBackground,
+    ...$borderRadius(20, 20, 0, 0)
+  },
+})

+ 223 - 0
Strides-SPAPP/app/components/Button.js

@@ -0,0 +1,223 @@
+import React from 'react';
+import { Pressable, StyleSheet, Text, View } from 'react-native';
+import TextView from './TextView';
+
+export default Button = ({
+  style = styles.buttonView,
+  text,
+  textSize,
+  textColor,
+  textStyle = styles.buttonText,
+  viewStyle = styles.button,
+  children,
+  onClick,
+  onLongClick,
+  disabled = false,
+  elevation = 0,
+  borderRadius = 40,
+  iconLeft,
+  iconRight,
+  numberOfLines=1
+}) => {
+  //var start = {}, end = {};
+  //const isSamsung = BRAND == 'samsung';
+  return (
+    <View style={getElevation(style, disabled, elevation, borderRadius)}>
+      <Pressable
+        style={({pressed }) => [
+          pressed && isIOS && {
+            backgroundColor: rippleColor
+          },
+          isIOS && getRadius(style, borderRadius),
+          viewStyle
+        ]}
+        disabled={disabled}
+        onPress={e => {
+          if (onClick) onClick(e)
+        }}
+        onLongPress={e => {
+          if (onLongClick) {
+            onLongClick(e)
+            //start = {}
+          }
+        }}
+        onPressIn={(e) => {
+          /*if (isSamsung && e.nativeEvent)
+            start = e.nativeEvent*/
+          }
+        }
+        onPressOut={e => {
+          /*if (isSamsung && e.nativeEvent && start.timestamp) {
+            end = e.nativeEvent
+            var x = Math.abs(start.pageX - end.pageX)
+            var y = Math.abs(start.pageY - end.pageY)
+            //console.log(x, y, viewStyle.height)
+            if (x < 50 && y < 10) {
+              if (end.timestamp - start.timestamp > 600) { //长按
+                //console.log('LongClick')
+                if (onClick) onClick(e)
+              } else { //click
+                //console.log('Click')
+                if (onClick) onClick(e)
+              }
+            }
+          }*/
+        }}
+        android_ripple={ripple}>
+        {iconLeft ?? <></>}
+        { children ? children :
+          <TextView style={mergeStyle(textStyle, textColor, textSize, disabled)} numberOfLines={numberOfLines}>{text}</TextView>
+        }
+        {iconRight ?? <></>}
+      </Pressable>
+    </View>
+  );
+}
+
+const mergeStyle = (style, color, size, disabled) => {
+  if (Array.isArray(style)) {
+    let res = {}
+    for (let s of style) {
+      res = {...res, ...s};
+    }
+    style = res;
+  }
+  var s = Object.assign({}, style);
+  if (disabled) {
+    s.color = '#999';
+  } else if (color) {
+    s.color = color;
+  }
+  if (size) {
+    s.fontSize = size;
+  }
+  return s;
+}
+
+const getRadius = (style, r) => {
+  if (Array.isArray(style)) {
+    let res = {}
+    for (let s of style) {
+      res = {...res, ...s};
+    }
+    style = res;
+  }
+  const s = {}
+  if (style.borderTopLeftRadius !== undefined)
+    s.borderTopLeftRadius = style.borderTopLeftRadius
+  if (style.borderTopRightRadius !== undefined)
+    s.borderTopRightRadius = style.borderTopRightRadius
+  if (style.borderBottomLeftRadius !== undefined)
+    s.borderBottomLeftRadius = style.borderBottomLeftRadius
+  if (style.borderBottomRightRadius !== undefined)
+    s.borderBottomRightRadius = style.borderBottomRightRadius
+  if (style.borderRadius !== undefined)
+    s.borderRadius = style.borderRadius
+  if (Object.keys(s).length == 0 && r) {
+    return $borderRadius(r)
+  }
+  return s;
+}
+
+const getElevation = (style, d, e, r) => {
+  if (Array.isArray(style)) {
+    let res = {}
+    for (let s of style) {
+      res = {...res, ...s};
+    }
+    style = res;
+  }
+  var s = Object.assign({}, style);
+  s.padding = 0;
+  if (!isIOS)
+    s.overflow = 'hidden';
+  s.flexDirection = 'row';
+  if (style.borderRadius == undefined && r) {
+    s.borderRadius = r;
+  }
+  if (!s.backgroundColor) {
+    s.backgroundColor = styles.buttonView.backgroundColor
+  }
+  if (!d) {
+    var ele = e ? e : style.elevation ? style.elevation : 0
+    s = Object.assign(ElevationObject(ele), s)
+  } else {
+    s = Object.assign(ElevationObject(0), s)
+    s.backgroundColor = '#CCC';
+  }
+  return s;
+}
+
+/**
+ * Shadow阴影生成
+ * @param {*} e 阴影大小
+ * @returns 样式json
+ */
+export const ElevationObject = (e) => {
+  if (e) {
+    return {
+      elevation: e,
+      shadowOpacity: .5,
+      shadowColor: '#999999',
+      shadowOffset: {width: 0, height: e},
+    };
+  } else {
+    return {};
+  }
+}
+
+export const ViewHeight = (height) => {
+  return {
+    flex: 1,
+    height: height,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  }
+}
+
+export const ViewHeightPadding = (height, padding=0) => {
+  return {
+    flex: 1,
+    height: height,
+    paddingLeft: padding,
+    paddingRight: padding,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  }
+}
+
+const styles = StyleSheet.create({
+  buttonView: {
+    //调整默认按钮颜色
+    backgroundColor: colorAccent,
+    //backgroundColor: colorPrimary
+  },
+  button: {
+    flex: 1,
+    height: 50,
+    paddingLeft: 16,
+    paddingRight: 16,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  },
+  buttonMini: {
+    height: 42,
+    borderRadius: 6,
+    paddingLeft: 16,
+    paddingRight: 16,
+    alignItems: 'center',
+    justifyContent: 'center',
+    backgroundColor: colorAccent//colorPrimary
+  },
+  buttonText: {
+    flex: 1,
+    color: textButton,
+    fontSize: 16,
+    fontWeight: 'bold',
+    textAlign: 'center',
+    textTransform: 'uppercase'
+  }
+});

+ 43 - 0
Strides-SPAPP/app/components/CheckBox.js

@@ -0,0 +1,43 @@
+import React from 'react';
+import { StyleSheet } from 'react-native';
+import CheckBoxBase from '@react-native-community/checkbox';
+
+const CheckBox = ({
+  value=false,
+  disabled=false,
+  onValueChange,
+  tintColor=colorAccent,
+  iosSize=24
+}) => {
+  if (isIOS) {
+    return (
+      <MaterialIcons
+        name={value ? "check-box" : "check-box-outline-blank"}
+        size={iosSize}
+        color={value ? tintColor : '#777'}
+        style={styles.checkBoxView}
+        onPress={() => {
+          if (onValueChange)
+            onValueChange(!value)
+        }}
+      />
+    );
+  } else {
+    return (
+      <CheckBoxBase
+        value={value}
+        disabled={disabled}
+        tintColors={{true: tintColor, false: '#777'}}
+        onValueChange={onValueChange}
+      />
+    )
+  }
+}
+
+const styles = StyleSheet.create({
+  checkBoxView: {
+    padding: 4
+  }
+})
+
+export default CheckBox;