From dadad6434feeeed0d8056483518c11ce14cb39b6 Mon Sep 17 00:00:00 2001 From: John Lyon-Smith Date: Fri, 11 May 2018 13:51:14 -0700 Subject: [PATCH] Added progress bar, progress modal and bubble loader --- mobile/src/App.js | 2 +- mobile/src/Auth/DefaultRoute.js | 13 ++++- mobile/src/Modal/ProgressModal.js | 56 +++++++++++++++++++ mobile/src/Modal/WaitModal.js | 4 +- mobile/src/Modal/index.js | 1 + mobile/src/WorkItem/WorkItem.js | 47 ++++++++++++++-- mobile/src/ui/BoundPhotoPanel.js | 3 +- mobile/src/ui/BubbleLoader.js | 77 ++++++++++++++++++++++++++ mobile/src/ui/ProgressBar.js | 86 +++++++++++++++++++++++++++++ mobile/src/ui/index.js | 2 + server/src/api/routes/AuthRoutes.js | 1 + 11 files changed, 281 insertions(+), 11 deletions(-) create mode 100644 mobile/src/Modal/ProgressModal.js create mode 100644 mobile/src/ui/BubbleLoader.js create mode 100644 mobile/src/ui/ProgressBar.js diff --git a/mobile/src/App.js b/mobile/src/App.js index 44a1066..ff9a8b8 100644 --- a/mobile/src/App.js +++ b/mobile/src/App.js @@ -65,7 +65,7 @@ export default class App extends React.Component { path="/workItemList" component={WorkItemList} /> - + diff --git a/mobile/src/Auth/DefaultRoute.js b/mobile/src/Auth/DefaultRoute.js index 43027b5..469e25c 100644 --- a/mobile/src/Auth/DefaultRoute.js +++ b/mobile/src/Auth/DefaultRoute.js @@ -1,7 +1,14 @@ import React, { Fragment, Component } from "react" import { Route, Redirect } from "react-router-native" +import PropTypes from "prop-types" -export const DefaultRoute = () => { - // NOTE: When working on the app, change this to the page you are working on - return } /> +export class DefaultRoute extends Component { + static propTypes = { + redirect: PropTypes.string, + } + + render() { + // NOTE: When working on the app, change this to the page you are working on + return } /> + } } diff --git a/mobile/src/Modal/ProgressModal.js b/mobile/src/Modal/ProgressModal.js new file mode 100644 index 0000000..585a34e --- /dev/null +++ b/mobile/src/Modal/ProgressModal.js @@ -0,0 +1,56 @@ +import React, { Component } from "react" +import Modal from "react-native-modal" +import PropTypes from "prop-types" +import { View, Text, ActivityIndicator, TouchableOpacity } from "react-native" +import { ProgressBar } from "../ui" +import autobind from "autobind-decorator" + +export class ProgressModal extends Component { + static propTypes = { + open: PropTypes.bool, + message: PropTypes.string.isRequired, + percent: PropTypes.number, + onCancel: PropTypes.func, + } + + render() { + const { open, message, percent } = this.props + + return ( + + + + + {message} + + + Cancel + + + + ) + } +} diff --git a/mobile/src/Modal/WaitModal.js b/mobile/src/Modal/WaitModal.js index ecfa387..856ebf8 100644 --- a/mobile/src/Modal/WaitModal.js +++ b/mobile/src/Modal/WaitModal.js @@ -2,6 +2,7 @@ import React, { Component } from "react" import Modal from "react-native-modal" import PropTypes from "prop-types" import { View, Text, ActivityIndicator } from "react-native" +import { BubbleLoader } from "../ui" export class WaitModal extends Component { static propTypes = { @@ -18,9 +19,10 @@ export class WaitModal extends Component { style={{ flexDirection: "column", justifyContent: "center", + alignItems: "center", backgroundColor: "transparent", }}> - + @@ -327,10 +357,17 @@ export class WorkItem extends React.Component { binder={binder} onUploadStarted={this.handleUploadStarted} onUploadEnded={this.handleUploadEnded} + onUploadProgress={this.handleUploadProgress} /> {isIphoneX ? : null} + { if (onUploadEnded) { onUploadEnded(true, uploadData) diff --git a/mobile/src/ui/BubbleLoader.js b/mobile/src/ui/BubbleLoader.js new file mode 100644 index 0000000..3776080 --- /dev/null +++ b/mobile/src/ui/BubbleLoader.js @@ -0,0 +1,77 @@ +import React from "react" +import { View, Animated, Easing } from "react-native" +import PropTypes from "prop-types" + +export class BubbleLoader extends React.Component { + static propTypes = { + size: PropTypes.number, + } + + static defaultProps = { + size: 50, + } + + constructor(props) { + super(props) + this.animatedScales = [0, 1, 2].map((i) => new Animated.Value(1.0)) + + Animated.loop( + Animated.parallel( + this.animatedScales.map((value, i) => + Animated.sequence([ + Animated.timing(value, { + toValue: 0.2, + duration: 800, + delay: 200 * i, + easing: Easing.out(Easing.sin), + useNativeDriver: true, + }), + Animated.timing(value, { + toValue: 1.0, + duration: 800, + easing: Easing.out(Easing.sin), + useNativeDriver: true, + }), + Animated.delay(200 * (2 - i)), + ]) + ) + ) + ).start() + } + + render() { + const { size } = this.props + const spacing = size / 5 + + return ( + + {[0, 1, 2].map((i) => ( + + ))} + + ) + } +} diff --git a/mobile/src/ui/ProgressBar.js b/mobile/src/ui/ProgressBar.js new file mode 100644 index 0000000..577a848 --- /dev/null +++ b/mobile/src/ui/ProgressBar.js @@ -0,0 +1,86 @@ +import React from "react" +import { + AppRegistry, + StyleSheet, + Text, + View, + Easing, + Animated, +} from "react-native" +import PropTypes from "prop-types" + +var style = StyleSheet.create({ + container: { + width: "100%", + flexDirection: "row", + overflow: "hidden", + borderWidth: 2, + borderColor: "#555555", + borderRadius: 8, + marginBottom: 5, + backgroundColor: "#FFFFFF", + }, + bar: { + flexDirection: "row", + justifyContent: "flex-end", + alignItems: "center", + backgroundColor: "#3BB0FD", + }, + value: { + position: "absolute", + right: 0, + paddingRight: 5, + backgroundColor: "#00000000", + color: "#FFFFFF", + }, +}) + +export class ProgressBar extends React.Component { + static propInfo = { + height: PropTypes.number, + value: PropTypes.number, + } + + static defaultProps = { + value: 0, + } + + constructor(props) { + super(props) + this.state = { + animatedValue: new Animated.Value(props.value % 101), + } + } + + componentWillReceiveProps(nextProps) { + if (this.props.value !== nextProps.value) { + Animated.timing(this.state.animatedValue, { + toValue: nextProps.value % 101, + easing: Easing.out(Easing.ease), + duration: 500, + }).start() + } + } + + render() { + const { height } = this.props + const width = this.state.animatedValue.interpolate({ + inputRange: [0, 100], + outputRange: ["0%", "100%"], + }) + + return ( + + + {this.props.value}% + + + ) + } +} diff --git a/mobile/src/ui/index.js b/mobile/src/ui/index.js index 9805903..8e8c0dd 100644 --- a/mobile/src/ui/index.js +++ b/mobile/src/ui/index.js @@ -1,6 +1,8 @@ export { Icon } from "./Icon" export { Header } from "./Header" export { OptionStrip } from "./OptionStrip" +export { BubbleLoader } from "./BubbleLoader" +export { ProgressBar } from "./ProgressBar" export { BoundSwitch } from "./BoundSwitch" export { BoundInput } from "./BoundInput" export { FormStaticInput } from "./FormStaticInput" diff --git a/server/src/api/routes/AuthRoutes.js b/server/src/api/routes/AuthRoutes.js index c7e8f4e..b082b37 100644 --- a/server/src/api/routes/AuthRoutes.js +++ b/server/src/api/routes/AuthRoutes.js @@ -15,6 +15,7 @@ export class AuthRoutes { constructor(container) { const app = container.app + this.log = container.log this.mq = container.mq this.db = container.db this.maxEmailTokenAgeInHours = config.get("email.maxEmailTokenAgeInHours")