Implemented filter

This commit is contained in:
grimsi
2022-08-05 23:01:07 +02:00
parent ddc1c036b6
commit 04febd13d1
9 changed files with 250 additions and 48 deletions
@@ -4,26 +4,80 @@
<h2>Loading library...</h2>
</div>
<div *ngIf="!this.loading && this.detectedGames.length === 0" fxFlex fxLayout="column" fxLayoutAlign="center center" style="height: calc(100vh - 64px)">
<div *ngIf="!this.loading && this.gameLibraryIsEmpty" fxFlex fxLayout="column" fxLayoutAlign="center center"
style="height: calc(100vh - 64px)">
<div class="library-management-hint" fxLayout="column" fxLayoutAlign="start end">
<mat-icon fontSet="material-icons-outlined">north_east</mat-icon>
<p>Use the library management to scan your file system for games</p>
</div>
<div fxLayout="column" fxLayoutAlign="center center">
<mat-icon fontSet="material-icons-outlined" color="primary" style="font-size: 128px; height: 128px; width: 128px;">videogame_asset_off</mat-icon>
<mat-icon fontSet="material-icons-outlined" color="primary"
style="font-size: 128px; height: 128px; width: 128px;">videogame_asset_off
</mat-icon>
<h1>Your game library is empty!</h1>
</div>
</div>
<div class="content" fxLayout="row" fxFlexFill="100" *ngIf="!this.loading && this.detectedGames.length > 0">
<div class="content" fxLayout="row" fxLayout.lt-lg="column" fxFlexFill="100"
*ngIf="!this.loading && !this.gameLibraryIsEmpty">
<div fxFlex="10" fxHide fxShow.gt-md><!--SPACER--></div>
<div fxFlex="0 1 20"><!--FILTER--></div>
<div fxFlex.gt-md="0 1 15" fxLayout="column" fxLayoutGap="16px" fxLayoutAlign.lt-lg="start center" fxFlex.lt-lg="100" [ngClass.gt-md]="'sticky'">
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="6px">
<mat-icon matTooltip="Search for games by title">search</mat-icon>
<mat-form-field fxFlex="80" class="filter-category-content">
<input type="text" matInput [matAutocomplete]="auto" [(ngModel)]="searchTerm" (ngModelChange)="filterGames()">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let game of games" [value]="game.title">
{{game.title}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div>
<div fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="6px">
<h3 class="filter-category-title">Gamemodes</h3>
<mat-icon matTooltip="Filter may not work correctly, working on a fix" color="warn">error</mat-icon>
</div>
<div fxLayout="column" class="filter-category-content">
<mat-checkbox [(ngModel)]="offlineCoopFilterEnabled" (change)="filterGames()" color="primary">Offline Co-op
</mat-checkbox>
<mat-checkbox [(ngModel)]="onlineCoopFilterEnabled" (change)="filterGames()" color="primary">Online Co-op
</mat-checkbox>
<mat-checkbox [(ngModel)]="lanSupportFilterEnabled" (change)="filterGames()" color="primary">LAN Support
</mat-checkbox>
</div>
</div>
<div *ngIf="availableGenres.length > 0">
<h3 class="filter-category-title">Genres</h3>
<div fxLayout="column" class="filter-category-content">
<mat-checkbox *ngFor="let genre of availableGenres" (change)="toggleGenreFilter(genre.slug)"
[checked]="activeGenreFilters.includes(genre.slug)"
color="primary">{{genre.name}}</mat-checkbox>
</div>
</div>
<div *ngIf="availableThemes.length > 0">
<h3 class="filter-category-title">Themes</h3>
<div fxLayout="column" class="filter-category-content">
<mat-checkbox *ngFor="let theme of availableThemes" (change)="toggleThemeFilter(theme.slug)"
[checked]="activeThemeFilters.includes(theme.slug)"
color="primary">{{theme.name}}</mat-checkbox>
</div>
</div>
</div>
<div fxFlex fxLayout="row wrap" fxLayoutGap="16px grid">
<div *ngFor="let game of detectedGames">
<div *ngFor="let game of games">
<game-cover [game]="game"></game-cover>
</div>
</div>
<div fxFlex="0 1 10" fxHide fxShow.gt-lg><!--SPACER--></div>
</div>
</div>
@@ -39,3 +39,29 @@
.content {
padding: 16px;
}
.filter-category-title {
margin-bottom: 0;
}
.filter-category-content {
margin-left: 6px;
}
::ng-deep .mat-checkbox-frame {
$config: mat.get-color-config($custom-theme);
$primary-palette: map.get($config, 'primary');
border-color: mat.get-color-from-palette($primary-palette, 500);
}
::ng-deep .mat-form-field-underline {
$config: mat.get-color-config($custom-theme);
$primary-palette: map.get($config, 'primary');
background-color: mat.get-color-from-palette($primary-palette, 500) !important;
}
.sticky {
position: sticky;
align-self: flex-start;
top: 80px; //64px height of app-header + 16px padding of content
}
@@ -1,6 +1,9 @@
import {AfterContentInit, AfterViewInit, Component} from '@angular/core';
import {AfterContentInit, AfterViewInit, Component, Input} from '@angular/core';
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 {forkJoin, Observable} from "rxjs";
@Component({
selector: 'app-gameserver-list',
@@ -9,19 +12,98 @@ import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
})
export class LibraryOverviewComponent implements AfterContentInit {
detectedGames: DetectedGameDto[] = [];
searchTerm: string = "";
offlineCoopFilterEnabled: boolean = false;
onlineCoopFilterEnabled: boolean = false;
lanSupportFilterEnabled: boolean = false;
activeThemeFilters: string[] = [];
activeGenreFilters: string[] = [];
games: DetectedGameDto[] = [];
availableGenres: GenreDto[] = [];
availableThemes: ThemeDto[] = [];
loading: boolean = true;
gameLibraryIsEmpty: boolean = false;
constructor(private gameServerService: GamesService) {
}
ngAfterContentInit(): void {
this.gameServerService.getAllGames().subscribe(
(detectedGames: DetectedGameDto[]) => {
this.detectedGames = detectedGames;
this.loading = false;
detectedGames => {
if(detectedGames.length === 0) {
this.gameLibraryIsEmpty = true;
return;
}
this.games = detectedGames;
let genreObservable: Observable<ThemeDto[]> = this.gameServerService.getAvailableGenres();
let themeObservable: Observable<GenreDto[]> = this.gameServerService.getAvailableThemes();
forkJoin([themeObservable, genreObservable]).subscribe(result => {
this.availableThemes = result[0];
this.availableGenres = result[1];
this.filterGames();
this.loading = false;
});
}
);
}
filterGames(): void {
this.gameServerService.getAllGames().subscribe(games => {
let filteredGames: DetectedGameDto[] = games;
if(this.searchTerm.trim().toLowerCase().length > 0) {
filteredGames = filteredGames.filter(game => game.title.trim().toLowerCase().includes(this.searchTerm.trim().toLowerCase()));
}
if(this.offlineCoopFilterEnabled || this.onlineCoopFilterEnabled || this.lanSupportFilterEnabled) {
filteredGames = filteredGames.filter(game => (game.offlineCoop === this.offlineCoopFilterEnabled || game.onlineCoop === this.onlineCoopFilterEnabled || game.lanSupport === this.lanSupportFilterEnabled));
}
if(this.activeGenreFilters.length > 0) {
filteredGames = filteredGames.filter(game => this.activeGenreFilters.every(activeGenreFilter => game.genres?.map(g => g.slug).includes(activeGenreFilter)));
}
if(this.activeThemeFilters.length > 0) {
filteredGames = filteredGames.filter(game => this.activeThemeFilters.every(activeThemeFilter => game.themes?.map(g => g.slug).includes(activeThemeFilter)));
}
this.games = filteredGames;
})
}
toggleGenreFilter(slug: string): void {
if(this.activeGenreFilters.includes(slug)) {
const index = this.activeGenreFilters.indexOf(slug, 0);
if (index > -1) {
this.activeGenreFilters.splice(index, 1);
}
} else {
this.activeGenreFilters.push(slug);
}
this.filterGames();
}
toggleThemeFilter(slug: string) {
if(this.activeThemeFilters.includes(slug)) {
const index = this.activeThemeFilters.indexOf(slug, 0);
if (index > -1) {
this.activeThemeFilters.splice(index, 1);
}
} else {
this.activeThemeFilters.push(slug);
}
this.filterGames();
}
}