From a06dfa7c47398b2c78829677ccc9dc0758fd82fe Mon Sep 17 00:00:00 2001 From: Simon Grimme Date: Fri, 22 Jul 2022 12:54:39 +0200 Subject: [PATCH] WIP: Proceed with frontend implementation --- .../grimsi/gameyfin/dto/GameOverviewDto.java | 12 +++++++ .../de/grimsi/gameyfin/mapper/GameMapper.java | 9 ++++++ .../grimsi/gameyfin/rest/GamesController.java | 14 +++++++++ .../grimsi/gameyfin/service/GameService.java | 9 ++++++ frontend/src/app/api/GamesApi.ts | 3 ++ frontend/src/app/app-routing.module.ts | 13 ++------ .../game-cover/game-cover.component.html | 2 +- .../game-cover/game-cover.component.ts | 7 +++-- .../game-detail-view.component.html | 2 +- .../game-detail-view.component.ts | 23 +++++++++++++- .../components/header/header.component.html | 31 ------------------- .../library-overview.component.ts | 7 +++-- .../src/app/models/dtos/GameOverviewDto.ts | 5 +++ frontend/src/app/services/games.service.ts | 9 ++++++ 14 files changed, 96 insertions(+), 50 deletions(-) create mode 100644 backend/src/main/java/de/grimsi/gameyfin/dto/GameOverviewDto.java create mode 100644 frontend/src/app/models/dtos/GameOverviewDto.ts diff --git a/backend/src/main/java/de/grimsi/gameyfin/dto/GameOverviewDto.java b/backend/src/main/java/de/grimsi/gameyfin/dto/GameOverviewDto.java new file mode 100644 index 0000000..f0fa069 --- /dev/null +++ b/backend/src/main/java/de/grimsi/gameyfin/dto/GameOverviewDto.java @@ -0,0 +1,12 @@ +package de.grimsi.gameyfin.dto; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class GameOverviewDto { + private String slug; + private String title; + private String coverId; +} diff --git a/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java b/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java index 338f6fa..e9ac70d 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java +++ b/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java @@ -1,6 +1,7 @@ package de.grimsi.gameyfin.mapper; import com.igdb.proto.Igdb; +import de.grimsi.gameyfin.dto.GameOverviewDto; import de.grimsi.gameyfin.entities.DetectedGame; import de.grimsi.gameyfin.util.ProtobufUtils; @@ -40,6 +41,14 @@ public class GameMapper { .build(); } + public static GameOverviewDto toGameOverviewDto(DetectedGame game) { + return GameOverviewDto.builder() + .slug(game.getSlug()) + .title(game.getTitle()) + .coverId(game.getCoverId()) + .build(); + } + private static boolean hasOfflineCoop(List modes) { return modes.stream().anyMatch(Igdb.MultiplayerMode::getOfflinecoop); } diff --git a/backend/src/main/java/de/grimsi/gameyfin/rest/GamesController.java b/backend/src/main/java/de/grimsi/gameyfin/rest/GamesController.java index 0ab0524..321138f 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/rest/GamesController.java +++ b/backend/src/main/java/de/grimsi/gameyfin/rest/GamesController.java @@ -1,10 +1,12 @@ package de.grimsi.gameyfin.rest; +import de.grimsi.gameyfin.dto.GameOverviewDto; import de.grimsi.gameyfin.entities.DetectedGame; import de.grimsi.gameyfin.service.GameService; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -26,8 +28,20 @@ public class GamesController { return gameService.getAllDetectedGames(); } + @GetMapping(value = "/game/{slug}", produces = MediaType.APPLICATION_JSON_VALUE) + public DetectedGame getGame(@PathVariable String slug) { + return gameService.getDetectedGame(slug); + } + + @GetMapping(value = "/game-overviews", produces = MediaType.APPLICATION_JSON_VALUE) + public List getGameOverviews() { + return gameService.getGameOverviews(); + } + @GetMapping(value = "/game-mappings", produces = MediaType.APPLICATION_JSON_VALUE) public Map getGameMappings() { return gameService.getAllMappings(); } + + } diff --git a/backend/src/main/java/de/grimsi/gameyfin/service/GameService.java b/backend/src/main/java/de/grimsi/gameyfin/service/GameService.java index bea73b0..916c85e 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/service/GameService.java +++ b/backend/src/main/java/de/grimsi/gameyfin/service/GameService.java @@ -1,6 +1,7 @@ package de.grimsi.gameyfin.service; import com.igdb.proto.Igdb; +import de.grimsi.gameyfin.dto.GameOverviewDto; import de.grimsi.gameyfin.entities.DetectedGame; import de.grimsi.gameyfin.entities.UnmappableFile; import de.grimsi.gameyfin.igdb.IgdbWrapper; @@ -33,6 +34,10 @@ public class GameService { return detectedGameRepository.findAll(); } + public DetectedGame getDetectedGame(String slug) { + return detectedGameRepository.findById(slug).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Game with slug '%s' not found in library.".formatted(slug))); + } + public List getAllUnmappedFiles() { return unmappableFileRepository.findAll(); } @@ -41,6 +46,10 @@ public class GameService { return detectedGameRepository.findAll().stream().collect(Collectors.toMap(DetectedGame::getPath, DetectedGame::getTitle)); } + public List getGameOverviews() { + return detectedGameRepository.findAll().stream().map(GameMapper::toGameOverviewDto).toList(); + } + public DetectedGame mapUnmappedFile(Long unmappedGameId, String igdbSlug) { UnmappableFile unmappableFile = unmappableFileRepository.findById(unmappedGameId) diff --git a/frontend/src/app/api/GamesApi.ts b/frontend/src/app/api/GamesApi.ts index f945514..b198553 100644 --- a/frontend/src/app/api/GamesApi.ts +++ b/frontend/src/app/api/GamesApi.ts @@ -1,7 +1,10 @@ import {Observable} from "rxjs"; import {DetectedGameDto} from "../models/dtos/DetectedGameDto"; +import {GameOverviewDto} from "../models/dtos/GameOverviewDto"; export interface GamesApi { getAllGames(): Observable; + getGame(slug: String): Observable; + getGameOverviews(): Observable; getAllGameMappings(): Observable>; } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 968489a..922d108 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -5,6 +5,7 @@ import {PageNotFoundComponent} from "./components/page-not-found/page-not-found. import {NavbarLayoutComponent} from "./layouts/navbar-layout/navbar-layout.component"; import {NotImplementedComponent} from "./components/not-implemented/not-implemented.component"; import {LibraryOverviewComponent} from "./components/library-overview/library-overview.component"; +import {GameDetailViewComponent} from "./components/game-detail-view/game-detail-view.component"; const appRoutes: Routes = [ { @@ -16,16 +17,8 @@ const appRoutes: Routes = [ component: LibraryOverviewComponent }, { - path: 'games', - component: NotImplementedComponent - }, - { - path: 'info', - component: NotImplementedComponent - }, - { - path: 'config', - component: NotImplementedComponent + path: 'game/:slug', + component: GameDetailViewComponent }, { path: '', diff --git a/frontend/src/app/components/game-cover/game-cover.component.html b/frontend/src/app/components/game-cover/game-cover.component.html index dd9e2e4..50cedc2 100644 --- a/frontend/src/app/components/game-cover/game-cover.component.html +++ b/frontend/src/app/components/game-cover/game-cover.component.html @@ -1,5 +1,5 @@ diff --git a/frontend/src/app/components/game-cover/game-cover.component.ts b/frontend/src/app/components/game-cover/game-cover.component.ts index 6f8e6b4..5157295 100644 --- a/frontend/src/app/components/game-cover/game-cover.component.ts +++ b/frontend/src/app/components/game-cover/game-cover.component.ts @@ -1,5 +1,5 @@ import {Component, Input, OnInit} from '@angular/core'; -import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; +import {GameOverviewDto} from "../../models/dtos/GameOverviewDto"; @Component({ selector: 'game-cover', @@ -8,9 +8,10 @@ import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; }) export class GameCoverComponent implements OnInit { - @Input() game!: DetectedGameDto; + @Input() game!: GameOverviewDto; - constructor() { } + constructor() { + } ngOnInit(): void { } diff --git a/frontend/src/app/components/game-detail-view/game-detail-view.component.html b/frontend/src/app/components/game-detail-view/game-detail-view.component.html index 2fffb85..f351113 100644 --- a/frontend/src/app/components/game-detail-view/game-detail-view.component.html +++ b/frontend/src/app/components/game-detail-view/game-detail-view.component.html @@ -1 +1 @@ -

game-detail-view works!

+
{{game | json}}
diff --git a/frontend/src/app/components/game-detail-view/game-detail-view.component.ts b/frontend/src/app/components/game-detail-view/game-detail-view.component.ts index 7c9d888..64921a9 100644 --- a/frontend/src/app/components/game-detail-view/game-detail-view.component.ts +++ b/frontend/src/app/components/game-detail-view/game-detail-view.component.ts @@ -1,4 +1,8 @@ import { Component, OnInit } from '@angular/core'; +import {ActivatedRoute, Router} from "@angular/router"; +import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; +import {GamesService} from "../../services/games.service"; +import {HttpErrorResponse} from "@angular/common/http"; @Component({ selector: 'app-game-detail-view', @@ -7,7 +11,24 @@ import { Component, OnInit } from '@angular/core'; }) export class GameDetailViewComponent implements OnInit { - constructor() { } + game!: DetectedGameDto; + + constructor(private route: ActivatedRoute, + private router: Router, + private gamesService: GamesService) { + this.route.params.subscribe( params => { + this.gamesService.getGame(params['slug']).subscribe({ + next: game => this.game = game, + error: error => { + if(error.status === 404) { + this.router.navigate(['/library']); + } else { + console.error(error); + } + } + }); + }); + } ngOnInit(): void { } diff --git a/frontend/src/app/components/header/header.component.html b/frontend/src/app/components/header/header.component.html index 553433d..67bc2be 100644 --- a/frontend/src/app/components/header/header.component.html +++ b/frontend/src/app/components/header/header.component.html @@ -1,33 +1,2 @@ - - - - - - - -

TestUser

- - - - -
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 2242242..77dc75c 100644 --- a/frontend/src/app/components/library-overview/library-overview.component.ts +++ b/frontend/src/app/components/library-overview/library-overview.component.ts @@ -1,6 +1,7 @@ import {AfterViewInit, Component} from '@angular/core'; import {GamesService} from "../../services/games.service"; import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; +import {GameOverviewDto} from "../../models/dtos/GameOverviewDto"; @Component({ selector: 'app-gameserver-list', @@ -9,15 +10,15 @@ import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; }) export class LibraryOverviewComponent implements AfterViewInit { - detectedGames: DetectedGameDto[] = []; + detectedGames: GameOverviewDto[] = []; loading: boolean = true; constructor(private gameServerService: GamesService) { } ngAfterViewInit(): void { - this.gameServerService.getAllGames().subscribe( - (detectedGames: DetectedGameDto[]) => { + this.gameServerService.getGameOverviews().subscribe( + (detectedGames: GameOverviewDto[]) => { this.detectedGames = detectedGames; this.loading = false; } diff --git a/frontend/src/app/models/dtos/GameOverviewDto.ts b/frontend/src/app/models/dtos/GameOverviewDto.ts new file mode 100644 index 0000000..4a07e63 --- /dev/null +++ b/frontend/src/app/models/dtos/GameOverviewDto.ts @@ -0,0 +1,5 @@ +export class GameOverviewDto { + slug!: string; + title!: string; + coverId!: string; +} diff --git a/frontend/src/app/services/games.service.ts b/frontend/src/app/services/games.service.ts index 037d2fe..b7fadbf 100644 --- a/frontend/src/app/services/games.service.ts +++ b/frontend/src/app/services/games.service.ts @@ -3,6 +3,7 @@ import {GamesApi} from "../api/GamesApi"; import {HttpClient} from "@angular/common/http"; import {Observable} from "rxjs"; import {DetectedGameDto} from "../models/dtos/DetectedGameDto"; +import {GameOverviewDto} from "../models/dtos/GameOverviewDto"; @Injectable({ providedIn: 'root' @@ -18,6 +19,14 @@ export class GamesService implements GamesApi { return this.http.get(this.apiPath); } + getGame(slug: String): Observable { + return this.http.get(`${this.apiPath}/game/${slug}`); + } + + getGameOverviews(): Observable { + return this.http.get(`${this.apiPath}/game-overviews`); + } + getAllGameMappings(): Observable> { return this.http.get>(`${this.apiPath}/game-mappings`); }