Skip to content

Commit

Permalink
feat: movie manager
Browse files Browse the repository at this point in the history
  • Loading branch information
69pmb committed Oct 29, 2023
1 parent 0adce3a commit d38659f
Show file tree
Hide file tree
Showing 11 changed files with 500 additions and 444 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import {TranslateService, LangChangeEvent} from '@ngx-translate/core';
import {TranslateService} from '@ngx-translate/core';
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {ActivatedRoute, Router, Params} from '@angular/router';
import {
Component,
OnInit,
OnDestroy,
Input,
OnChanges,
SimpleChanges,
Output,
EventEmitter,
} from '@angular/core';
import {ActivatedRoute, Router, ParamMap} from '@angular/router';
import {filter} from 'rxjs/operators';
import {combineLatest, Subscription} from 'rxjs';
filter,
tap,
map,
switchMap,
distinctUntilChanged,
} from 'rxjs/operators';
import {combineLatest, merge, ReplaySubject} from 'rxjs';
import {
faImage,
faChevronCircleRight,
Expand All @@ -22,42 +19,137 @@ import {
import {Tag} from './../../../../model/tag';
import {DuckDuckGo} from './../../../../constant/duck-duck-go';
import {Movie} from '../../../../model/movie';
import {Keyword, Genre, DetailConfig} from '../../../../model/model';
import {MovieService} from '../../../../service/movie.service';
import {DetailConfig, Id} from '../../../../model/model';
import {TitleService} from '../../../../service/title.service';
import {TabsService} from '../../../../service/tabs.service';
import {MyTagsService} from '../../../../service/my-tags.service';
import {MyDatasService} from '../../../../service/my-datas.service';
import {MenuService} from '../../../../service/menu.service';
import {MovieManager} from '../../../../manager/movie.manager';

@Component({
selector: 'app-movie-detail',
styleUrls: ['./movie-detail.component.scss'],
templateUrl: './movie-detail.component.html',
})
export class MovieDetailComponent implements OnInit, OnChanges, OnDestroy {
@Input() id!: number;
@Input() config!: DetailConfig;
export class MovieDetailComponent {
private readonly id$ = new ReplaySubject<number>(1);
private readonly config$ = new ReplaySubject<DetailConfig>(1);

@Input()
set id(value: number) {
this.isDetail = false;
this.config$.next(
new DetailConfig(
true,
true,
false,
false,
false,
false,
true,
false,
false,
undefined
)
);
this.loaded.emit(false);
this.id$.next(value);
}

ids$ = merge(
this.movieManager.listenParam(this.route.paramMap, 'id').pipe(
filter(id => id !== 0),
tap(() => {
this.isDetail = true;
this.config$.next(
new DetailConfig(
true,
true,
true,
true,
true,
true,
true,
true,
false,
undefined
)
);
})
),
this.id$
);

movie$ = this.config$.pipe(
distinctUntilChanged(
(prev, curr) =>
prev.similar === curr.similar && prev.keywords === curr.keywords
),
switchMap(config =>
this.movieManager.find(this.ids$, config).pipe(
tap(movie => {
this.loaded.emit(true);
if (this.isDetail) {
this.title.setTitle(movie.title);
this.menuService.scrollTo$.next(0);
}
})
)
)
);

loading$ = combineLatest([this.ids$, this.movie$]).pipe(
map(([i, m]) => !m || i !== m.id)
);

tags$ = combineLatest([
this.myTagsService.myTags$,
this.myDatasService.myMovies$,
this.movie$,
]).pipe(
filter(
([tags, movies, movie]) =>
tags !== undefined &&
tags.length > 0 &&
movies !== undefined &&
movie !== undefined
),
map(([tags, movies, movie]) => {
this.showTags = false;
if (movies.map(m => m.id).includes(movie.id)) {
this.showTags = true;
return tags.filter(t =>
t.datas
.filter(d => d.movie)
.map(d => d.id)
.includes(movie.id)
);
} else {
return [];
}
})
);

@Output() loaded = new EventEmitter<boolean>();
movie!: Movie;
tags: Tag[] = [];
showTags = false;
isImagesVisible = false;
isDetail!: boolean;
isDetail: boolean;
showTitles = false;
sc!: string;
sc: string;
Url = DuckDuckGo;
subs: Subscription[] = [];

faChevronCircleRight = faChevronCircleRight;
faImage = faImage;
faPlus = faPlus;
faMinus = faMinus;

constructor(
private movieService: MovieService,
private movieManager: MovieManager,
private route: ActivatedRoute,
private translate: TranslateService,
protected translate: TranslateService,
private title: TitleService,
private router: Router,
public tabsService: TabsService,
Expand All @@ -66,101 +158,11 @@ export class MovieDetailComponent implements OnInit, OnChanges, OnDestroy {
private myDatasService: MyDatasService<Movie>
) {}

ngOnInit(): void {
this.subs.push(
this.route.paramMap.subscribe((params: ParamMap) => {
if (params) {
const idParam = +params.get('id');
if (idParam && idParam !== 0) {
this.id = idParam;
this.isDetail = true;
this.getMovie(this.id);
}
}
})
);
this.subs.push(
this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
this.config.lang = event.lang;
this.getMovie(this.id);
})
);
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.id) {
this.id = changes.id.currentValue ? changes.id.currentValue : this.id;
this.isDetail = false;
}
this.getMovie(this.id);
}

getMovie(id: number): void {
if (this.id && this.id !== 0) {
this.loaded.emit(false);
this.config =
this.config === undefined
? new DetailConfig(
true,
true,
true,
true,
true,
true,
true,
true,
false,
this.translate.currentLang
)
: this.config;
this.movieService.getMovie(id, this.config, true).then(movie => {
this.movie = movie;
this.loaded.emit(true);
if (this.isDetail) {
this.title.setTitle(movie.title);
this.menuService.scrollTo$.next(0);
}
});
this.subs.push(
combineLatest([
this.myTagsService.myTags$,
this.myDatasService.myMovies$,
])
.pipe(
filter(
([tags, movies]) => tags !== undefined && movies !== undefined
)
)
.subscribe(([tags, movies]) => {
this.tags = [];
this.showTags = false;
if (movies.map(m => m.id).includes(this.id)) {
this.showTags = true;
this.tags = tags.filter(t =>
t.datas
.filter(d => d.movie)
.map(m => m.id)
.includes(this.id)
);
}
})
);
}
}

redirectGenreToDiscover(genre: Genre): void {
toDiscover<T extends Id>(item: T, key: string): void {
const params: Params = {};
params[key] = JSON.stringify([item.id]);
this.router.navigate(['discover'], {
queryParams: {genre: JSON.stringify([genre.id])},
queryParams: params,
});
}

redirectKeywordToDiscover(keyword: Keyword): void {
this.router.navigate(['discover'], {
queryParams: {keyword: JSON.stringify([keyword.id])},
});
}

ngOnDestroy(): void {
this.subs.forEach(subscription => subscription.unsubscribe());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ <h3>
<div *ngIf="selectedId">
<app-movie-detail
[id]="selectedId"
[config]="config"
(loaded)="onLoaded()"
></app-movie-detail>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ export class SeasonDetailComponent {
faArrowCircleRight = faArrowCircleRight;

serie$ = this.serieManager
.find(this.route.paramMap, 'id')
.find(this.serieManager.listenParam(this.route.paramMap, 'id'))
.pipe(tap(s => this.title.setTitle(s.title)));

season$ = this.seasonManager.find(this.route.paramMap, 'season').pipe(
map(season => {
season.images.push(...season.episodes.map(e => e.poster));
season.images = season.images.filter(i => Utils.isNotBlank(i));
return season;
})
);
season$ = this.seasonManager
.find(this.serieManager.listenParam(this.route.paramMap, 'season'))
.pipe(
map(season => {
season.images.push(...season.episodes.map(e => e.poster));
season.images = season.images.filter(i => Utils.isNotBlank(i));
return season;
})
);

constructor(
private serieManager: SerieManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ export class SerieDetailComponent {
imageSize = ImageSize;
protected sc!: string;

serie$ = this.serieManager.find(this.route.paramMap, 'id').pipe(
tap(serie => {
this.title.setTitle(serie.title);
this.menuService.scrollTo$.next(0);
})
);
serie$ = this.serieManager
.find(this.serieManager.listenParam(this.route.paramMap, 'id'))
.pipe(
tap(serie => {
this.title.setTitle(serie.title);
this.menuService.scrollTo$.next(0);
})
);

loading$ = combineLatest([
this.serieManager.listenParam(this.route.paramMap, 'id'),
Expand Down
6 changes: 3 additions & 3 deletions src/app/manager/abstract.manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
map,
startWith,
} from 'rxjs/operators';
import {DetailConfig} from '../model/model';

export abstract class AbstractService<T, ID> {
private readonly id$ = new BehaviorSubject<ID>(undefined);
Expand Down Expand Up @@ -51,8 +52,7 @@ export abstract class AbstractService<T, ID> {
}

public abstract find(
paramMap: Observable<ParamMap>,
key: string,
...args: (number | string)[]
id$: Observable<number>,
...args: DetailConfig[]
): Observable<T>;
}
40 changes: 40 additions & 0 deletions src/app/manager/movie.manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {Injectable} from '@angular/core';
import {AbstractService} from './abstract.manager';
import {DetailConfig} from '../model/model';
import {TranslateService} from '@ngx-translate/core';
import {Observable, combineLatest} from 'rxjs';
import {switchMap, tap} from 'rxjs/operators';
import {MovieService} from '../service/movie.service';
import {Movie} from '../model/movie';

@Injectable({
providedIn: 'root',
})
export class MovieManager extends AbstractService<
Movie,
{id: number; config: DetailConfig}
> {
constructor(
private readonly movieService: MovieService,
translate: TranslateService
) {
super(
movieId => this.movieService.getMovie$(movieId.id, movieId.config, true),
(prev, curr) =>
prev.id === curr.id &&
prev.config.lang === curr.config.lang &&
prev.config.reco === curr.config.reco,
translate
);
}

find(id$: Observable<number>, config: DetailConfig): Observable<Movie> {
return combineLatest([id$, this.lang$]).pipe(
tap(([id, lang]) => {
config.lang = lang;
this.update({id, config});
}),
switchMap(() => this.listen())
);
}
}
Loading

0 comments on commit d38659f

Please sign in to comment.