diff --git a/README.md b/README.md index 9b73f1b..cafcc66 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,14 @@ **PokéNurse** is a desktop application for Windows and Mac that allows you to manage your pokémon from Pokémon Go without the need for a mobile device. You can now favorite, transfer, and evolve from the comfort of your own home! -## Downloads for v2.1.0 +## Downloads for v2.2.0 You may view all the releases [here](https://github.com/vinnymac/PokeNurse/releases) -* [macOS](https://github.com/vinnymac/PokeNurse/releases/download/v2.1.0/PokeNurse.dmg) -* [Windows](https://github.com/vinnymac/PokeNurse/releases/download/v2.1.0/PokeNurse.exe) -* [Linux 32 bit](https://github.com/vinnymac/PokeNurse/releases/download/v2.1.0/PokeNurse-ia32.deb) -* [Linux 64 bit](https://github.com/vinnymac/PokeNurse/releases/download/v2.1.0/PokeNurse-x64.deb) +* [macOS](https://github.com/vinnymac/PokeNurse/releases/download/v2.2.0/PokeNurse.dmg) +* [Windows](https://github.com/vinnymac/PokeNurse/releases/download/v2.2.0/PokeNurse.exe) +* [Debian 32 bit](https://github.com/vinnymac/PokeNurse/releases/download/v2.2.0/PokeNurse-ia32.deb) +* [Debian 64 bit](https://github.com/vinnymac/PokeNurse/releases/download/v2.2.0/PokeNurse-x64.deb) +* [AppImage 32 bit](https://github.com/vinnymac/PokeNurse/releases/download/v2.2.0/PokeNurse-ia32.AppImage) +* [AppImage 64 bit](https://github.com/vinnymac/PokeNurse/releases/download/v2.2.0/PokeNurse-x64.AppImage) ## Examples ![Login Window](app/loginExample.png) diff --git a/app/actions/authenticate.js b/app/actions/authenticate.js index e670390..ee8c986 100644 --- a/app/actions/authenticate.js +++ b/app/actions/authenticate.js @@ -28,7 +28,7 @@ const userLoginFailed = createAction('USER_LOGIN_FAILED') const accountPath = path.join(remote.app.getPath('appData'), '/pokenurse/account.json') export default { - login({ method, username, password, hashingKey }) { + login({ method, username, password, hashingKey, apiVersion }) { return async (dispatch) => { dispatch(userLoginStarted()) @@ -49,8 +49,8 @@ export default { useHashingServer: !!hashingKey, } - // Use API version 0.53 (minimum version for hashing server) - if (hashingKey) options.version = 5300 + // Use default API version + if (hashingKey) options.version = apiVersion || 5704 const client = new pogobuf.Client(options) diff --git a/app/app.global.css b/app/app.global.css index 3931912..6ad6557 100644 --- a/app/app.global.css +++ b/app/app.global.css @@ -1,6 +1,13 @@ @import "~bootstrap/dist/css/bootstrap.css"; @import "~font-awesome/css/font-awesome.css"; +/* Let the app use native fonts */ +body { +font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Noto, Cantarell, "Open Sans", "Avenir Next", Avenir, "Helvetica Neue", Helvetica, "Lucida Grande", Arial, sans-serif; +text-rendering: optimizeLegibility; +-webkit-font-smoothing: antialiased; +} + /**** Menu Styles ****/ /* Position and sizing of burger button */ .bm-burger-button { @@ -276,12 +283,12 @@ display:inline-block; margin-left: 30px; margin-right: 30px; background: #fafafa; -box-shadow: 0px 1px 15px rgba(0, 0, 0, 0.43); +box-shadow: 0 15px 50px rgba(0, 0, 0, 0.35); padding: 10px; text-align: center; max-width: 550px; margin: auto; -border-radius: 3px; +border-radius: .5rem; width: 450px; box-sizing: border-box; padding-top: 50px; @@ -400,6 +407,9 @@ margin: auto; left: 0; right: 0; cursor: pointer; +//max-width: 400px; +height: 90%; +image-rendering: pixelated; } #pokemon_sprite_wrapper { @@ -442,27 +452,25 @@ transform: rotate(0deg) translate(-192px); #pokemon_name { font-size: 40px; -margin-top: 3px; color:#466c6d; text-transform: capitalize; } #pokemon_health_bar { display: block; -margin: auto; +margin: 8px auto; width: 240px; background: #6ceaba; -height: 7px; -margin-top: 8px; -border-radius: 2px; +height: 8px; +border-radius: 1rem; border: 1px solid #61cea4; box-sizing: border-box; } #pokemon_health { font-size: 20px; -margin-top: 4px; color: #383e3c; +margin-bottom: 16px; } .pokemon_info { @@ -471,13 +479,17 @@ width: 100%; height: 80px; position:relative; border-bottom: 1px solid #e2e2e2; +border-top: 1px solid #e2e2e2; +margin-bottom: -1px; } .pokemon-info-item { -display: inline-block; +display: inline-flex; +flex-direction: column; +justify-content: center; +align-content: center; height: 100%; position: relative; -width: 100%; } .split-2-way{ @@ -488,37 +500,39 @@ width: 49%; width: 32%; } -.split-2-way:nth-child(1) { -box-sizing: border-box; -border-right: 1px solid #e2e2e2; +.split-4-way{ +width: 24%; } -.split-3-way:nth-child(1) { +.split-2-way, +.split-3-way, +.split-4-way { box-sizing: border-box; -border-right: 1px solid #e2e2e2; +border-left: 1px solid #e2e2e2; } -.split-3-way:nth-child(2) { -box-sizing: border-box; -border-right: 1px solid #e2e2e2; +.split-2-way:nth-child(1), +.split-3-way:nth-child(1), +.split-4-way:nth-child(1) { + border-left: none; } .pokemon-info-item-title { color: #717171; -margin-top:6px; +text-transform: uppercase; +letter-spacing: 0.5px; } .pokemon-info-item-text { font-size: 16px; -margin-top: 12px; text-transform: capitalize; +font-weight: 600; } .pokemon-stat-unit { color: #717171; -font-size:14px; +font-size: 14px; position: relative; -top:1px; text-transform: lowercase; } @@ -537,28 +551,33 @@ color: #3c605c; #pokemon_evolve_info { display: block; width: 100%; -height: 100px; -margin-top: 20px; +margin: 16px 0; position: relative; -border-bottom: 1px solid #e2e2e2; +border-top: 1px solid #e2e2e2; } .pokemon-evolve-info-item { display:inline-block; -height:70px; +margin-left: 1rem; +} + +.pokemon-evolve-info-item:nth-child(2) { +margin-left: 0; } .pokemon-evolve-info-item-title { -margin-top:-20px; +margin-top: -16px; text-transform: capitalize; text-decoration: none; color:#466c6d; } .pokemon-evolve-info-title { -margin-top:0px; +margin-top:24px; +margin-bottom: 8px; color: #717171; text-transform: uppercase; +letter-spacing: 0.5px; } .pokemon_move_info { @@ -569,6 +588,7 @@ position:relative; .pokemon-move-item { display:inline-flex; +align-items: center; position: relative; height: 60px; width:100%; @@ -576,14 +596,16 @@ color:#3C4741; } .pokemon-move-item-title { -margin-top: 15px; -margin-bottom: 15px; +margin-top: 24px; +margin-bottom: 8px; color: #717171; text-transform: uppercase; +letter-spacing: 0.5px; } .pokemon-move-item.mine{ -border:1px solid #D3D3D3; +border-radius: .5rem; +border:1px solid #B8B8BB; background-color:#E8E8EE; } @@ -593,10 +615,7 @@ border:0px solid white; .pokemon-move-item-text-area{ display:inline-block; -position:relative; -height:100%; width:40%; -padding-top: 6px; } .pokemon-move-title { @@ -615,21 +634,18 @@ text-transform: capitalize; .pokemon-move-damage { display: inline-block; -position: relative; -height:100%; -width:30%; +width:20%; text-transform: capitalize; color:#3c605c; -line-height: 50px; text-align: center; +font-weight: 600; +font-size: 16px; } .pokemon-move-cost { -display: inline-block; -position: relative; -height:10px; -width:30%; -padding-top: 10px; +display: inline-flex; +justify-content: space-around; +width:40%; } .pokemon-move-cost-item { @@ -640,10 +656,8 @@ background: -moz-linear-gradient(top, rgba(68,180,252,1) 0%, rgba(104,225,251,1 background: -webkit-linear-gradient(top, rgba(68,180,252,1) 0%,rgba(104,225,251,1) 100%); background: linear-gradient(to bottom, rgba(68,180,252,1) 0%,rgba(104,225,251,1) 100%); filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#44b4fc', endColorstr='#68e1fb',GradientType=0 ); -margin-left:3px; -margin-top:10px; border:3px solid #afdaff; -border-radius:5px; +border-radius:1rem; } .pokemon-cp{ @@ -652,17 +666,28 @@ fontSize: 18px; font-weight: bold; } -#detailModal .modal-outline-white{ -text-shadow: - 1px 2px 0 #000, - -1px -1px 0 #000, - 1px -1px 0 #000, - -1px 1px 0 #000, - 1px 1px 0 #000; --webkit-text-fill-color: white; +#detailModal .modal-outline-white { + color: white; + opacity: 1; +} + +.close { + color: white; + opacity: 0.75; +} + +.close:hover, .close:focus { + color: white; + opacity: 1; } + #detailModal .modal-header{ -border-bottom: 0px solid; +border-bottom: 0; +} + +.modal-content { + border: none; + border-radius: .5rem; } .pokemon-move-type.normal {color: #A8A878;} diff --git a/app/package.json b/app/package.json index aa5ef89..13d41b7 100644 --- a/app/package.json +++ b/app/package.json @@ -1,7 +1,7 @@ { "name": "PokeNurse", "productName": "PokeNurse", - "version": "2.1.0", + "version": "2.2.0", "description": "A tool for Pokémon Go to aid in transferring and evolving Pokémon", "main": "./main.js", "author": { diff --git a/app/reducers/trainer.js b/app/reducers/trainer.js index b0a0d7c..1118420 100644 --- a/app/reducers/trainer.js +++ b/app/reducers/trainer.js @@ -73,7 +73,10 @@ function getNewSpeciesState(state) { } }) updatedSpecieState.checkAll = checkAll - speciesState[pid] = Object.assign({}, existingSpecieState, updatedSpecieState) + speciesState[pid] = { + ...existingSpecieState, + ...updatedSpecieState, + } // specie state does not exist } else { speciesState[pid] = { @@ -103,62 +106,69 @@ function getNewMonsters(state, monsters, sortBy, sortDir) { specie.pokemon = getSortedPokemon(specie, specieState) }) - - return Object.assign({}, monsters, { - species: sortedSpecies - }) + return { + ...monsters, + species: sortedSpecies, + } } // Anytime the speciesState changes we should recount selected function updateSpecies(state, index, updater) { - const speciesAtIndex = state.monsters.species[index] - const updatedSpecies = Object.assign({}, speciesAtIndex, updater(speciesAtIndex)) - - const updatedMonsters = Object.assign({}, state.monsters, { - species: Immutable.array.set(state.monsters.species, index, updatedSpecies) - }) + const specieAtIndexPokemonId = index + 1 + const indexForSpecie = state.monsters.species.findIndex(specie => specie.pokemon_id === specieAtIndexPokemonId) + const specieAtIndex = state.monsters.species[indexForSpecie] + const updatedSpecies = { ...specieAtIndex, ...updater(specieAtIndex) } + + const updatedMonsters = { + ...state.monsters, + species: Immutable.array.set(state.monsters.species, indexForSpecie, updatedSpecies), + } - const updatedStateWithMonsters = Object.assign({}, state, { - monsters: updatedMonsters - }) + const updatedStateWithMonsters = { + ...state, + monsters: updatedMonsters, + } const { speciesState, selectedCount } = getNewSpeciesState(updatedStateWithMonsters) - return Object.assign({}, updatedStateWithMonsters, { + return { + ...updatedStateWithMonsters, speciesState, - selectedCount - }) + selectedCount, + } } function updateSpeciesState(state, id, updater) { const { - speciesState + speciesState, } = state - const newSpecieState = {} const existingSpecieState = speciesState[String(id)] - newSpecieState[String(id)] = Object.assign( - {}, - existingSpecieState, - updater(existingSpecieState) - ) - - return Object.assign({}, speciesState, newSpecieState) + return { + ...speciesState, + [String(id)]: { + ...existingSpecieState, + ...updater(existingSpecieState), + }, + } } function updatePokemonState(speciesState, pid, updater) { const existingPokemonByIdState = speciesState.pokemonState[String(pid)] const newPokemonByIdState = {} - newPokemonByIdState[String(pid)] = Object.assign( - {}, - existingPokemonByIdState, - updater(existingPokemonByIdState) - ) - return Object.assign({}, speciesState.pokemonState, newPokemonByIdState) + newPokemonByIdState[String(pid)] = { + ...existingPokemonByIdState, + ...updater(existingPokemonByIdState), + } + + return { + ...speciesState.pokemonState, + ...newPokemonByIdState + } } function updateMonster(state, pokemon, options = {}) { @@ -169,9 +179,10 @@ function updateMonster(state, pokemon, options = {}) { return updateSpecies(state, speciesIndex, (speciesAtIndex) => { const index = speciesAtIndex.pokemon.findIndex((p) => p.id === pokemon.id) - const sorted = getSortedPokemon(Object.assign({}, speciesAtIndex, { - pokemon: Immutable.array.set(speciesAtIndex.pokemon, index, updatedPokemon) - }), state.speciesState[pokemon.pokemon_id]) + const sorted = getSortedPokemon({ + ...speciesAtIndex, + pokemon: Immutable.array.set(speciesAtIndex.pokemon, index, updatedPokemon), + }, state.speciesState[pokemon.pokemon_id]) return { // make sure we sort the new pokemon index now that we updated it pokemon: sorted @@ -195,7 +206,10 @@ function getNewSortDirectionFromSortBy(sortBy, specieState) { export default handleActions({ GET_TRAINER_INFO_SUCCESS(state, action) { - return Object.assign({}, state, action.payload) + return { + ...state, + ...action.payload, + } }, GET_TRAINER_INFO_FAILED(state, action) { @@ -206,7 +220,10 @@ export default handleActions({ GET_TRAINER_POKEMON_SUCCESS(state, action) { const monsters = getNewMonsters(state, action.payload, state.sortBy, state.sortDir) - const updatedStateWithMonsters = Object.assign({}, state, { monsters }) + const updatedStateWithMonsters = { + ...state, + monsters, + } const { speciesState, @@ -214,10 +231,11 @@ export default handleActions({ } = getNewSpeciesState(updatedStateWithMonsters) // TODO always sort the data before we return it - return Object.assign({}, updatedStateWithMonsters, { + return { + ...updatedStateWithMonsters, speciesState, - selectedCount - }) + selectedCount, + } }, GET_TRAINER_POKEMON_FAILED(state, action) { @@ -246,23 +264,25 @@ export default handleActions({ // TODO Maybe just generic UPDATE_TRAINER_STORE // using this too much right now, taking the easy way out of refactoring UPDATE_MONSTER_SORT(state, action) { - return Object.assign({}, state, action.payload) + return { ...state, ...action.payload } }, SORT_SPECIES(state, action) { const { sortBy, - speciesIndex + speciesIndex, // this index could be wrong when sorted, so we use findIndex } = action.payload - const pokemonId = state.monsters.species[speciesIndex].pokemon_id + const pokemonId = speciesIndex + 1 + const specieState = state.speciesState[pokemonId] const sortDir = getNewSortDirectionFromSortBy(sortBy, specieState) - const updatedSpeciesState = Object.assign({}, state, { - speciesState: updateSpeciesState(state, pokemonId, () => ({ sortDir, sortBy })) - }) + const updatedSpeciesState = { + ...state, + speciesState: updateSpeciesState(state, pokemonId, () => ({ sortDir, sortBy })), + } return updateSpecies(updatedSpeciesState, speciesIndex, (speciesAtIndex) => { const sorted = getSortedPokemon(speciesAtIndex, null, sortBy, sortDir) @@ -332,13 +352,14 @@ export default handleActions({ if (specie.count < 1) return state - return Object.assign({}, state, { + return { + ...state, speciesState: updateSpeciesState(state, specie.pokemon_id, (speciesState) => { const newCollapsed = !speciesState.collapsed return { collapsed: newCollapsed } - }) - }) + }), + } }, CHECK_ALL_BY_SPECIES(state, action) { @@ -360,11 +381,10 @@ export default handleActions({ } } - newPokemonState[id] = Object.assign( - {}, - specieState.pokemonState[id], - { check: newCheckAllState } - ) + newPokemonState[id] = { + ...specieState.pokemonState[id], + check: newCheckAllState, + } }) return { @@ -373,10 +393,11 @@ export default handleActions({ } }) - return Object.assign({}, state, { + return { + ...state, speciesState, - selectedCount - }) + selectedCount, + } }, CHECK_POKEMON(state, action) { @@ -410,10 +431,11 @@ export default handleActions({ } ) - return Object.assign({}, state, { + return { + ...state, speciesState, - selectedCount - }) + selectedCount, + } }, SORT_ALL_SPECIES(state, action) { @@ -421,15 +443,17 @@ export default handleActions({ const sortDir = getNewSortDirectionFromSortBy(sortBy, state) - const monsters = Object.assign({}, state.monsters, { - species: getSortedSpecies(state.monsters, sortBy, sortDir) - }) + const monsters = { + ...state.monsters, + species: getSortedSpecies(state.monsters, sortBy, sortDir), + } - return Object.assign({}, state, { + return { + ...state, sortDir, sortBy, monsters - }) + } }, SORT_WITH_DEFAULTS(state, action) { @@ -440,30 +464,31 @@ export default handleActions({ defaultSpecieSortDirection, } = action.payload - const updatedSpeciesAndMonstersState = Object.assign({}, state.monsters, { + const updatedSpeciesAndMonstersState = { + ...state.monsters, species: getSortedSpecies(state.monsters, defaultPokedexSortBy, defaultPokedexSortDirection).map((s) => { const sorted = getSortedPokemon(s, null, defaultSpecieSortBy, defaultSpecieSortDirection) - return Object.assign({}, s, { - pokemon: sorted - }) - }) - }) + return { ...s, pokemon: sorted } + }), + } const updatedSpeciesState = mapValues(state.speciesState, (specieState) => { - const newSpecieState = Object.assign({}, specieState, { + const newSpecieState = { + ...specieState, sortBy: defaultSpecieSortBy, sortDir: defaultSpecieSortDirection, - }) + } return newSpecieState }) - return Object.assign({}, state, { + return { + ...state, monsters: updatedSpeciesAndMonstersState, sortBy: defaultPokedexSortBy, sortDir: defaultPokedexSortDirection, speciesState: updatedSpeciesState, - }) + } }, }, initialState) diff --git a/app/screens/Detail/components/CinematicMove.js b/app/screens/Detail/components/CinematicMove.js index 5daed80..4d1e9f9 100644 --- a/app/screens/Detail/components/CinematicMove.js +++ b/app/screens/Detail/components/CinematicMove.js @@ -21,7 +21,7 @@ class CinematicMove extends React.Component { myMove } = this.props - const chargeMoveStyle = { width: `${move.energy_cost}px` } + const chargeMoveStyle = { width: `${move.energy_cost - 3}%` } const chargedMoveBars = times(Math.floor(100 / move.energy_cost), (i) =>
diff --git a/app/screens/Detail/components/ModalBody.js b/app/screens/Detail/components/ModalBody.js index f3448cb..b94cace 100644 --- a/app/screens/Detail/components/ModalBody.js +++ b/app/screens/Detail/components/ModalBody.js @@ -93,21 +93,21 @@ class ModalBody extends React.Component {