diff --git a/frontend/src/app/components/header/header.component.ts b/frontend/src/app/components/header/header.component.ts index 130ca42..5c8c67f 100644 --- a/frontend/src/app/components/header/header.component.ts +++ b/frontend/src/app/components/header/header.component.ts @@ -5,7 +5,7 @@ import {timeInterval} from "rxjs"; import {Router} from "@angular/router"; import {GamesService} from "../../services/games.service"; import {ThemingService} from "../../services/theming.service"; -import {DOCUMENT} from '@angular/common'; +import {DOCUMENT, Location} from '@angular/common'; @Component({ selector: 'app-header', @@ -21,7 +21,8 @@ export class HeaderComponent { private gameService: GamesService, private themingService: ThemingService, private snackBar: MatSnackBar, - private router: Router) { + private router: Router, + private location: Location) { } scanLibrary(): void { @@ -42,7 +43,7 @@ export class HeaderComponent { } goToLibraryScreen(): void { - this.router.navigate(['/']); + this.location.back(); } goToLibraryManagementScreen(): void { diff --git a/frontend/src/app/components/library-overview/library-overview.component.ts b/frontend/src/app/components/library-overview/library-overview.component.ts index a8efcd1..c40b4f7 100644 --- a/frontend/src/app/components/library-overview/library-overview.component.ts +++ b/frontend/src/app/components/library-overview/library-overview.component.ts @@ -3,10 +3,12 @@ import {GamesService} from "../../services/games.service"; import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; import {GenreDto} from "../../models/dtos/GenreDto"; import {ThemeDto} from "../../models/dtos/ThemeDto"; -import {firstValueFrom, forkJoin, Observable, pipe} from "rxjs"; +import {firstValueFrom, forkJoin, Observable} from "rxjs"; import {SortDirection} from "@angular/material/sort"; -import {CompanyDto} from "../../models/dtos/CompanyDto"; import {PlayerPerspectiveDto} from "../../models/dtos/PlayerPerspectiveDto"; +import {ActivatedRoute, Params, Router} from "@angular/router"; +import {Location} from "@angular/common"; +import {HttpParams} from "@angular/common/http"; class SortOption { title: string; @@ -60,7 +62,10 @@ export class LibraryOverviewComponent implements AfterContentInit { loading: boolean = true; gameLibraryIsEmpty: boolean = false; - constructor(private gameServerService: GamesService) { + constructor(private gameServerService: GamesService, + private route: ActivatedRoute, + private router: Router, + private location: Location) { } ngAfterContentInit(): void { @@ -83,7 +88,16 @@ export class LibraryOverviewComponent implements AfterContentInit { this.availableThemes = result[1]; this.availablePlayerPerspectives = result[2]; - this.refreshLibraryView().then(() => this.loading = false); + this.route.queryParams.subscribe(params => { + if (params['search'] !== undefined) this.searchTerm = params['search']; + if (params['sort'] !== undefined) this.selectedSortOption = this.matchSelectedSortOptionFromParam(params['sort']); + if (params['gamemodes'] !== undefined) this.setSelectedGamemodesFromParam(params['gamemodes']); + if (params['genres'] !== undefined) this.activeGenreFilters = this.matchSelectedFilters(this.availableGenres, params['genres']); + if (params['themes'] !== undefined) this.activeThemeFilters = this.matchSelectedFilters(this.availableThemes, params['themes']); + if (params['playerPerspectives'] !== undefined) this.activePlayerPerspectiveFilters = this.matchSelectedFilters(this.availablePlayerPerspectives, params['playerPerspectives']); + + this.refreshLibraryView().then(() => this.loading = false); + }); }); } ); @@ -91,7 +105,8 @@ export class LibraryOverviewComponent implements AfterContentInit { async refreshLibraryView(): Promise { let games: DetectedGameDto[] = await firstValueFrom(this.gameServerService.getAllGames()); - this.games = this.sortGames(this.filterGames(games)); + this.games = this.sortGames(this.filterGames(games)); + this.saveStateToRoute(); } clearSearchTerm(): void { @@ -130,11 +145,11 @@ export class LibraryOverviewComponent implements AfterContentInit { // @ts-ignore let f2 = g2[this.selectedSortOption.field]; - if(f1 > f2) return 1; - if(f1 < f2) return -1; + if (f1 > f2) return 1; + if (f1 < f2) return -1; return 0; }); - if(this.selectedSortOption.direction === "desc") games = games.reverse(); + if (this.selectedSortOption.direction === "desc") games = games.reverse(); return games; } @@ -183,4 +198,49 @@ export class LibraryOverviewComponent implements AfterContentInit { this.refreshLibraryView(); } + private saveStateToRoute(): void { + let stateParams: Params = {}; + + if (this.searchTerm.trim().length > 0) stateParams['search'] = this.searchTerm; + if (this.selectedSortOption !== this.defaultSortOption) stateParams['sort'] = this.toParam(this.selectedSortOption); + if (this.getActiveGameModesFilters().length > 0) stateParams['gamemodes'] = this.getActiveGameModesFilters().join(','); + if (this.activeGenreFilters.length > 0) stateParams['genres'] = this.activeGenreFilters.join(','); + if (this.activeThemeFilters.length > 0) stateParams['themes'] = this.activeThemeFilters.join(','); + if (this.activePlayerPerspectiveFilters.length > 0) stateParams['playerPerspectives'] = this.activePlayerPerspectiveFilters.join(','); + + const url = this.router.createUrlTree([], {relativeTo: this.route, queryParams: stateParams}).toString(); + this.location.go(url); + } + + private toParam(sortOption: SortOption): string { + return `${sortOption.field}_${sortOption.direction}`; + } + + private matchSelectedSortOptionFromParam(sortParam: string): SortOption { + return this.sortOptions.find(s => sortParam === this.toParam(s)) ?? this.defaultSortOption; + } + + private matchSelectedFilters(options: any[], paramString: string): string[] { + let params: string[] = paramString.split(","); + return options.filter(o => params.includes(o.slug)).map(o => o.slug); + } + + private getActiveGameModesFilters(): string[] { + let activeFilters: string[] = []; + + if (this.offlineCoopFilterEnabled) activeFilters.push('offlineCoop'); + if (this.onlineCoopFilterEnabled) activeFilters.push('onlineCoop'); + if (this.lanSupportFilterEnabled) activeFilters.push('lanSupport'); + + return activeFilters; + } + + private setSelectedGamemodesFromParam(paramString: string): void { + let params: string[] = paramString.split(","); + + if (params.includes('offlineCoop')) this.offlineCoopFilterEnabled = true; + if (params.includes('onlineCoop')) this.onlineCoopFilterEnabled = true; + if (params.includes('lanSupport')) this.lanSupportFilterEnabled = true; + } + }