diff --git a/README.md b/README.md
index 17cec7a..6318386 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
## Downloads for v1.5.0
You may view all the releases [here](https://github.com/vinnymac/PokeNurse/releases)
-* [Mac OS X](https://github.com/vinnymac/PokeNurse/releases/download/v1.5.0/PokeNurse-darwin-x64.zip)
+* [macOS](https://github.com/vinnymac/PokeNurse/releases/download/v1.5.0/PokeNurse-darwin-x64.zip)
* [Windows 32 bit](https://github.com/vinnymac/PokeNurse/releases/download/v1.5.0/PokeNurse-win32-ia32.zip)
* [Windows 64 bit](https://github.com/vinnymac/PokeNurse/releases/download/v1.5.0/PokeNurse-win32-x64.zip)
* [Linux 32 bit](https://github.com/vinnymac/PokeNurse/releases/download/v1.5.0/PokeNurse-linux-ia32.zip)
diff --git a/app/actions/status.js b/app/actions/status.js
index 2191c97..43e1412 100644
--- a/app/actions/status.js
+++ b/app/actions/status.js
@@ -2,7 +2,10 @@ import {
createAction
} from 'redux-actions'
+const updateStatus = createAction('UPDATE_STATUS')
+const resetStatus = createAction('RESET_STATUS')
+
export default {
- updateStatus: createAction('UPDATE_STATUS'),
- resetStatus: createAction('RESET_STATUS')
+ updateStatus,
+ resetStatus,
}
diff --git a/app/actions/trainer.js b/app/actions/trainer.js
index 59c8053..3760754 100644
--- a/app/actions/trainer.js
+++ b/app/actions/trainer.js
@@ -7,6 +7,10 @@ import {
} from 'lodash'
import pogobuf from 'pogobuf'
import POGOProtos from 'node-pogo-protos'
+import {
+ ipcRenderer
+} from 'electron'
+import moment from 'moment'
import client from '../client'
@@ -14,6 +18,11 @@ import client from '../client'
import utils from '../utils'
import baseStats from '../../baseStats'
+import {
+ updateStatus,
+ resetStatus,
+} from './status'
+
// Maybe put this info and the helper methods in utils?
const kantoDexCount = 151
@@ -253,6 +262,7 @@ function transferPokemon(pokemon, delay) {
dispatch(transferPokemonSuccess(pokemon))
} catch (error) {
dispatch(transferPokemonFailed(error))
+ throw error
}
}
}
@@ -265,12 +275,106 @@ function evolvePokemon(pokemon, delay) {
dispatch(evolvePokemonSuccess(pokemon))
} catch (error) {
dispatch(evolvePokemonFailed(error))
+ throw error
}
}
}
+function promiseChainFromArray(array, iterator) {
+ let promise = Promise.resolve()
+
+ array.forEach((value, index) => {
+ promise = promise.then(() => iterator(value, index))
+ })
+
+ return promise
+}
+
+function randomDelay([min, max]) {
+ return Math.round((min + Math.random() * (max - min)) * 1000)
+}
+
+function average(arr) {
+ const sum = arr.reduce((result, currentValue) =>
+ result + currentValue
+ , 0)
+
+ return sum / arr.length
+}
+
+const updateMonster = createAction('UPDATE_MONSTER')
+
+function processSelectedPokemon(selectedPokemon, method, action, time, delayRange, done) {
+ return async (dispatch) => {
+ dispatch(updateStatus({
+ selectedPokemon,
+ method,
+ time,
+ }))
+
+ let startTime = moment()
+ const responseTimesInSeconds = []
+
+ promiseChainFromArray(selectedPokemon, (pokemon, index) =>
+ dispatch(action(pokemon, index * randomDelay(delayRange)))
+ .then(() => {
+ let statusUpdates = { current: pokemon }
+
+ // Calculate the Estimated Time in Seconds Left
+ const requestLatencyInSeconds = moment().diff(startTime, 'seconds')
+ startTime = moment()
+
+ if (requestLatencyInSeconds > 0) {
+ responseTimesInSeconds.push(requestLatencyInSeconds)
+ const averageRequestLatencyInSeconds = average(responseTimesInSeconds)
+
+ const numberOfJobsLeft = selectedPokemon.length - (index + 1)
+ const estimatedSecondsLeft = numberOfJobsLeft * averageRequestLatencyInSeconds
+
+ statusUpdates = Object.assign({}, statusUpdates, { time: estimatedSecondsLeft })
+ }
+
+ dispatch(updateStatus(statusUpdates))
+
+ dispatch(updateMonster({
+ pokemon,
+ options: { remove: true }
+ }))
+ })
+ ).then(() => {
+ done()
+ ipcRenderer.send('information-dialog', 'Complete!', `Finished ${method}`)
+ dispatch(resetStatus())
+ dispatch(getTrainerPokemon())
+ }).catch(error => {
+ done()
+ ipcRenderer.send('error-message', `Error while running ${method.toLowerCase()}:\n\n${error}`)
+ dispatch(resetStatus())
+ dispatch(getTrainerPokemon())
+ })
+ }
+}
+
+function transferSelectedPokemon(selectedPokemon, done) {
+ const method = 'Transfer'
+ const time = selectedPokemon.length * 2.5
+ const delayRange = [2, 3]
+ const action = transferPokemon
+
+ return processSelectedPokemon(selectedPokemon, method, action, time, delayRange, done)
+}
+
+function evolveSelectedPokemon(selectedPokemon, done) {
+ const method = 'Evolve'
+ const time = selectedPokemon.length * 27.5
+ const delayRange = [25, 30]
+ const action = evolvePokemon
+
+ return processSelectedPokemon(selectedPokemon, method, action, time, delayRange, done)
+}
+
export default {
- updateMonster: createAction('UPDATE_MONSTER'),
+ updateMonster,
updateSpecies: createAction('UPDATE_SPECIES'),
updateMonsterSort: createAction('UPDATE_MONSTER_SORT'),
sortSpecies: createAction('SORT_SPECIES'),
@@ -286,4 +390,6 @@ export default {
renamePokemon,
transferPokemon,
evolvePokemon,
+ evolveSelectedPokemon,
+ transferSelectedPokemon,
}
diff --git a/app/css/pokenurse.css b/app/css/pokenurse.css
index a771809..795fafb 100644
--- a/app/css/pokenurse.css
+++ b/app/css/pokenurse.css
@@ -38,17 +38,30 @@
.bm-item-list ul {
float: none;
display: block;
+ list-style: none;
+ width: 100%;
}
.bm-menu .bm-item-list li {
float: none;
display: block;
padding: 5px 0px;
- border-bottom: 1px solid #b8b7ad;
+ border-top: 1px solid #b8b7ad;
+ width: 100%;
+}
+.bm-menu .bm-item-list li:first-of-type, li:last-of-type {
+ border-top: none;
}
.bm-menu .bm-item-list li a {
padding: 5px 0px;
cursor: pointer;
+ color: #9d9d9d;
+ text-decoration: none;
+ line-height: 20px;
+}
+
+.bm-menu .bm-item-list li a:hover, a:active {
+ color: white;
}
.bm-menu .bm-item-list i {
@@ -56,6 +69,10 @@
float: right;
}
+.bm-menu .bm-item-list .submenu li {
+ background-color: rgba(35, 35, 35, 0.4);
+}
+
/* Morph shape necessary with bubble or elastic */
.bm-morph-shape {
fill: #373a47;
diff --git a/app/imgs/egg.png b/app/imgs/egg.png
new file mode 100644
index 0000000..5ca7920
Binary files /dev/null and b/app/imgs/egg.png differ
diff --git a/app/reducers/status.js b/app/reducers/status.js
index d8c9dc7..9d749f2 100644
--- a/app/reducers/status.js
+++ b/app/reducers/status.js
@@ -7,7 +7,6 @@ const initialState = {
current: null,
time: 0,
method: '',
- finished: null
}
export default handleActions({
diff --git a/app/screens/ConfirmationDialog/components/SelectedPokemon.js b/app/screens/ConfirmationDialog/components/SelectedPokemon.js
index 9aad147..7834f3f 100644
--- a/app/screens/ConfirmationDialog/components/SelectedPokemon.js
+++ b/app/screens/ConfirmationDialog/components/SelectedPokemon.js
@@ -28,7 +28,7 @@ const SelectedPokemon = React.createClass({
- { this.buildRows(pokemon) }
+ { this.buildRows(pokemon) }
diff --git a/app/screens/Menu/components/Eggs.js b/app/screens/Menu/components/Eggs.js
new file mode 100644
index 0000000..69afef6
--- /dev/null
+++ b/app/screens/Menu/components/Eggs.js
@@ -0,0 +1,29 @@
+import React, {
+ PropTypes
+} from 'react'
+
+const Eggs = React.createClass({
+ propTypes: {
+ eggList: PropTypes.array,
+ },
+
+ render() {
+ const {
+ eggList
+ } = this.props
+
+ const eggs = eggList.map((e, i) =>
+
+ {e.egg_km_walked_start}.0 / {e.egg_km_walked_target}.0 km
+
+ )
+
+ return (
+
+ )
+ }
+})
+
+export default Eggs
diff --git a/app/screens/Menu/index.js b/app/screens/Menu/index.js
index 9dcba46..7df0314 100644
--- a/app/screens/Menu/index.js
+++ b/app/screens/Menu/index.js
@@ -9,26 +9,37 @@ import {
logout
} from '../../actions'
import renderSettings from '../Settings'
+// import Eggs from './components/Eggs'
const Menu = require('react-burger-menu').slide
const MainMenu = React.createClass({
propTypes: {
updateStatus: PropTypes.func.isRequired,
- logout: PropTypes.func.isRequired
+ logout: PropTypes.func.isRequired,
+ eggs: PropTypes.array,
},
render() {
+ // const {
+ // eggs
+ // } = this.props
+
return (