diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6cb4c05 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:4200", + "webRoot": "${workspaceFolder}/", + "runtimeExecutable": "${env:APPDATA}\\..\\Local\\Vivaldi\\Application\\vivaldi.exe", + "sourceMaps": true, + "runtimeArgs": [ + "--remote-debugging-port=9222", + "--user-data-dir=${workspaceFolder}/DevProfile" + ], + "sourceMapPathOverrides": { + "webpack:///./src/*": "${webRoot}/src/*", + "webpack:///src/*": "${webRoot}/src/*", + "webpack:///*": "*", + "/./*": "${webRoot}/*", + "/src/*": "${webRoot}/src/*", + "/*": "*", + "/./~/*": "${webRoot}/node_modules/*" + }, + "port": 9222, + "trace": true, + } + ] +} \ No newline at end of file diff --git a/src/app/core/models/pokemon.model.ts b/src/app/core/models/pokemon.model.ts index 6c4d75c..a5321c3 100644 --- a/src/app/core/models/pokemon.model.ts +++ b/src/app/core/models/pokemon.model.ts @@ -3,15 +3,16 @@ export interface Pokemon { Name: string; Form: string | null; NationalDex: number; - Generation?: number; + Generation: number; StorableInHome?: boolean; IsBabyForm?: boolean; Encounters?: PokemonEncounter[]; MarkIcon?: string; - MarkName?: string; + MarkName: string; Image?: string; IsDefault?: boolean; IsCaught?: boolean; + IsGenderRelevant?: boolean; } export interface PokemonEncounter { diff --git a/src/app/core/services/pokemon.service.ts b/src/app/core/services/pokemon.service.ts index 8c7aa36..4f7085a 100644 --- a/src/app/core/services/pokemon.service.ts +++ b/src/app/core/services/pokemon.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { map, Observable, shareReplay, tap } from 'rxjs'; +import { concatMap, map, Observable, pipe, shareReplay, tap } from 'rxjs'; import { Pokemon, PokemonEncounter } from '../models/pokemon.model'; import { environment } from '../../../environments/environment.development'; import { comparePfics } from '../utils/pfic-utils'; @@ -12,41 +12,123 @@ export class PokemonService { private apiUrl = environment.apiUrl; private pokemonCache: Observable<(Pokemon | null)[][]> | null = null; private pokemonGroups: (Pokemon | null)[][] = []; + private pokemonFormMap: Map = new Map(); + + private pokemonFormCache: Observable<(Pokemon)[]> | null = null; constructor(private http: HttpClient) { } - getPokemonList(): Observable<(Pokemon | null)[][]> { + getPokemonBoxList(): Observable<(Pokemon | null)[][]> { if (this.pokemonCache) { return this.pokemonCache; } - this.pokemonCache = this.http.get<(any | null)[][]>(`${this.apiUrl}/pokemon`).pipe( - map(groups => groups.map(group => - group.map(pokemon => pokemon ? { - PFIC: pokemon.PFIC, - Name: pokemon.name, - Form: pokemon.form_name, - NationalDex: pokemon.national_dex, - Generation: pokemon.generation, - StorableInHome: pokemon.storable_in_home, - IsBabyForm: pokemon.is_baby_form, - Encounters: pokemon.encounters || [], - MarkIcon: pokemon.icon_path, - MarkName: pokemon.mark_name, - Image: this.getPokemonImageUrl(pokemon.PFIC), - IsDefault: pokemon.is_default || false, - IsCaught: this.caughtPokemon.has(pokemon.PFIC) - } as Pokemon : null) - )), - tap(groups => { - this.pokemonGroups = groups; // Store the groups for later updates + this.pokemonCache = this.getPokemonList().pipe( + map((pokemonList) => { + const boxes: (Pokemon | null)[][] = []; + let currentBox: (Pokemon | null)[] = []; + let currentGeneration = 0; + let currentDexNumber = 0; + let formsGroup: Pokemon[] = []; + + for (const pokemon of pokemonList) { + // Start a new NationalDex group if needed + if (pokemon.NationalDex !== currentDexNumber) { + // If formsGroup has Pokémon, add them to the current box + if (formsGroup.length > 0) { + for (const form of formsGroup) { + currentBox.push(form); + if (currentBox.length === 30) { + boxes.push([...currentBox]); + currentBox = []; + } + } + formsGroup = []; + } + currentDexNumber = pokemon.NationalDex; + + // Start a new generation box if needed + if (currentGeneration !== pokemon.Generation) { + if (currentBox.length > 0) { + while (currentBox.length < 30) { + currentBox.push(null); + } + boxes.push([...currentBox]); + currentBox = []; + } + currentGeneration = pokemon.Generation; + } + } + + // Add the Pokémon form to the group for the current NationalDex + formsGroup.push(pokemon); + } + + // Add any remaining forms in the last group + for (const form of formsGroup) { + currentBox.push(form); + if (currentBox.length === 30) { + boxes.push([...currentBox]); + currentBox = []; + } + } + + // Add the last box with padding if needed + if (currentBox.length > 0) { + while (currentBox.length < 30) { + currentBox.push(null); + } + boxes.push(currentBox); + } + + return boxes; }), + // Share the result to cache it for future subscribers shareReplay(1) - ); + ); return this.pokemonCache; } + getPokemonList(){ + if(this.pokemonFormCache) { + return this.pokemonFormCache; + } + this.pokemonFormCache = this.http.get(`${this.apiUrl}/pokemon`).pipe( + map((rows) => rows.map(row => { + const pkmn = { + PFIC: row.pfic, + Name: row.data.name, + Form: row.data.form_name, + NationalDex: row.data.national_dex, + Generation: row.data.generation, + StorableInHome: row.data.storable_in_home, + IsBabyForm: row.data.is_baby_form, + Encounters: row.data.encounters || [], + MarkIcon: "", + MarkName: row.data.mark, + Image: "", + IsDefault: row.data.is_default || false, + IsGenderRelevant: row.data.gender_relevant, + IsCaught: this.caughtPokemon.has(row.PFIC) + } as Pokemon; + pkmn.MarkIcon = this.getMarkImgName(pkmn.MarkName) + pkmn.Image = this.getPokemonImageUrl(pkmn) + return pkmn; + }) + ), + tap(pokemon_list => { + pokemon_list.forEach(mon => { + this.pokemonFormMap.set(mon.PFIC, mon); + }); + }), + // Cache the result for future subscribers + shareReplay(1) + ); + + return this.pokemonFormCache; + } + getPokemonDetails(pfic: string): Observable { return this.http.get(`${this.apiUrl}/pokemon/${pfic}`); } @@ -84,6 +166,10 @@ export class PokemonService { return this.caughtPokemon.has(pfic); } + getPokemonFromPFIC(pfic:string): Pokemon { + return this.pokemonFormMap.get(pfic) as Pokemon + } + updateCaughtStatus(pfic: string, caught: boolean) { if (caught) { this.caughtPokemon.add(pfic); @@ -92,8 +178,35 @@ export class PokemonService { } } - getPokemonImageUrl(pfic: string): string { - return `/assets/images/pokemon/${pfic}.png`; + getPokemonImageUrl(data: Pokemon): string { + if (data.IsGenderRelevant) { + return `/assets/images/pokemon/${data.PFIC}.png`; + } + const gender_less = data.PFIC.slice(0, -1) + '0' + return `/assets/images/pokemon/${gender_less}.png`; + } + + getMarkImgName(mark: string): string { + switch (mark) { + case "Game Boy": + return "images/marks/GB_icon_HOME.png" + case "Markless": + return "images/marks/Markless_icon_HOME.png" + case "Kalos": + return "images/marks/Blue_pentagon_HOME.png" + case "Let's Go": + return "images/marks/Let's_Go_icon_HOME.png" + case "Galar": + return "images/marks/Galar_symbol_HOME.png" + case "Sinnoh": + return "images/marks/BDSP_icon_HOME.png" + case "Hisui": + return "images/marks/Arceus_mark_HOME.png" + case "Paldea": + return "images/marks/Paldea_icon_HOME.png" + } + + return "images/marks/Markless_icon_HOME.png" } getMarkImageUrl(markName: string): string { diff --git a/src/app/features/plan/plan-pokemon/plan-pokemon.component.ts b/src/app/features/plan/plan-pokemon/plan-pokemon.component.ts index 7a7c1e9..0aad31a 100644 --- a/src/app/features/plan/plan-pokemon/plan-pokemon.component.ts +++ b/src/app/features/plan/plan-pokemon/plan-pokemon.component.ts @@ -35,7 +35,7 @@ interface PokemonStatusEvent {
{ this.pokemonGroups = groups; this.cdr.markForCheck(); diff --git a/src/app/features/pokemon/pokemon-cell/pokemon-cell.component.ts b/src/app/features/pokemon/pokemon-cell/pokemon-cell.component.ts index 20e485f..6f74963 100644 --- a/src/app/features/pokemon/pokemon-cell/pokemon-cell.component.ts +++ b/src/app/features/pokemon/pokemon-cell/pokemon-cell.component.ts @@ -22,12 +22,12 @@ import { PokemonService } from '../../../core/services/pokemon.service';
{{ pokemon.Name }}
- {{ pokemon.Form !== 'Default' ? pokemon.Form : '-----' }} + {{ getFormString(pokemon) }}
@@ -169,4 +169,19 @@ export class PokemonCellComponent { this.caught.emit(this.pokemon.PFIC); } } + + getFormString(pokemon: Pokemon): string { + if (!pokemon.Form) { + return '-----' + } + var form = pokemon.Form + if(pokemon.IsGenderRelevant == false) { + form = form.replace("Female", "").replace("female", "") + form = form.replace("Male", "").replace("male", "") + } + if (form == "" || form == 'Default') { + return '-----' + } + return form + } } \ No newline at end of file