mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
+1
-1
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>gameyfin</artifactId>
|
||||
<groupId>de.grimsi</groupId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.1.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>gameyfin-backend</artifactId>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>gameyfin</artifactId>
|
||||
<groupId>de.grimsi</groupId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
<div *ngIf="game.genres !== undefined && game.genres.length > 0">
|
||||
<h2>Genres</h2>
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let genre of game.genres">{{genre.name}}</mat-chip>
|
||||
<mat-chip *ngFor="let genre of game.genres" (click)="goToLibraryWithFilter('genres', genre.slug)">{{genre.name}}</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
|
||||
<div *ngIf="game.themes !== undefined && game.themes.length > 0">
|
||||
<h2>Themes</h2>
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let theme of game.themes">{{theme.name}}</mat-chip>
|
||||
<mat-chip *ngFor="let theme of game.themes" (click)="goToLibraryWithFilter('themes', theme.slug)">{{theme.name}}</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Params, Router} from "@angular/router";
|
||||
import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
|
||||
import {GamesService} from "../../services/games.service";
|
||||
import {HttpErrorResponse} from "@angular/common/http";
|
||||
import {takeWhile} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-game-detail-view',
|
||||
@@ -58,4 +56,10 @@ export class GameDetailViewComponent implements OnInit {
|
||||
return bytes.toFixed(dp) + ' ' + units[u];
|
||||
}
|
||||
|
||||
goToLibraryWithFilter(field: string, value: string) {
|
||||
let params: Params = {};
|
||||
params[field] = value;
|
||||
this.router.navigate(['/library'], {queryParams: params});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
<div *ngIf="loggedIn && (this.unmappedFiles.length > 0 || this.mappedGames.length > 0)" fxFlexFill fxLayoutAlign="center start">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Game mappings">
|
||||
<mapped-games-table [mappedGames]="mappedGames"></mapped-games-table>
|
||||
</mat-tab>
|
||||
<mat-tab label="Unmapped files">
|
||||
<unmapped-files-table [unmappedFiles]="unmappedFiles"></unmapped-files-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!loggedIn" fxFlex fxLayout="column" fxLayoutAlign="center center" style="height: calc(100vh - 64px)">
|
||||
<div fxLayout="column" fxLayoutAlign="center center">
|
||||
<mat-icon fontSet="material-icons-outlined" color="primary" style="font-size: 128px; height: 128px; width: 128px;">
|
||||
lock
|
||||
</mat-icon>
|
||||
<h1>Please log in to manage your game library</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="loggedIn && this.unmappedFiles.length === 0 && this.mappedGames.length === 0" 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 fxFlexFill>
|
||||
<div *ngIf="loggedIn && (this.unmappedFiles.length > 0 || this.mappedGames.length > 0)" fxFlex fxLayoutAlign="center start">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Game mappings">
|
||||
<mapped-games-table [mappedGames]="mappedGames"></mapped-games-table>
|
||||
</mat-tab>
|
||||
<mat-tab label="Unmapped files">
|
||||
<unmapped-files-table [unmappedFiles]="unmappedFiles"></unmapped-files-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</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>
|
||||
<h1>Your game library is empty!</h1>
|
||||
<div *ngIf="!loggedIn" fxFlex fxLayout="column" fxLayoutAlign="center center">
|
||||
<div fxLayout="column" fxLayoutAlign="center center">
|
||||
<mat-icon fontSet="material-icons-outlined" color="primary" style="font-size: 128px; height: 128px; width: 128px;">
|
||||
lock
|
||||
</mat-icon>
|
||||
<h1>Please log in to manage your game library</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="loggedIn && this.unmappedFiles.length === 0 && this.mappedGames.length === 0" fxFlex fxLayout="column" fxLayoutAlign="center center">
|
||||
<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>
|
||||
<h1>Your game library is empty!</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,23 +4,21 @@
|
||||
<h2>Loading library...</h2>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!this.loading && this.gameLibraryIsEmpty" fxFlex fxLayout="column" fxLayoutAlign="center center"
|
||||
style="height: calc(100vh - 64px)">
|
||||
<div *ngIf="!this.loading && this.gameLibraryIsEmpty" fxFlex fxLayout="column" fxLayoutAlign="center center">
|
||||
<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 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" fxLayout.lt-lg="column" fxFlexFill="100"
|
||||
*ngIf="!this.loading && !this.gameLibraryIsEmpty">
|
||||
<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.gt-md="0 1 15" fxLayout="column" fxLayoutGap="16px" fxLayoutAlign.lt-lg="start center"
|
||||
@@ -56,7 +54,7 @@
|
||||
</mat-select>
|
||||
</mat-card>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel [expanded]="offlineCoopFilterEnabled || onlineCoopFilterEnabled || lanSupportFilterEnabled">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="6px">
|
||||
<h3 class="filter-category-title">Gamemodes</h3>
|
||||
@@ -77,7 +75,7 @@
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel *ngIf="availableGenres.length > 0">
|
||||
<mat-expansion-panel *ngIf="availableGenres.length > 0" [expanded]="activeGenreFilters.length > 0">
|
||||
<mat-expansion-panel-header>
|
||||
<h3 class="filter-category-title">Genres</h3>
|
||||
</mat-expansion-panel-header>
|
||||
@@ -89,7 +87,7 @@
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel *ngIf="availableThemes.length > 0">
|
||||
<mat-expansion-panel *ngIf="availableThemes.length > 0" [expanded]="activeThemeFilters.length > 0">
|
||||
<mat-expansion-panel-header>
|
||||
<h3 class="filter-category-title">Themes</h3>
|
||||
</mat-expansion-panel-header>
|
||||
@@ -101,7 +99,7 @@
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel *ngIf="availablePlayerPerspectives.length > 0">
|
||||
<mat-expansion-panel *ngIf="availablePlayerPerspectives.length > 0" [expanded]="activePlayerPerspectiveFilters.length > 0">
|
||||
<mat-expansion-panel-header>
|
||||
<h3 class="filter-category-title">Player Perspectives</h3>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
@@ -6,9 +6,8 @@ import {ThemeDto} from "../../models/dtos/ThemeDto";
|
||||
import {firstValueFrom, forkJoin, Observable} from "rxjs";
|
||||
import {SortDirection} from "@angular/material/sort";
|
||||
import {PlayerPerspectiveDto} from "../../models/dtos/PlayerPerspectiveDto";
|
||||
import {ActivatedRoute, Params, Router} from "@angular/router";
|
||||
import {ActivatedRoute, ActivatedRouteSnapshot, Params, Router} from "@angular/router";
|
||||
import {Location} from "@angular/common";
|
||||
import {HttpParams} from "@angular/common/http";
|
||||
|
||||
class SortOption {
|
||||
title: string;
|
||||
@@ -61,6 +60,7 @@ export class LibraryOverviewComponent implements AfterContentInit {
|
||||
|
||||
loading: boolean = true;
|
||||
gameLibraryIsEmpty: boolean = false;
|
||||
private previousStateParams: Params = {};
|
||||
|
||||
constructor(private gameServerService: GamesService,
|
||||
private route: ActivatedRoute,
|
||||
@@ -88,16 +88,15 @@ export class LibraryOverviewComponent implements AfterContentInit {
|
||||
this.availableThemes = result[1];
|
||||
this.availablePlayerPerspectives = result[2];
|
||||
|
||||
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.previousStateParams = this.route.snapshot.queryParams;
|
||||
if (this.previousStateParams['search'] !== undefined) this.searchTerm = this.previousStateParams['search'];
|
||||
if (this.previousStateParams['sort'] !== undefined) this.selectedSortOption = this.matchSelectedSortOptionFromParam(this.previousStateParams['sort']);
|
||||
if (this.previousStateParams['gamemodes'] !== undefined) this.setSelectedGamemodesFromParam(this.previousStateParams['gamemodes']);
|
||||
if (this.previousStateParams['genres'] !== undefined) this.activeGenreFilters = this.matchSelectedFilters(this.availableGenres, this.previousStateParams['genres']);
|
||||
if (this.previousStateParams['themes'] !== undefined) this.activeThemeFilters = this.matchSelectedFilters(this.availableThemes, this.previousStateParams['themes']);
|
||||
if (this.previousStateParams['playerPerspectives'] !== undefined) this.activePlayerPerspectiveFilters = this.matchSelectedFilters(this.availablePlayerPerspectives, this.previousStateParams['playerPerspectives']);
|
||||
|
||||
this.refreshLibraryView().then(() => this.loading = false);
|
||||
});
|
||||
this.refreshLibraryView().then(() => this.loading = false);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -199,25 +198,29 @@ export class LibraryOverviewComponent implements AfterContentInit {
|
||||
}
|
||||
|
||||
private saveStateToRoute(): void {
|
||||
let stateParams: Params = {};
|
||||
let newStateParams: 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(',');
|
||||
if (this.searchTerm.trim().length > 0) newStateParams['search'] = this.searchTerm;
|
||||
if (this.selectedSortOption !== this.defaultSortOption) newStateParams['sort'] = LibraryOverviewComponent.toParam(this.selectedSortOption);
|
||||
if (this.getActiveGameModesFilters().length > 0) newStateParams['gamemodes'] = this.getActiveGameModesFilters().join(',');
|
||||
if (this.activeGenreFilters.length > 0) newStateParams['genres'] = this.activeGenreFilters.join(',');
|
||||
if (this.activeThemeFilters.length > 0) newStateParams['themes'] = this.activeThemeFilters.join(',');
|
||||
if (this.activePlayerPerspectiveFilters.length > 0) newStateParams['playerPerspectives'] = this.activePlayerPerspectiveFilters.join(',');
|
||||
|
||||
const url = this.router.createUrlTree([], {relativeTo: this.route, queryParams: stateParams}).toString();
|
||||
this.location.go(url);
|
||||
// only update the route if it changed
|
||||
if (JSON.stringify(this.previousStateParams) !== JSON.stringify(newStateParams)) {
|
||||
const url = this.router.createUrlTree([], {relativeTo: this.route, queryParams: newStateParams}).toString();
|
||||
this.previousStateParams = newStateParams;
|
||||
this.location.go(url);
|
||||
}
|
||||
}
|
||||
|
||||
private toParam(sortOption: SortOption): string {
|
||||
private static 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;
|
||||
return this.sortOptions.find(s => sortParam === LibraryOverviewComponent.toParam(s)) ?? this.defaultSortOption;
|
||||
}
|
||||
|
||||
private matchSelectedFilters(options: any[], paramString: string): string[] {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
table {
|
||||
min-width: 50vw;
|
||||
width: 50vw;
|
||||
min-width: 750px;
|
||||
}
|
||||
|
||||
.mat-column-path {
|
||||
width: 50%;
|
||||
}
|
||||
.mat-column-game {
|
||||
width: 35%;
|
||||
.mat-column-actions {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,8 +1,9 @@
|
||||
table {
|
||||
min-width: 50vw;
|
||||
width: 50vw;
|
||||
min-width: 750px;
|
||||
}
|
||||
|
||||
.mat-column-path {
|
||||
width: 85%;
|
||||
.mat-column-actions {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user