feat: add crew on movie page (#4722)

* add crew on movie page

* order by director, add default image and fix click

Co-authored-by: tidusjar <tidusjar@gmail.com>
fix-stats-controller
Hadrien 2 years ago committed by GitHub
parent 2f5d54c5bf
commit 1d53261382
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -268,6 +268,12 @@
<e p="cast-carousel.component.scss" t="Include" />
<e p="cast-carousel.component.ts" t="Include" />
</e>
<e p="crew-carousel" t="Include">
<e p="crew-carousel.component.html" t="Include" />
<e p="crew-carousel.component.scss" t="Include" />
<e p="crew-carousel.component.ts" t="Include" />
</e>
<e p="deny-dialog" t="Include">
<e p="deny-dialog.component.html" t="Include" />
<e p="deny-dialog.component.ts" t="Include" />

@ -1,7 +1,7 @@
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { SearchV2Service } from "../../../services";
import { IActorCredits, IActorCast } from "../../../interfaces/ISearchTvResultV2";
import { IActorCredits, IActorCast, IActorCrew } from "../../../interfaces/ISearchTvResultV2";
import { IDiscoverCardResult } from "../../interfaces";
import { RequestType } from "../../../interfaces";
import { AuthService } from "../../../auth/auth.service";
@ -38,13 +38,13 @@ export class DiscoverActorComponent implements OnInit {
this.searchService.getMoviesByActor(this.actorId),
this.searchService.getTvByActor(this.actorId)
]).subscribe(([movie, tv]) => {
this.pushDiscoverResults(movie.cast, RequestType.movie);
this.pushDiscoverResults(tv.cast, RequestType.tvShow);
this.pushDiscoverResults(movie.crew, movie.cast, RequestType.movie);
this.pushDiscoverResults(tv.crew, tv.cast, RequestType.tvShow);
this.finishLoading();
});
}
pushDiscoverResults(cast: IActorCast[], type: RequestType) {
pushDiscoverResults(crew: IActorCrew[], cast: IActorCast[], type: RequestType) {
cast.forEach(m => {
this.discoverResults.push({
available: false,
@ -62,6 +62,23 @@ export class DiscoverActorComponent implements OnInit {
background: ""
});
});
crew.forEach(m => {
this.discoverResults.push({
available: false,
posterPath: m.poster_path ? `https://image.tmdb.org/t/p/w300/${m.poster_path}` : "../../../images/default_movie_poster.png",
requested: false,
title: m.title,
type: type,
id: m.id,
url: null,
rating: 0,
overview: m.overview,
approved: false,
imdbid: "",
denied: false,
background: ""
});
});
}
private loading() {

@ -4,6 +4,7 @@ import { ArtistDetailsComponent } from "./artist/artist-details.component";
import { ArtistInformationPanel } from "./artist/panels/artist-information-panel/artist-information-panel.component";
import { ArtistReleasePanel } from "./artist/panels/artist-release-panel/artist-release-panel.component";
import { CastCarouselComponent } from "./shared/cast-carousel/cast-carousel.component";
import { CrewCarouselComponent } from "./shared/crew-carousel/crew-carousel.component";
import { DenyDialogComponent } from "./shared/deny-dialog/deny-dialog.component";
import { IssuesPanelComponent } from "./shared/issues-panel/issues-panel.component";
import { MediaPosterComponent } from "./shared/media-poster/media-poster.component";
@ -32,6 +33,7 @@ export const components: any[] = [
SocialIconsComponent,
MediaPosterComponent,
CastCarouselComponent,
CrewCarouselComponent,
DenyDialogComponent,
TvRequestsPanelComponent,
MovieAdvancedOptionsComponent,

@ -197,13 +197,19 @@
</mat-card>
</div>
</div>
<div class="row">
<div class="col-12">
<cast-carousel [cast]="movie.credits.cast"></cast-carousel>
</div>
</div>
<div class="row">
<div class="col-12">
<crew-carousel [crew]="movie.credits.crew"></crew-carousel>
</div>
</div>
<!-- <div class="row card-spacer" *ngIf="movie.videos?.results?.length > 0">
<div class="col-md-6" *ngFor="let video of movie.videos?.results">

@ -2,7 +2,7 @@ import { Component, OnInit, ViewEncapsulation } from "@angular/core";
import { ImageService, SearchV2Service, RequestService, MessageService, RadarrService, SettingsStateService } from "../../../services";
import { ActivatedRoute, Router } from "@angular/router";
import { DomSanitizer } from "@angular/platform-browser";
import { ISearchMovieResultV2 } from "../../../interfaces/ISearchMovieResultV2";
import { ICrewViewModel, ISearchMovieResultV2 } from "../../../interfaces/ISearchMovieResultV2";
import { MatDialog } from "@angular/material/dialog";
import { YoutubeTrailerComponent } from "../shared/youtube-trailer.component";
import { AuthService } from "../../../auth/auth.service";
@ -82,6 +82,7 @@ export class MovieDetailsComponent implements OnInit{
this.searchService.getMovieByImdbId(this.imdbId).subscribe(async x => {
this.movie = x;
this.checkPoster();
this.movie.credits.crew = this.orderCrew(this.movie.credits.crew);
if (this.movie.requestId > 0) {
// Load up this request
this.hasRequest = true;
@ -93,6 +94,7 @@ export class MovieDetailsComponent implements OnInit{
this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(async x => {
this.movie = x;
this.checkPoster();
this.movie.credits.crew = this.orderCrew(this.movie.credits.crew);
if (this.movie.requestId > 0) {
// Load up this request
this.hasRequest = true;
@ -319,4 +321,16 @@ export class MovieDetailsComponent implements OnInit{
});
}
private orderCrew(crew: ICrewViewModel[]): ICrewViewModel[] {
return crew.sort((a, b) => {
if (a.job === "Director") {
return -1;
} else if (b.job === "Director") {
return 1;
} else {
return 0;
}
});
}
}

@ -11,7 +11,7 @@
<a *ngIf="item.profile_path" [routerLink]="'/discover/actor/' + item.id">
<ombi-image class="cast-profile-img" src="https://image.tmdb.org/t/p/w300{{item.profile_path}}"></ombi-image>
</a>
<!-- TODO get profile image default -->
<i *ngIf="!item.image && !item.profile_path" class="fa-solid fa-user-large fa-2xl crew-profile-img" aria-hidden="true"></i>
</div>
<div class="col-12">

@ -0,0 +1,32 @@
<mat-card class="mat-elevation-z8 spacing-below">
<mat-card-header>{{'MediaDetails.Crews.CrewTitle' | translate}}</mat-card-header>
<mat-card-content>
<p-carousel [value]="crew" easing="easeOutStrong" [responsiveOptions]="responsiveOptions" [numVisible]="5" >
<ng-template let-item pTemplate="item">
<div class="row justify-content-md-center mat-card mat-card-flat carousel-item">
<div [routerLink]="'/discover/actor/' + item.id" class="bottom-space link">
<a *ngIf="item.image">
<img class="crew-profile-img" src="https://image.tmdb.org/t/p/w300{{item.image}}">
</a>
<a *ngIf="item.profile_path">
<img class="crew-profile-img" src="https://image.tmdb.org/t/p/w300{{item.profile_path}}">
</a>
<i *ngIf="!item.image && !item.profile_path" class="fa-solid fa-user-large fa-2xl crew-profile-img" aria-hidden="true"></i>
</div>
<div class="col-12">
<span *ngIf="item.name"><strong>{{item.name}}</strong></span>
<span *ngIf="item.person"><strong>{{item.person}}</strong></span>
</div>
<div class="col-12">
<span *ngIf="item.job"><small>{{item.job}}</small></span>
<span *ngIf="item.department"><small>{{item.position}}</small></span>
<span *ngIf="item.title"><small>{{item.title}}</small></span>
<span *ngIf="item.overview"><small>{{item.overview}}</small></span>
</div>
</div>
</ng-template>
</p-carousel>
</mat-card-content>
</mat-card>

@ -0,0 +1,87 @@
@import "~@angular/material/theming";
@import "~styles/variables.scss";
::ng-deep body .ui-carousel .ui-carousel-content .ui-carousel-prev,
body .ui-carousel .ui-carousel-content .ui-carousel-next {
background-color: #ffffff;
border: solid 1px rgba(178, 193, 205, 0.64);
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
margin: 0.2em;
color: #333333;
-moz-transition: color 0.2s;
-o-transition: color 0.2s;
-webkit-transition: color 0.2s;
transition: color 0.2s;
}
::ng-deep body .ui-carousel .ui-carousel-content .ui-carousel-prev:not(.ui-state-disabled):hover,
body .ui-carousel .ui-carousel-content .ui-carousel-next:not(.ui-state-disabled):hover {
background-color: #ffffff;
color: #000;
border-color: solid 1px rgba(178, 193, 205, 0.64);
}
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item>.ui-button {
border-color: transparent;
background-color: transparent;
}
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item .ui-carousel-dot-icon {
width: 20px;
height: 6px;
background-color: rgba(255, 255, 255, 0.44);
margin: 0 0.2em;
}
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item .ui-carousel-dot-icon::before {
content: " ";
}
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item.ui-state-highlight .ui-carousel-dot-icon {
background-color: #FFF;
}
.carousel-item {
text-align: center;
}
::ng-deep .ui-carousel-next {
background-color: #ffffff;
border: solid 1px rgba(178, 193, 205, 0.64);
border-radius: 50%;
margin: 0.2em;
color: #333333;
transition: color 0.2s;
}
::ng-deep .ui-carousel-content button:focus {
outline: none;
}
.bottom-space {
padding-bottom: 10px;
}
@media (min-width: 979px) {
.crew-profile-img {
border-radius: 100%;
width: 200px;
max-height: 200px;
object-fit: cover;
}
}
@media (max-width: 978px) {
.crew-profile-img {
border-radius: 100%;
width: 100px;
max-height: 100px;
object-fit: cover;
}
}
.link {
cursor: pointer;
}

@ -0,0 +1,32 @@
import { Component, Input } from "@angular/core";
@Component({
selector: "crew-carousel",
templateUrl: "./crew-carousel.component.html",
styleUrls: ["./crew-carousel.component.scss"]
})
export class CrewCarouselComponent {
constructor() {
this.responsiveOptions = [
{
breakpoint: '1024px',
numVisible: 5,
numScroll: 5
},
{
breakpoint: '768px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '560px',
numVisible: 1,
numScroll: 1
}
];
}
@Input() crew: any[];
public responsiveOptions: any[];
}

@ -181,6 +181,11 @@
}
.crew-profile-img {
border-radius: 100%;
width: 170px;
}
.small-middle-container {
margin: auto;

@ -364,6 +364,9 @@
"Casts": {
"CastTitle": "Cast"
},
"Crews": {
"CrewTitle": "Crew"
},
"EpisodeSelector": {
"AllSeasonsTooltip": "This will request every season for this show",
"FirstSeasonTooltip": "This will only request the First Season for this show",

@ -364,6 +364,9 @@
"Casts": {
"CastTitle": "Casting"
},
"Crews": {
"CrewTitle": "Equipe"
},
"EpisodeSelector": {
"AllSeasonsTooltip": "Cette action demandera toutes les saisons de cette série",
"FirstSeasonTooltip": "Cette action ne demandera que la Première Saison de cette série",

Loading…
Cancel
Save