From aac5ad0e282bfa3a9977963af526e4f2c8be0599 Mon Sep 17 00:00:00 2001 From: Chau Tran Date: Fri, 2 Apr 2021 07:27:40 -0500 Subject: [PATCH] Adjust stream constructions and remove most template function calls (#29) * refactor: adjust stream constructions and remove most template call * feat: update getPlaylistsWithRouteUrl selector Co-authored-by: Trung Vo --- apps/angular-spotify/src/app/app.component.ts | 18 +++++------ .../src/lib/unauthorized-modal.component.ts | 3 +- .../feature-playlists.selector.ts | 21 ++++++++++++ .../src/lib/featured-playlists.component.html | 18 ++++++----- .../src/lib/featured-playlists.component.ts | 10 ++---- .../lib/store/playlists/playlists.selector.ts | 14 +++++++- .../list/src/lib/playlists.component.html | 2 +- .../list/src/lib/playlists.component.ts | 10 ++---- .../src/lib/playlist-track.component.html | 7 ++-- .../src/lib/playlist-track.component.ts | 32 ++++++++++++++++--- .../src/lib/track-current-info.component.ts | 2 +- .../src/lib/album-art-overlay.component.html | 9 +++--- .../src/lib/album-art-overlay.component.ts | 7 ++-- .../nav-playlist/nav-playlist.component.html | 6 ++-- .../nav-playlist/nav-playlist.component.ts | 17 +++++----- .../src/lib/player-volume.component.ts | 8 ++--- .../src/lib/user-dropdown.component.ts | 5 ++- .../feature/src/lib/visualizer.component.ts | 14 +++++--- 18 files changed, 127 insertions(+), 76 deletions(-) diff --git a/apps/angular-spotify/src/app/app.component.ts b/apps/angular-spotify/src/app/app.component.ts index 99221a37..cd9aebcb 100644 --- a/apps/angular-spotify/src/app/app.component.ts +++ b/apps/angular-spotify/src/app/app.component.ts @@ -1,24 +1,24 @@ import { Component } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; +import { filter } from 'rxjs/operators'; import { environment } from '../environments/environment'; import { GoogleAnalyticsService } from './google-analytics.service'; @Component({ selector: 'angular-spotify-root', - template: ``, + template: ` `, styleUrls: ['./app.component.scss'] }) export class AppComponent { constructor(private router: Router, private googleAnalytics: GoogleAnalyticsService) { if (environment.production) { - this.router.events.subscribe(this.handleGoogleAnalytics); + this.router.events + .pipe(filter((event) => event instanceof NavigationEnd)) + .subscribe((navigationEndEvent) => { + this.googleAnalytics.sendPageView( + (navigationEndEvent as NavigationEnd).urlAfterRedirects + ); + }); } } - - handleGoogleAnalytics = (event: any): void => { - // eslint-disable-line - if (event instanceof NavigationEnd) { - this.googleAnalytics.sendPageView(event.urlAfterRedirects); - } - }; } diff --git a/libs/web/auth/ui/unauthorized-modal/src/lib/unauthorized-modal.component.ts b/libs/web/auth/ui/unauthorized-modal/src/lib/unauthorized-modal.component.ts index 70d9858a..c6bcee27 100644 --- a/libs/web/auth/ui/unauthorized-modal/src/lib/unauthorized-modal.component.ts +++ b/libs/web/auth/ui/unauthorized-modal/src/lib/unauthorized-modal.component.ts @@ -1,6 +1,7 @@ +import { AuthStore } from '@angular-spotify/web/auth/data-access'; import { ChangeDetectionStrategy, Component } from '@angular/core'; import { NzModalRef } from 'ng-zorro-antd/modal'; -import { AuthStore } from '@angular-spotify/web/auth/data-access'; + @Component({ templateUrl: './unauthorized-modal.component.html', styleUrls: ['./unauthorized-modal.component.scss'], diff --git a/libs/web/home/data-access/src/lib/store/feature-playlists/feature-playlists.selector.ts b/libs/web/home/data-access/src/lib/store/feature-playlists/feature-playlists.selector.ts index f5813ca1..9fd53f97 100644 --- a/libs/web/home/data-access/src/lib/store/feature-playlists/feature-playlists.selector.ts +++ b/libs/web/home/data-access/src/lib/store/feature-playlists/feature-playlists.selector.ts @@ -1,3 +1,4 @@ +import { RouteUtil } from '@angular-spotify/web/shared/utils'; import { createFeatureSelector, createSelector } from '@ngrx/store'; import { featuredPlaylistsFeatureKey, FeaturePlaylistsState } from './feature-playlists.reducer'; @@ -8,3 +9,23 @@ export const getFeaturePlaylistsState = createFeatureSelector { return data; }); + +export const getFeaturedPlaylistsWithRouteUrl = createSelector( + getFeaturedPlaylists, + (featuredPlaylists) => { + if (featuredPlaylists) { + return { + ...featuredPlaylists, + playlists: { + ...featuredPlaylists.playlists, + items: featuredPlaylists.playlists.items.map((item) => ({ + ...item, + routeUrl: RouteUtil.getPlaylistRouteUrl(item) + })) + } + }; + } + + return featuredPlaylists; + } +); diff --git a/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.html b/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.html index 11d6f2dc..56242d8a 100644 --- a/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.html +++ b/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.html @@ -1,13 +1,15 @@

{{ data.message }}

- +
-
\ No newline at end of file + diff --git a/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.ts b/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.ts index bd579e97..d91620ed 100644 --- a/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.ts +++ b/libs/web/home/ui/featured-playlists/src/lib/featured-playlists.component.ts @@ -1,6 +1,5 @@ -import { getFeaturedPlaylists } from '@angular-spotify/web/home/data-access'; +import { getFeaturedPlaylistsWithRouteUrl } from '@angular-spotify/web/home/data-access'; import { PlayerApiService } from '@angular-spotify/web/shared/data-access/spotify-api'; -import { RouteUtil } from '@angular-spotify/web/shared/utils'; import { ChangeDetectionStrategy, Component } from '@angular/core'; import { select, Store } from '@ngrx/store'; @@ -11,11 +10,10 @@ import { select, Store } from '@ngrx/store'; changeDetection: ChangeDetectionStrategy.OnPush }) export class FeaturedPlaylistsComponent { - featuredPlaylists$ = this.store.pipe(select(getFeaturedPlaylists)); + featuredPlaylists$ = this.store.pipe(select(getFeaturedPlaylistsWithRouteUrl)); constructor(private store: Store, private playerApi: PlayerApiService) {} - togglePlay(isPlaying: boolean, playlistUri: string) { this.playerApi .togglePlay(isPlaying, { @@ -23,8 +21,4 @@ export class FeaturedPlaylistsComponent { }) .subscribe(); } - - getPlaylistRouteUrl(playlist: SpotifyApi.PlaylistObjectSimplified) { - return RouteUtil.getPlaylistRouteUrl(playlist); - } } diff --git a/libs/web/playlist/data-access/src/lib/store/playlists/playlists.selector.ts b/libs/web/playlist/data-access/src/lib/store/playlists/playlists.selector.ts index 929076cd..e6258189 100644 --- a/libs/web/playlist/data-access/src/lib/store/playlists/playlists.selector.ts +++ b/libs/web/playlist/data-access/src/lib/store/playlists/playlists.selector.ts @@ -1,9 +1,21 @@ +import { RouteUtil, SelectorUtil } from '@angular-spotify/web/shared/utils'; import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { SelectorUtil } from '@angular-spotify/web/shared/utils'; import { playlistsFeatureKey, PlaylistsState } from './playlists.reducer'; export const getPlaylistsState = createFeatureSelector(playlistsFeatureKey); export const getPlaylists = createSelector(getPlaylistsState, (state) => state.data); +export const getPlaylistsWithRouteUrl = createSelector(getPlaylists, (playlists) => { + if (playlists) { + return { + ...playlists, + items: playlists.items.map((item) => ({ + ...item, + routeUrl: RouteUtil.getPlaylistRouteUrl(item) + })) + }; + } + return playlists; +}); export const getPlaylistsLoading = createSelector(getPlaylistsState, SelectorUtil.isLoading); export const getPlaylistsDone = createSelector(getPlaylistsState, SelectorUtil.isDone); export const getPlaylistsMap = createSelector(getPlaylistsState, (state) => state.map); diff --git a/libs/web/playlist/feature/list/src/lib/playlists.component.html b/libs/web/playlist/feature/list/src/lib/playlists.component.html index 98f8ba0b..07f11810 100644 --- a/libs/web/playlist/feature/list/src/lib/playlists.component.html +++ b/libs/web/playlist/feature/list/src/lib/playlists.component.html @@ -6,7 +6,7 @@ [uri]="playlist.uri" [description]="playlist.description" [imageUrl]="playlist.images[0]?.url" - [routerUrl]="getPlaylistRouteUrl(playlist)" + [routerUrl]="playlist.routeUrl" (togglePlay)="togglePlay($event, playlist.uri)" > diff --git a/libs/web/playlist/feature/list/src/lib/playlists.component.ts b/libs/web/playlist/feature/list/src/lib/playlists.component.ts index 8b2d7bbc..db61df6f 100644 --- a/libs/web/playlist/feature/list/src/lib/playlists.component.ts +++ b/libs/web/playlist/feature/list/src/lib/playlists.component.ts @@ -2,7 +2,7 @@ import { PlayerApiService } from '@angular-spotify/web/shared/data-access/spotif import { RouteUtil } from '@angular-spotify/web/shared/utils'; import { ChangeDetectionStrategy, Component } from '@angular/core'; import { select, Store } from '@ngrx/store'; -import { getPlaylists, getPlaylistsLoading } from '@angular-spotify/web/playlist/data-access'; +import { getPlaylists, getPlaylistsLoading, getPlaylistsWithRouteUrl } from '@angular-spotify/web/playlist/data-access'; @Component({ selector: 'as-playlists', @@ -11,14 +11,10 @@ import { getPlaylists, getPlaylistsLoading } from '@angular-spotify/web/playlist changeDetection: ChangeDetectionStrategy.OnPush }) export class PlaylistsComponent { - playlists$ = this.store.pipe(select(getPlaylists)); + playlists$ = this.store.pipe(select(getPlaylistsWithRouteUrl)); isPlaylistsLoading$ = this.store.pipe(select(getPlaylistsLoading)); - constructor(private store: Store, private playerApi: PlayerApiService) { - } - - getPlaylistRouteUrl(playlist: SpotifyApi.PlaylistObjectSimplified) { - return RouteUtil.getPlaylistRouteUrl(playlist); + constructor(private store: Store, private playerApi: PlayerApiService) { } togglePlay(isPlaying: boolean, contextUri: string) { diff --git a/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.html b/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.html index 0a9ca792..c99cab7c 100644 --- a/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.html +++ b/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.html @@ -2,12 +2,9 @@ - + - + {{ item.track.album.name }}
diff --git a/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.ts b/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.ts index e961df23..ae415440 100644 --- a/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.ts +++ b/libs/web/playlist/ui/playlist-track/src/lib/playlist-track.component.ts @@ -1,8 +1,15 @@ -import { Component, OnInit, ChangeDetectionStrategy, Input, ViewEncapsulation } from '@angular/core'; -import { combineLatest, Observable, of } from 'rxjs'; +import { PlayerApiService } from '@angular-spotify/web/shared/data-access/spotify-api'; import { PlaybackStore } from '@angular-spotify/web/shared/data-access/store'; import { RouteUtil, SelectorUtil } from '@angular-spotify/web/shared/utils'; -import { PlayerApiService } from '@angular-spotify/web/shared/data-access/spotify-api'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnInit, + ViewEncapsulation +} from '@angular/core'; +import { combineLatest, Observable, of } from 'rxjs'; + @Component({ selector: 'as-playlist-track', templateUrl: './playlist-track.component.html', @@ -11,16 +18,31 @@ import { PlayerApiService } from '@angular-spotify/web/shared/data-access/spotif encapsulation: ViewEncapsulation.None }) export class PlaylistTrackComponent implements OnInit { + get item(): SpotifyApi.PlaylistTrackObject | undefined { + return this._item; + } + + @Input() + set item(value: SpotifyApi.PlaylistTrackObject | undefined) { + this._item = value; + if (value?.track) { + this.albumRouteUrl = RouteUtil.getAlbumRouteUrl(value.track.album.id); + } + } + + private _item: SpotifyApi.PlaylistTrackObject | undefined; + @Input() index!: number; @Input() contextUri!: string | null; - @Input() item: SpotifyApi.PlaylistTrackObject | undefined; + isTrackPlaying$!: Observable; + albumRouteUrl?: string; constructor(private playbackStore: PlaybackStore, private playerApi: PlayerApiService) {} ngOnInit(): void { this.isTrackPlaying$ = SelectorUtil.getTrackPlayingState( - combineLatest([of(this.item?.track.id), this.playbackStore.playback$]) + combineLatest([of(this._item?.track.id), this.playbackStore.playback$]) ); } diff --git a/libs/web/shared/ui/track-current-info/src/lib/track-current-info.component.ts b/libs/web/shared/ui/track-current-info/src/lib/track-current-info.component.ts index 2ed80876..9a2b5316 100644 --- a/libs/web/shared/ui/track-current-info/src/lib/track-current-info.component.ts +++ b/libs/web/shared/ui/track-current-info/src/lib/track-current-info.component.ts @@ -1,6 +1,6 @@ /// -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { RouteUtil, StringUtil } from '@angular-spotify/web/shared/utils'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; @Component({ selector: 'as-track-current-info', diff --git a/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.html b/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.html index 71ed7fc6..3624b5ff 100644 --- a/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.html +++ b/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.html @@ -1,4 +1,5 @@ -
-
\ No newline at end of file +
diff --git a/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.ts b/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.ts index aad3a1c0..5fb6ec32 100644 --- a/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.ts +++ b/libs/web/shell/ui/album-art-overlay/src/lib/album-art-overlay.component.ts @@ -1,5 +1,5 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; import { PlaybackStore } from '@angular-spotify/web/shared/data-access/store'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { map } from 'rxjs/operators'; @Component({ @@ -15,10 +15,9 @@ export class AlbumArtOverlayComponent { return null; } const imageUrl = track.album.images[0]?.url; - return imageUrl ? `url(${imageUrl})` : null + return imageUrl ? `url(${imageUrl})` : null; }) ); - constructor(private playbackStore: PlaybackStore) { - } + constructor(private playbackStore: PlaybackStore) {} } diff --git a/libs/web/shell/ui/nav-bar-playlist/src/lib/nav-playlist/nav-playlist.component.html b/libs/web/shell/ui/nav-bar-playlist/src/lib/nav-playlist/nav-playlist.component.html index 095aa216..db1ba99c 100644 --- a/libs/web/shell/ui/nav-bar-playlist/src/lib/nav-playlist/nav-playlist.component.html +++ b/libs/web/shell/ui/nav-bar-playlist/src/lib/nav-playlist/nav-playlist.component.html @@ -1,12 +1,12 @@ - {{ playlist.name }} + {{ playlistWithRoute.name }} ; constructor(private playbackStore: PlaybackStore, private playerApi: PlayerApiService) {} ngOnInit(): void { this.isPlaylistPlaying$ = SelectorUtil.getMediaPlayingState( - combineLatest([of(this.playlist?.uri), this.playbackStore.playback$]) + combineLatest([of(this.playlistWithRoute?.uri), this.playbackStore.playback$]) ); } - getPlaylistRouteUrl(playlist: SpotifyApi.PlaylistObjectSimplified) { - return RouteUtil.getPlaylistRouteUrl(playlist); - } - togglePlaylist(isPlaying: boolean) { this.playerApi .togglePlay(isPlaying, { - context_uri: this.playlist?.uri + context_uri: this.playlistWithRoute?.uri }) .subscribe(); //TODO: Refactor with component store live stream } diff --git a/libs/web/shell/ui/player-volume/src/lib/player-volume.component.ts b/libs/web/shell/ui/player-volume/src/lib/player-volume.component.ts index ceb6c802..10431835 100644 --- a/libs/web/shell/ui/player-volume/src/lib/player-volume.component.ts +++ b/libs/web/shell/ui/player-volume/src/lib/player-volume.component.ts @@ -1,6 +1,5 @@ import { VolumeHighIcon, - VolumeMediumIcon, VolumeMuteIcon } from '@angular-spotify/web/shared/data-access/models'; @@ -10,6 +9,7 @@ import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { NzSliderValue } from 'ng-zorro-antd/slider'; import { Subject } from 'rxjs'; import { debounceTime, map, switchMap } from 'rxjs/operators'; + @UntilDestroy() @Component({ selector: 'as-player-volume', @@ -25,11 +25,11 @@ export class PlayerVolumeComponent { map((volume) => { if (volume >= 70) { return new VolumeHighIcon(volume); - } else if (volume > 0) { + } + if (volume > 0) { return new VolumeMediumIcon(volume); - } else { - return new VolumeMuteIcon(); } + return new VolumeMuteIcon(); }) ); diff --git a/libs/web/shell/ui/user-dropdown/src/lib/user-dropdown.component.ts b/libs/web/shell/ui/user-dropdown/src/lib/user-dropdown.component.ts index da341528..b1b9daed 100644 --- a/libs/web/shell/ui/user-dropdown/src/lib/user-dropdown.component.ts +++ b/libs/web/shell/ui/user-dropdown/src/lib/user-dropdown.component.ts @@ -11,7 +11,6 @@ import { UserDropdownStore } from './user-dropdown.store'; export class UserDropdownComponent { userName$ = this.store.userName$; userAvatar$ = this.store.userAvatar$; - constructor(private store: UserDropdownStore) { - - } + + constructor(private store: UserDropdownStore) {} } diff --git a/libs/web/visualizer/feature/src/lib/visualizer.component.ts b/libs/web/visualizer/feature/src/lib/visualizer.component.ts index d91bf1f2..fcd3f43f 100644 --- a/libs/web/visualizer/feature/src/lib/visualizer.component.ts +++ b/libs/web/visualizer/feature/src/lib/visualizer.component.ts @@ -1,9 +1,11 @@ import { PlaybackStore } from '@angular-spotify/web/shared/data-access/store'; import { AudioAnalyser, initVisualizer } from '@angular-spotify/web/visualizer/data-access'; +import { DOCUMENT } from '@angular/common'; import { ChangeDetectionStrategy, Component, ElementRef, + Inject, OnDestroy, OnInit, ViewChild @@ -11,10 +13,11 @@ import { import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { mean } from 'lodash-es'; import { timer } from 'rxjs'; -import { map, switchMap } from 'rxjs/operators'; +import { map, switchMap, tap } from 'rxjs/operators'; import { Sketch } from 'sketch-js'; const INTERVAL = 100; + @UntilDestroy() @Component({ selector: 'as-visualizer', @@ -29,7 +32,10 @@ export class VisualizerComponent implements OnInit, OnDestroy { @ViewChild('visualizer', { static: true }) visualizer!: ElementRef; - constructor(private playbackStore: PlaybackStore) {} + constructor( + private playbackStore: PlaybackStore, + @Inject(DOCUMENT) private readonly document: Document + ) {} ngOnInit(): void { const { sketch, analyser } = initVisualizer(this.visualizer.nativeElement); @@ -49,7 +55,7 @@ export class VisualizerComponent implements OnInit, OnDestroy { })) ) ), - map(({ num, data }) => { + tap(({ num, data }) => { const { position, isPlaying, segments } = data; if (!isPlaying) { return; @@ -68,7 +74,7 @@ export class VisualizerComponent implements OnInit, OnDestroy { toggleFullscreen() { if (this.isFullscreen) { - document.exitFullscreen(); + this.document.exitFullscreen(); } else { (this.visualizer.nativeElement as HTMLElement).requestFullscreen(); }