From 5fec5557de4872d0d8aff79dd87d9b5b8c3e1eb0 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 21 Aug 2019 21:38:00 +0200 Subject: [PATCH 01/12] Add a list component that retrieves its own data from the service --- src/app/app.module.ts | 2 + .../virtual-scroll-list.component.html | 77 +++++++++++++++++++ .../virtual-scroll-list.component.scss | 52 +++++++++++++ .../virtual-scroll-list.component.spec.ts | 25 ++++++ .../virtual-scroll-list.component.ts | 49 ++++++++++++ src/app/datasources/paged-data-source.ts | 7 ++ src/app/datasources/track-data-source.ts | 39 ++++++++++ src/app/modules/material-import.module.ts | 2 + .../pages/tracks/tracks-page.component.html | 10 +-- src/app/pages/tracks/tracks-page.component.ts | 15 ++-- 10 files changed, 264 insertions(+), 14 deletions(-) create mode 100644 src/app/components/virtual-scroll-list/virtual-scroll-list.component.html create mode 100644 src/app/components/virtual-scroll-list/virtual-scroll-list.component.scss create mode 100644 src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts create mode 100644 src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts create mode 100644 src/app/datasources/paged-data-source.ts create mode 100644 src/app/datasources/track-data-source.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 07d190d..38cbc11 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -48,6 +48,7 @@ import {AlbumState} from './store/states/album.state'; import { AlbumSaveButtonComponent } from './components/album-save-button/album-save-button.component'; import { AlbumDetailPageComponent } from './pages/album-detail-page/album-detail-page.component'; import { ArtistNamesComponent } from './components/artist-names/artist-names.component'; +import { VirtualScrollListComponent } from './components/virtual-scroll-list/virtual-scroll-list.component'; const spotifyConfig = { clientId: environment.clientId, @@ -114,6 +115,7 @@ export function serialize(value: any) { AlbumSaveButtonComponent, AlbumDetailPageComponent, ArtistNamesComponent, + VirtualScrollListComponent, ], imports: [ BrowserModule, diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html new file mode 100644 index 0000000..3e69120 --- /dev/null +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html @@ -0,0 +1,77 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Popularity + + Album + {{element.album.name}} + Artist + + {{artist.name}} + , + + + timer + {{element.duration_ms | minutesSeconds}} + + + + + +
+
+ + diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.scss b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.scss new file mode 100644 index 0000000..a44f6e5 --- /dev/null +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.scss @@ -0,0 +1,52 @@ +:host { + display: flex; + flex-direction: column; + height: 100%; +} + +.playing { + background: rgba(255, 255, 255, 0.13); +} + +.list-container { + flex: 1; + overflow: auto; + + border-bottom: 1px rgba(255,255,255,.12) solid; + box-sizing: content-box; +} + +.table { + width: 100%; + + tr { + height: 32px; + } + + td { + &.mat-column-image, + &.mat-column-album-image { + width: 32px; + } + + &.mat-column-popularity { + .progress-bar { + width: 100%; + } + } + + &.mat-column-track-saved, + &.mat-column-artist-saved, + &.mat-column-duration, + &.mat-column-popularity, + &.mat-column-album-saved { + width: 40px; + } + } + + img { + height: 32px; + width: auto; + display: block; + } +} diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts new file mode 100644 index 0000000..8f6d5ca --- /dev/null +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { VirtualScrollListComponent } from './virtual-scroll-list.component'; + +describe('VirtualScrollListComponent', () => { + let component: VirtualScrollListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ VirtualScrollListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(VirtualScrollListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts new file mode 100644 index 0000000..d830a78 --- /dev/null +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts @@ -0,0 +1,49 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {SpotifyEntityModel} from '../../store/models/spotify-entity.model'; +import {DataSource} from '@angular/cdk/table'; +import {PagedDataSource} from '../../datasources/paged-data-source'; + +@Component({ + selector: 'app-virtual-scroll-list', + templateUrl: './virtual-scroll-list.component.html', + styleUrls: ['./virtual-scroll-list.component.scss'] +}) +export class VirtualScrollListComponent implements OnInit { + /** + * The dataSource this list subscribes to + */ + @Input() dataSource: PagedDataSource; + + /** + * The displayed colums. + * Columns that can be used: + * - image + * - album-image + * - name + * - popularity + * - album + * - artist + * - duration + * - saved + */ + @Input() public columns: string[] = ['name']; + + /** + * Emits an event containing the row object. + */ + @Output() public rowDoubleClick = new EventEmitter(); + + public ngOnInit(): void { + this.dataSource.openPage(0); + console.log('Opened page 0'); + } + + public onPageChange(event): void { + console.log(event); + this.dataSource.openPage(event.pageIndex); + } + + public trackBy(index, item) { + return item.id; + } +} diff --git a/src/app/datasources/paged-data-source.ts b/src/app/datasources/paged-data-source.ts new file mode 100644 index 0000000..338152b --- /dev/null +++ b/src/app/datasources/paged-data-source.ts @@ -0,0 +1,7 @@ +import {DataSource} from '@angular/cdk/table'; + +export abstract class PagedDataSource extends DataSource { + public total: number; + public pageSize: number; + abstract openPage(page): void; +} diff --git a/src/app/datasources/track-data-source.ts b/src/app/datasources/track-data-source.ts new file mode 100644 index 0000000..f50c14c --- /dev/null +++ b/src/app/datasources/track-data-source.ts @@ -0,0 +1,39 @@ +import {TrackModel} from '../store/models/track.model'; +import {CollectionViewer} from '@angular/cdk/collections'; +import {BehaviorSubject, Observable} from 'rxjs'; +import {TrackSpotifyService} from '../store/providers/track-spotify.service'; +import {PagedDataSource} from './paged-data-source'; + +export class TrackDataSource extends PagedDataSource { + private tracks = []; + + private subject = new BehaviorSubject(this.tracks); + private observable = this.subject.asObservable(); + + constructor( + private trackService: TrackSpotifyService, + private ids: string[], + public pageSize: number, + ) { + super(); + this.total = ids.length; + } + + connect(collectionViewer: CollectionViewer): Observable> { + return this.observable; + } + + disconnect(collectionViewer: CollectionViewer): void { + this.subject.complete(); + } + + public openPage(page): void { + const start = page * this.pageSize; + const end = start + this.pageSize; + const pageIds = this.ids.slice(start, end); + this.trackService.getTracks(pageIds, this.pageSize).subscribe((value: any) => { + this.tracks = value.tracks; + this.subject.next(this.tracks); + }); + } +} diff --git a/src/app/modules/material-import.module.ts b/src/app/modules/material-import.module.ts index 96945b6..fa2e742 100644 --- a/src/app/modules/material-import.module.ts +++ b/src/app/modules/material-import.module.ts @@ -13,6 +13,7 @@ import { MatTooltipModule } from '@angular/material'; import {FormsModule} from '@angular/forms'; +import {ScrollingModule} from '@angular/cdk/scrolling'; const modules = [ CommonModule, @@ -29,6 +30,7 @@ const modules = [ FormsModule, MatSliderModule, MatTabsModule, + ScrollingModule, ]; @NgModule({ diff --git a/src/app/pages/tracks/tracks-page.component.html b/src/app/pages/tracks/tracks-page.component.html index f439dbf..bcd6596 100644 --- a/src/app/pages/tracks/tracks-page.component.html +++ b/src/app/pages/tracks/tracks-page.component.html @@ -1,9 +1,5 @@ - +> diff --git a/src/app/pages/tracks/tracks-page.component.ts b/src/app/pages/tracks/tracks-page.component.ts index ee5f2d1..3564b63 100644 --- a/src/app/pages/tracks/tracks-page.component.ts +++ b/src/app/pages/tracks/tracks-page.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; import {Store} from '@ngxs/store'; -import {GetTracks} from '../../store/actions/track.actions'; -import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; import {TrackModel} from '../../store/models/track.model'; import {PlayTrack} from '../../store/actions/player.actions'; import {TrackState} from '../../store/states/track.state'; +import {TrackDataSource} from '../../datasources/track-data-source'; +import {TrackSpotifyService} from '../../store/providers/track-spotify.service'; @Component({ selector: 'app-tracks-page', @@ -15,19 +15,20 @@ export class TracksPageComponent implements OnInit { public ids: string[]; public pageSize = 50; public selector = TrackState.tracks; + public dataSource: TrackDataSource; - constructor(private store: Store) {} + constructor( + private store: Store, + private trackService: TrackSpotifyService, + ) {} public ngOnInit(): void { this.store.select(state => state.tracks.ids).subscribe((value) => { this.ids = value; + this.dataSource = new TrackDataSource(this.trackService, this.ids, this.pageSize); }); } - public onLoadRequest(event: LoadRequestEvent): void { - this.store.dispatch(new GetTracks(this.ids, event.page, event.pageSize)); - } - public onRowDoubleClick(event: TrackModel): void { this.store.dispatch(new PlayTrack(this.ids, event.id)); } From 01dfb2f882e047fc120983e6f3cf8b91b83217ea Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 00:40:44 +0200 Subject: [PATCH 02/12] Search using DataSources --- .../virtual-scroll-list.component.ts | 2 - src/app/datasources/search-data-source.ts | 38 ++++++++++ src/app/datasources/track-data-source.ts | 2 +- .../pages/search/search-page.component.html | 48 ++++-------- src/app/pages/search/search-page.component.ts | 75 ++++--------------- src/app/pages/tracks/tracks-page.component.ts | 10 ++- .../store/providers/search-spotify.service.ts | 5 +- 7 files changed, 81 insertions(+), 99 deletions(-) create mode 100644 src/app/datasources/search-data-source.ts diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts index d830a78..c76f797 100644 --- a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts @@ -35,11 +35,9 @@ export class VirtualScrollListComponent implements OnInit { public ngOnInit(): void { this.dataSource.openPage(0); - console.log('Opened page 0'); } public onPageChange(event): void { - console.log(event); this.dataSource.openPage(event.pageIndex); } diff --git a/src/app/datasources/search-data-source.ts b/src/app/datasources/search-data-source.ts new file mode 100644 index 0000000..e02a12d --- /dev/null +++ b/src/app/datasources/search-data-source.ts @@ -0,0 +1,38 @@ +import {PagedDataSource} from './paged-data-source'; +import {TrackModel} from '../store/models/track.model'; +import {BehaviorSubject, Observable} from 'rxjs'; +import {CollectionViewer} from '@angular/cdk/collections'; +import {SearchSpotifyService} from '../store/providers/search-spotify.service'; + +export class SearchDataSource extends PagedDataSource { + public entities = []; + + private subject = new BehaviorSubject(this.entities); + private observable = this.subject.asObservable(); + + constructor( + private searchService: SearchSpotifyService, + public query: string, + public pageSize: number, + public type: string, + ) { + super(); + this.total = 0; + } + + connect(collectionViewer: CollectionViewer): Observable> { + return this.observable; + } + + disconnect(collectionViewer: CollectionViewer): void { + this.subject.complete(); + } + + openPage(page): void { + this.searchService.search(this.query, this.pageSize, page, [this.type]).subscribe((value: any) => { + this.entities = value[this.type + 's'].items; + this.total = value[this.type + 's'].total; + this.subject.next(this.entities); + }); + } +} diff --git a/src/app/datasources/track-data-source.ts b/src/app/datasources/track-data-source.ts index f50c14c..a668f7e 100644 --- a/src/app/datasources/track-data-source.ts +++ b/src/app/datasources/track-data-source.ts @@ -16,7 +16,7 @@ export class TrackDataSource extends PagedDataSource { public pageSize: number, ) { super(); - this.total = ids.length; + this.total = ids.length > 0 ? ids.length : 0; } connect(collectionViewer: CollectionViewer): Observable> { diff --git a/src/app/pages/search/search-page.component.html b/src/app/pages/search/search-page.component.html index 3920c7f..95ee1b0 100644 --- a/src/app/pages/search/search-page.component.html +++ b/src/app/pages/search/search-page.component.html @@ -1,53 +1,37 @@ - - + + > - - + + > - - + + > - - + + > diff --git a/src/app/pages/search/search-page.component.ts b/src/app/pages/search/search-page.component.ts index 7412f41..742eb1e 100644 --- a/src/app/pages/search/search-page.component.ts +++ b/src/app/pages/search/search-page.component.ts @@ -1,10 +1,9 @@ -import {Component, OnInit} from '@angular/core'; +import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {Store} from '@ngxs/store'; -import {Search} from '../../store/actions/search.actions'; -import {SearchState} from '../../store/states/search.state'; -import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; import {PlayTrack} from '../../store/actions/player.actions'; +import {SearchSpotifyService} from '../../store/providers/search-spotify.service'; +import {SearchDataSource} from '../../datasources/search-data-source'; @Component({ selector: 'app-search-page', @@ -12,75 +11,33 @@ import {PlayTrack} from '../../store/actions/player.actions'; styleUrls: ['./search-page.component.scss'] }) export class SearchPageComponent implements OnInit { - public trackIds: string[]; - public trackTotal: number; - public tracksSelector = SearchState.tracks; - - public artistIds: string[]; - public artistTotal: number; - public artistSelector = SearchState.artists; - - public albumIds: string[]; - public albumTotal: number; - public albumSelector = SearchState.albums; - - public playlistIds: string[]; - public playlistTotal: number; - public playlistSelector = SearchState.playlists; + @Input() public trackDataSource: SearchDataSource; + @Input() public artistDataSource: SearchDataSource; + @Input() public albumDataSource: SearchDataSource; + @Input() public playlistDataSource: SearchDataSource; public pageSize = 50; - private query: string; - constructor( private route: ActivatedRoute, private store: Store, private router: Router, - ) { - } + private searchService: SearchSpotifyService, + private changeDetector: ChangeDetectorRef, + ) {} ngOnInit() { this.route.queryParams.subscribe((value) => { - this.query = value.query; - this.store.dispatch(new Search(this.query, this.pageSize, 0, [ - 'album', - 'artist', - 'track', - 'playlist', - ])); - }); - - this.store.select(state => state.search.results).subscribe((value) => { - if (value) { - if (value.tracks) { - this.trackIds = value.tracks.items.map(x => x.id); - this.trackTotal = value.tracks.total; - } - - if (value.artists) { - this.artistIds = value.artists.items.map(x => x.id); - this.artistTotal = value.artists.total; - } - - if (value.albums) { - this.albumIds = value.albums.items.map(x => x.id); - this.albumTotal = value.albums.total; - } - - if (value.playlists) { - this.playlistIds = value.playlists.items.map(x => x.id); - this.playlistTotal = value.playlists.total; - } - } + this.trackDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'track'); + this.artistDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'artist'); + this.albumDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'album'); + this.playlistDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'playlist'); + this.changeDetector.detectChanges(); }); } - public onLoadRequest(event: LoadRequestEvent, type: string) { - this.store.dispatch(new Search(this.query, event.pageSize, event.page, [type])); - } - public onTrackDoubleClick(event) { - this.store.dispatch(new PlayTrack(this.trackIds, event.id)); + this.store.dispatch(new PlayTrack(this.trackDataSource.entities.map(x => x.id), event.id)); } public onArtistDoubleClick(event) { diff --git a/src/app/pages/tracks/tracks-page.component.ts b/src/app/pages/tracks/tracks-page.component.ts index 3564b63..56e7f40 100644 --- a/src/app/pages/tracks/tracks-page.component.ts +++ b/src/app/pages/tracks/tracks-page.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit} from '@angular/core'; import {Store} from '@ngxs/store'; import {TrackModel} from '../../store/models/track.model'; import {PlayTrack} from '../../store/actions/player.actions'; @@ -9,7 +9,8 @@ import {TrackSpotifyService} from '../../store/providers/track-spotify.service'; @Component({ selector: 'app-tracks-page', templateUrl: './tracks-page.component.html', - styleUrls: ['./tracks-page.component.scss'] + styleUrls: ['./tracks-page.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class TracksPageComponent implements OnInit { public ids: string[]; @@ -20,12 +21,15 @@ export class TracksPageComponent implements OnInit { constructor( private store: Store, private trackService: TrackSpotifyService, + private changeDetector: ChangeDetectorRef, ) {} public ngOnInit(): void { this.store.select(state => state.tracks.ids).subscribe((value) => { - this.ids = value; + this.ids = value ? value : []; + console.log(this.ids); this.dataSource = new TrackDataSource(this.trackService, this.ids, this.pageSize); + this.changeDetector.detectChanges(); }); } diff --git a/src/app/store/providers/search-spotify.service.ts b/src/app/store/providers/search-spotify.service.ts index 7524c4f..97d84de 100644 --- a/src/app/store/providers/search-spotify.service.ts +++ b/src/app/store/providers/search-spotify.service.ts @@ -12,7 +12,8 @@ export class SearchSpotifyService { private http: HttpClient ) { } - search(query: string, limit: number, offset: number, type: string[]): Observable { - return this.http.get(`${this.config.apiBase}/search?q=${query}&type=${type}&market=from_token&limit=${limit}&offset=${offset}`); + search(query: string, pageSize: number, page: number, type: string[]): Observable { + const offset = page * pageSize; + return this.http.get(`${this.config.apiBase}/search?q=${query}&type=${type}&market=from_token&limit=${pageSize}&offset=${offset}`); } } From 746481084187710cfcd1f7b198e4063b81843050 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 00:44:05 +0200 Subject: [PATCH 03/12] Fix list component changedetection --- .../virtual-scroll-list/virtual-scroll-list.component.ts | 8 ++++++-- src/app/pages/search/search-page.component.ts | 2 -- src/app/pages/tracks/tracks-page.component.ts | 3 --- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts index c76f797..4b0d8a9 100644 --- a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {Component, EventEmitter, Input, OnChanges, OnInit, Output} from '@angular/core'; import {SpotifyEntityModel} from '../../store/models/spotify-entity.model'; import {DataSource} from '@angular/cdk/table'; import {PagedDataSource} from '../../datasources/paged-data-source'; @@ -8,7 +8,7 @@ import {PagedDataSource} from '../../datasources/paged-data-source'; templateUrl: './virtual-scroll-list.component.html', styleUrls: ['./virtual-scroll-list.component.scss'] }) -export class VirtualScrollListComponent implements OnInit { +export class VirtualScrollListComponent implements OnInit, OnChanges { /** * The dataSource this list subscribes to */ @@ -37,6 +37,10 @@ export class VirtualScrollListComponent implements OnInit { this.dataSource.openPage(0); } + public ngOnChanges(): void { + this.dataSource.openPage(0); + } + public onPageChange(event): void { this.dataSource.openPage(event.pageIndex); } diff --git a/src/app/pages/search/search-page.component.ts b/src/app/pages/search/search-page.component.ts index 742eb1e..e68fe12 100644 --- a/src/app/pages/search/search-page.component.ts +++ b/src/app/pages/search/search-page.component.ts @@ -23,7 +23,6 @@ export class SearchPageComponent implements OnInit { private store: Store, private router: Router, private searchService: SearchSpotifyService, - private changeDetector: ChangeDetectorRef, ) {} ngOnInit() { @@ -32,7 +31,6 @@ export class SearchPageComponent implements OnInit { this.artistDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'artist'); this.albumDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'album'); this.playlistDataSource = new SearchDataSource(this.searchService, value.query, this.pageSize, 'playlist'); - this.changeDetector.detectChanges(); }); } diff --git a/src/app/pages/tracks/tracks-page.component.ts b/src/app/pages/tracks/tracks-page.component.ts index 56e7f40..b681079 100644 --- a/src/app/pages/tracks/tracks-page.component.ts +++ b/src/app/pages/tracks/tracks-page.component.ts @@ -21,15 +21,12 @@ export class TracksPageComponent implements OnInit { constructor( private store: Store, private trackService: TrackSpotifyService, - private changeDetector: ChangeDetectorRef, ) {} public ngOnInit(): void { this.store.select(state => state.tracks.ids).subscribe((value) => { this.ids = value ? value : []; - console.log(this.ids); this.dataSource = new TrackDataSource(this.trackService, this.ids, this.pageSize); - this.changeDetector.detectChanges(); }); } From d78de35f59760d8e56cd2a2a61ea580d5151d402 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:13:07 +0200 Subject: [PATCH 04/12] Add NestedEntityDataSource for displaying a list property from an entity --- ...k-data-source.ts => entity-data-source.ts} | 20 +++++---- .../datasources/nested-entity-data-source.ts | 39 +++++++++++++++++ .../pages/album-page/albums-page.component.ts | 2 +- .../artist-detail-page.component.html | 11 ++--- .../artist-detail-page.component.ts | 42 +++++++------------ src/app/pages/tracks/tracks-page.component.ts | 18 ++++---- .../store/providers/album-spotify.service.ts | 6 ++- .../store/providers/artist-spotify.service.ts | 5 ++- .../providers/spotify-entity.service.spec.ts | 12 ++++++ .../store/providers/spotify-entity.service.ts | 31 ++++++++++++++ src/app/store/states/album.state.ts | 2 +- src/app/store/states/artist.state.ts | 2 +- src/app/themes/dark-theme.scss | 1 + src/app/themes/scrollbar-theme.scss | 26 ++++++++++++ src/styles.scss | 20 --------- 15 files changed, 159 insertions(+), 78 deletions(-) rename src/app/datasources/{track-data-source.ts => entity-data-source.ts} (55%) create mode 100644 src/app/datasources/nested-entity-data-source.ts create mode 100644 src/app/store/providers/spotify-entity.service.spec.ts create mode 100644 src/app/store/providers/spotify-entity.service.ts create mode 100644 src/app/themes/scrollbar-theme.scss diff --git a/src/app/datasources/track-data-source.ts b/src/app/datasources/entity-data-source.ts similarity index 55% rename from src/app/datasources/track-data-source.ts rename to src/app/datasources/entity-data-source.ts index a668f7e..80d1504 100644 --- a/src/app/datasources/track-data-source.ts +++ b/src/app/datasources/entity-data-source.ts @@ -1,25 +1,27 @@ import {TrackModel} from '../store/models/track.model'; import {CollectionViewer} from '@angular/cdk/collections'; import {BehaviorSubject, Observable} from 'rxjs'; -import {TrackSpotifyService} from '../store/providers/track-spotify.service'; import {PagedDataSource} from './paged-data-source'; +import {SpotifyEntityModel} from '../store/models/spotify-entity.model'; +import {SpotifyEntityService} from '../store/providers/spotify-entity.service'; -export class TrackDataSource extends PagedDataSource { - private tracks = []; +export class EntityDataSource extends PagedDataSource { + private entities = []; - private subject = new BehaviorSubject(this.tracks); + private subject = new BehaviorSubject(this.entities); private observable = this.subject.asObservable(); constructor( - private trackService: TrackSpotifyService, + private entityService: SpotifyEntityService, private ids: string[], + public type: string, public pageSize: number, ) { super(); this.total = ids.length > 0 ? ids.length : 0; } - connect(collectionViewer: CollectionViewer): Observable> { + connect(collectionViewer: CollectionViewer): Observable> { return this.observable; } @@ -31,9 +33,9 @@ export class TrackDataSource extends PagedDataSource { const start = page * this.pageSize; const end = start + this.pageSize; const pageIds = this.ids.slice(start, end); - this.trackService.getTracks(pageIds, this.pageSize).subscribe((value: any) => { - this.tracks = value.tracks; - this.subject.next(this.tracks); + this.entityService.getEntities(pageIds, this.type, this.pageSize).subscribe((value: any) => { + this.entities = value[this.type + 's']; + this.subject.next(this.entities); }); } } diff --git a/src/app/datasources/nested-entity-data-source.ts b/src/app/datasources/nested-entity-data-source.ts new file mode 100644 index 0000000..de43bf8 --- /dev/null +++ b/src/app/datasources/nested-entity-data-source.ts @@ -0,0 +1,39 @@ +import {BehaviorSubject, Observable} from 'rxjs'; +import {SpotifyEntityModel} from '../store/models/spotify-entity.model'; +import {SpotifyEntityService} from '../store/providers/spotify-entity.service'; +import {PagedDataSource} from './paged-data-source'; +import {CollectionViewer} from '@angular/cdk/collections'; +import {TrackModel} from '../store/models/track.model'; + +export class NestedEntityDataSource extends PagedDataSource { + private entities = []; + + private subject = new BehaviorSubject(this.entities); + private observable = this.subject.asObservable(); + + constructor( + private entityService: SpotifyEntityService, + private id: string, + private parentType: string, + public type: string, + public pageSize: number, + ) { + super(); + } + + connect(collectionViewer: CollectionViewer): Observable> { + return this.observable; + } + + disconnect(collectionViewer: CollectionViewer): void { + this.subject.complete(); + } + + public openPage(page): void { + this.entityService.getNestedEntities(this.id, this.parentType, this.type, page, this.pageSize).subscribe((value: any) => { + this.entities = value.items; + this.total = value.total; + this.subject.next(this.entities); + }); + } +} diff --git a/src/app/pages/album-page/albums-page.component.ts b/src/app/pages/album-page/albums-page.component.ts index 7dc46ef..23f9c31 100644 --- a/src/app/pages/album-page/albums-page.component.ts +++ b/src/app/pages/album-page/albums-page.component.ts @@ -13,7 +13,7 @@ import {AlbumModel} from '../../store/models/album.model'; }) export class AlbumsPageComponent implements OnInit { public ids: string[]; - public pageSize = 50; + public pageSize = 20; public selector = AlbumState.albums; constructor( diff --git a/src/app/pages/artist-detail/artist-detail-page.component.html b/src/app/pages/artist-detail/artist-detail-page.component.html index dddf18f..909d4ec 100644 --- a/src/app/pages/artist-detail/artist-detail-page.component.html +++ b/src/app/pages/artist-detail/artist-detail-page.component.html @@ -20,16 +20,13 @@

{{artist.name}}

Albums

- + >
diff --git a/src/app/pages/artist-detail/artist-detail-page.component.ts b/src/app/pages/artist-detail/artist-detail-page.component.ts index fd7b968..53ebf1a 100644 --- a/src/app/pages/artist-detail/artist-detail-page.component.ts +++ b/src/app/pages/artist-detail/artist-detail-page.component.ts @@ -1,14 +1,11 @@ import { Component, OnInit } from '@angular/core'; import {Store} from '@ngxs/store'; import {ActivatedRoute, Router} from '@angular/router'; -import {GetArtist, GetArtistAlbums} from '../../store/actions/artist.actions'; import {ArtistModel} from '../../store/models/artist.model'; -import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; -import {PlayTrack} from '../../store/actions/player.actions'; import {AlbumModel} from '../../store/models/album.model'; -import {AlbumState} from '../../store/states/album.state'; -import {GetAlbums} from '../../store/actions/album.actions'; -import {ArtistState} from '../../store/states/artist.state'; +import {EntityDataSource} from '../../datasources/entity-data-source'; +import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; +import {NestedEntityDataSource} from '../../datasources/nested-entity-data-source'; @Component({ selector: 'app-artist-detail-page', @@ -17,38 +14,31 @@ import {ArtistState} from '../../store/states/artist.state'; }) export class ArtistDetailPageComponent implements OnInit { public artist: ArtistModel; - public albumIds: string[]; - public albumsSelector = AlbumState.albums; - public pageSize = 50; - public total: number; + + public albumDataSource: NestedEntityDataSource; + public pageSize = 20; constructor( private store: Store, private route: ActivatedRoute, private router: Router, + private entityService: SpotifyEntityService, ) {} ngOnInit() { - this.route.params.subscribe((value) => { - this.store.dispatch(new GetArtist(value.id)); - this.store.dispatch(new GetArtistAlbums(value.id, 0, this.pageSize)); - }); - - this.store.select(ArtistState.currentArtist).subscribe((value: ArtistModel) => { - this.artist = value ? value : this.artist; - if (this.artist && this.artist.albums) { - this.albumIds = this.artist.albums.map(x => x.id); - this.total = this.artist.totalAlbums; - this.onLoadRequest({page: 0, pageSize: this.pageSize}); - } + this.route.params.subscribe((params) => { + this.loadEntities(params.id); }); } - onLoadRequest(event: LoadRequestEvent) { - this.store.dispatch(new GetAlbums(this.albumIds, event.page, event.pageSize)); + public onRowDoubleClick(event: AlbumModel) { + this.router.navigate(['album', event.id]); } - onRowDoubleClick(event: AlbumModel) { - this.router.navigate(['album', event.id]); + private loadEntities(id) { + this.entityService.getEntity(id, 'artist').subscribe((artist: ArtistModel) => { + this.artist = artist; + this.albumDataSource = new NestedEntityDataSource(this.entityService, id, 'artist', 'album', this.pageSize); + }); } } diff --git a/src/app/pages/tracks/tracks-page.component.ts b/src/app/pages/tracks/tracks-page.component.ts index b681079..36d7804 100644 --- a/src/app/pages/tracks/tracks-page.component.ts +++ b/src/app/pages/tracks/tracks-page.component.ts @@ -1,32 +1,32 @@ -import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit} from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {Store} from '@ngxs/store'; import {TrackModel} from '../../store/models/track.model'; import {PlayTrack} from '../../store/actions/player.actions'; import {TrackState} from '../../store/states/track.state'; -import {TrackDataSource} from '../../datasources/track-data-source'; -import {TrackSpotifyService} from '../../store/providers/track-spotify.service'; +import {EntityDataSource} from '../../datasources/entity-data-source'; +import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; @Component({ selector: 'app-tracks-page', templateUrl: './tracks-page.component.html', - styleUrls: ['./tracks-page.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush + styleUrls: ['./tracks-page.component.scss'] }) export class TracksPageComponent implements OnInit { public ids: string[]; public pageSize = 50; public selector = TrackState.tracks; - public dataSource: TrackDataSource; + public dataSource: EntityDataSource; constructor( private store: Store, - private trackService: TrackSpotifyService, + private entityService: SpotifyEntityService, ) {} public ngOnInit(): void { this.store.select(state => state.tracks.ids).subscribe((value) => { - this.ids = value ? value : []; - this.dataSource = new TrackDataSource(this.trackService, this.ids, this.pageSize); + if (value) { + this.dataSource = new EntityDataSource(this.entityService, value, 'track', this.pageSize); + } }); } diff --git a/src/app/store/providers/album-spotify.service.ts b/src/app/store/providers/album-spotify.service.ts index ec79f85..bbb5ef9 100644 --- a/src/app/store/providers/album-spotify.service.ts +++ b/src/app/store/providers/album-spotify.service.ts @@ -11,8 +11,10 @@ export class AlbumSpotifyService { private http: HttpClient ) { } - getAlbums(ids: string[]) { - return this.http.get(`${this.config.apiBase}/albums?ids=${ids}`); + getAlbums(ids: string[], pageSize: number) { + const albums = ids.slice(0, Math.min(pageSize, ids.length)).join(); + console.log(albums); + return this.http.get(`${this.config.apiBase}/albums?ids=${albums}`); } getAlbum(id: string) { diff --git a/src/app/store/providers/artist-spotify.service.ts b/src/app/store/providers/artist-spotify.service.ts index 8cd7bf8..5068d13 100644 --- a/src/app/store/providers/artist-spotify.service.ts +++ b/src/app/store/providers/artist-spotify.service.ts @@ -15,8 +15,9 @@ export class ArtistSpotifyService { return this.http.get(`${this.config.apiBase}/artists/${id}`); } - getArtists(ids: string[]) { - return this.http.get(`${this.config.apiBase}/artists?ids=${ids}`); + getArtists(ids: string[], pageSize: number) { + const artists = ids.slice(0, Math.min(pageSize, ids.length)).join(); + return this.http.get(`${this.config.apiBase}/artists?ids=${artists}`); } getArtistAlbums(id: string, page: number, pageSize: number) { diff --git a/src/app/store/providers/spotify-entity.service.spec.ts b/src/app/store/providers/spotify-entity.service.spec.ts new file mode 100644 index 0000000..1352041 --- /dev/null +++ b/src/app/store/providers/spotify-entity.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { SpotifyEntityService } from './spotify-entity.service'; + +describe('SpotifyEntityService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: SpotifyEntityService = TestBed.get(SpotifyEntityService); + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/store/providers/spotify-entity.service.ts b/src/app/store/providers/spotify-entity.service.ts new file mode 100644 index 0000000..0c88c0e --- /dev/null +++ b/src/app/store/providers/spotify-entity.service.ts @@ -0,0 +1,31 @@ +import {Inject, Injectable} from '@angular/core'; +import {SpotifyConfig} from '../../definitions/spotify-config'; +import {HttpClient} from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class SpotifyEntityService { + constructor( + @Inject('SpotifyConfig') private config: SpotifyConfig, + private http: HttpClient, + ) { } + + public getEntity(id: string, type: string) { + return this.http.get(`${this.config.apiBase}/${type}s/${id}?market=from_token`); + } + + public getEntities(ids: string[], type: string, pageSize: number) { + const entities = this.getFirstPage(ids, pageSize); + return this.http.get(`${this.config.apiBase}/${type}s?ids=${entities}&market=from_token`); + } + + public getNestedEntities(id: string, parentType: string, type: string, page: number, pageSize: number) { + const offset = page * pageSize; + return this.http.get(`${this.config.apiBase}/${parentType}s/${id}/${type}s?limit=${pageSize}&offset=${offset}&market=from_token`); + } + + private getFirstPage(ids: string[], pageSize: number) { + return ids.slice(0, Math.min(pageSize, ids.length)).join(); + } +} diff --git a/src/app/store/states/album.state.ts b/src/app/store/states/album.state.ts index ddbdf49..50c2fc9 100644 --- a/src/app/store/states/album.state.ts +++ b/src/app/store/states/album.state.ts @@ -35,7 +35,7 @@ export class AlbumState { const start = action.page * action.pageSize; const end = start + action.pageSize; const pageIds = action.ids.slice(start, end); - this.albumService.getAlbums(pageIds).subscribe((value: any) => { + this.albumService.getAlbums(pageIds, action.pageSize).subscribe((value: any) => { ctx.dispatch(new GetAlbumsSuccess(value.albums)); }); } diff --git a/src/app/store/states/artist.state.ts b/src/app/store/states/artist.state.ts index 7fb74e1..9da3149 100644 --- a/src/app/store/states/artist.state.ts +++ b/src/app/store/states/artist.state.ts @@ -47,7 +47,7 @@ export class ArtistState { const start = action.page * action.pageSize; const end = start + action.pageSize; const pageIds = action.ids.slice(start, end); - this.artistService.getArtists(pageIds).subscribe((value: any) => { + this.artistService.getArtists(pageIds, action.pageSize).subscribe((value: any) => { ctx.dispatch(new GetArtistsSuccess(value.artists)); }); } diff --git a/src/app/themes/dark-theme.scss b/src/app/themes/dark-theme.scss index 4ca32c3..a3708c0 100644 --- a/src/app/themes/dark-theme.scss +++ b/src/app/themes/dark-theme.scss @@ -19,6 +19,7 @@ $config: mat-typography-config(); @import "./artist-detail-theme"; @import "./app-theme"; @import "./link-theme"; +@import "./scrollbar-theme"; @import "./mat-table-theme"; @import "./mat-card-theme"; diff --git a/src/app/themes/scrollbar-theme.scss b/src/app/themes/scrollbar-theme.scss new file mode 100644 index 0000000..8131df4 --- /dev/null +++ b/src/app/themes/scrollbar-theme.scss @@ -0,0 +1,26 @@ +@mixin scrollbar-theme($theme) { + $background: map-get($theme, background); + + ::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px 0 mat-color($background, app-bar); + -moz-box-shadow: inset 0 0 6px 0 mat-color($background, app-bar); + box-shadow: inset 0 0 6px 0 mat-color($background, app-bar); + border-radius: 3px; + background: none; + } + + ::-webkit-scrollbar { + width: 6px; + background-color: mat-color($background, app-bar); + } + + ::-webkit-scrollbar-thumb { + -webkit-box-shadow: inset 0 0 6px 0 mat-color($background, card); + -moz-box-shadow: inset 0 0 6px 0 mat-color($background, card); + box-shadow: inset 0 0 6px 0 mat-color($background, card); + border-radius: 10px; + background: mat-color($background, card); + } +} + +@include scrollbar-theme($f10k-dark); diff --git a/src/styles.scss b/src/styles.scss index 9b40035..9a250f0 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -6,26 +6,6 @@ body { width: 100vw; } -::-webkit-scrollbar-track -{ - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - border-radius: 3px; - background: none; -} - -::-webkit-scrollbar -{ - width: 6px; - background-color: grey; -} - -::-webkit-scrollbar-thumb -{ - border-radius: 10px; - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); - background: #424242; -} - .disable-select { user-select: none; /* supported by Chrome and Opera */ -webkit-user-select: none; /* Safari */ From 9fecd18a4826e906357c5da9ee9fcfb7413d994f Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:18:42 +0200 Subject: [PATCH 05/12] Convert album page to new DataSource system --- .../pages/album-page/albums-page.component.html | 10 +++------- src/app/pages/album-page/albums-page.component.ts | 14 ++++++-------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/app/pages/album-page/albums-page.component.html b/src/app/pages/album-page/albums-page.component.html index 52e70d9..585e427 100644 --- a/src/app/pages/album-page/albums-page.component.html +++ b/src/app/pages/album-page/albums-page.component.html @@ -1,9 +1,5 @@ - +> diff --git a/src/app/pages/album-page/albums-page.component.ts b/src/app/pages/album-page/albums-page.component.ts index 23f9c31..12652c4 100644 --- a/src/app/pages/album-page/albums-page.component.ts +++ b/src/app/pages/album-page/albums-page.component.ts @@ -5,6 +5,8 @@ import {AlbumState} from '../../store/states/album.state'; import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; import {GetAlbums} from '../../store/actions/album.actions'; import {AlbumModel} from '../../store/models/album.model'; +import {EntityDataSource} from '../../datasources/entity-data-source'; +import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; @Component({ selector: 'app-albums-page', @@ -12,25 +14,21 @@ import {AlbumModel} from '../../store/models/album.model'; styleUrls: ['./albums-page.component.scss'] }) export class AlbumsPageComponent implements OnInit { - public ids: string[]; - public pageSize = 20; - public selector = AlbumState.albums; + public dataSource: EntityDataSource; + public pageSize = 50; constructor( private store: Store, private router: Router, + private entityService: SpotifyEntityService, ) {} public ngOnInit(): void { this.store.select(state => state.albums.ids).subscribe((value) => { - this.ids = value; + this.dataSource = new EntityDataSource(this.entityService, value, 'album', this.pageSize); }); } - public onLoadRequest(event: LoadRequestEvent): void { - this.store.dispatch(new GetAlbums(this.ids, event.page, event.pageSize)); - } - public onRowDoubleClick(event: AlbumModel): void { this.router.navigate(['album', event.id]); } From 8f0807dd88757deccb6eebac747c8ea17686a036 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:44:14 +0200 Subject: [PATCH 06/12] Convert album page to new DataSource system --- .../virtual-scroll-list.component.html | 2 +- .../virtual-scroll-list.component.ts | 14 ++++++-- src/app/datasources/entity-data-source.ts | 4 +++ .../datasources/nested-entity-data-source.ts | 4 +++ src/app/datasources/paged-data-source.ts | 1 + src/app/datasources/search-data-source.ts | 10 ++++-- .../album-detail-page.component.html | 11 +++--- .../album-detail-page.component.ts | 34 ++++++++----------- .../pages/album-page/albums-page.component.ts | 3 -- .../artist-detail-page.component.ts | 1 - .../pages/artists/artists-page.component.html | 10 ++---- .../pages/artists/artists-page.component.ts | 15 +++----- src/app/pages/search/search-page.component.ts | 2 +- src/app/pages/tracks/tracks-page.component.ts | 6 ++-- 14 files changed, 58 insertions(+), 59 deletions(-) diff --git a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html index 3e69120..0db6923 100644 --- a/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html @@ -69,7 +69,7 @@ - + (); + @Output() public rowDoubleClick = new EventEmitter<{ + id: string, + context: string[] + }>(); public ngOnInit(): void { this.dataSource.openPage(0); @@ -45,6 +48,13 @@ export class VirtualScrollListComponent implements OnInit, OnChanges { this.dataSource.openPage(event.pageIndex); } + public onRowClick(event: SpotifyEntityModel) { + this.rowDoubleClick.emit({ + id: event.id, + context: this.dataSource.getIds(), + }); + } + public trackBy(index, item) { return item.id; } diff --git a/src/app/datasources/entity-data-source.ts b/src/app/datasources/entity-data-source.ts index 80d1504..3692366 100644 --- a/src/app/datasources/entity-data-source.ts +++ b/src/app/datasources/entity-data-source.ts @@ -38,4 +38,8 @@ export class EntityDataSource extends PagedDataSource { this.subject.next(this.entities); }); } + + public getIds(): string[] { + return this.ids; + } } diff --git a/src/app/datasources/nested-entity-data-source.ts b/src/app/datasources/nested-entity-data-source.ts index de43bf8..b0ca90f 100644 --- a/src/app/datasources/nested-entity-data-source.ts +++ b/src/app/datasources/nested-entity-data-source.ts @@ -36,4 +36,8 @@ export class NestedEntityDataSource extends PagedDataSource this.subject.next(this.entities); }); } + + public getIds(): string[] { + return this.entities.map(x => x.id); + } } diff --git a/src/app/datasources/paged-data-source.ts b/src/app/datasources/paged-data-source.ts index 338152b..28caa41 100644 --- a/src/app/datasources/paged-data-source.ts +++ b/src/app/datasources/paged-data-source.ts @@ -4,4 +4,5 @@ export abstract class PagedDataSource extends DataSource { public total: number; public pageSize: number; abstract openPage(page): void; + abstract getIds(): string[]; } diff --git a/src/app/datasources/search-data-source.ts b/src/app/datasources/search-data-source.ts index e02a12d..319afb8 100644 --- a/src/app/datasources/search-data-source.ts +++ b/src/app/datasources/search-data-source.ts @@ -20,19 +20,23 @@ export class SearchDataSource extends PagedDataSource { this.total = 0; } - connect(collectionViewer: CollectionViewer): Observable> { + public connect(collectionViewer: CollectionViewer): Observable> { return this.observable; } - disconnect(collectionViewer: CollectionViewer): void { + public disconnect(collectionViewer: CollectionViewer): void { this.subject.complete(); } - openPage(page): void { + public openPage(page): void { this.searchService.search(this.query, this.pageSize, page, [this.type]).subscribe((value: any) => { this.entities = value[this.type + 's'].items; this.total = value[this.type + 's'].total; this.subject.next(this.entities); }); } + + public getIds(): string[] { + return this.entities.map(x => x.id); + } } diff --git a/src/app/pages/album-detail-page/album-detail-page.component.html b/src/app/pages/album-detail-page/album-detail-page.component.html index a2e6ca0..4b545b6 100644 --- a/src/app/pages/album-detail-page/album-detail-page.component.html +++ b/src/app/pages/album-detail-page/album-detail-page.component.html @@ -19,16 +19,13 @@

by

- + >
diff --git a/src/app/pages/album-detail-page/album-detail-page.component.ts b/src/app/pages/album-detail-page/album-detail-page.component.ts index 3c1ee9b..6054e7e 100644 --- a/src/app/pages/album-detail-page/album-detail-page.component.ts +++ b/src/app/pages/album-detail-page/album-detail-page.component.ts @@ -2,13 +2,9 @@ import { Component, OnInit } from '@angular/core'; import {Store} from '@ngxs/store'; import {ActivatedRoute} from '@angular/router'; import {AlbumModel} from '../../store/models/album.model'; -import {GetAlbum} from '../../store/actions/album.actions'; -import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; -import {GetTracks} from '../../store/actions/track.actions'; -import {TrackState} from '../../store/states/track.state'; import {PlayTrack} from '../../store/actions/player.actions'; -import {TrackModel} from '../../store/models/track.model'; -import {AlbumState} from '../../store/states/album.state'; +import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; +import {NestedEntityDataSource} from '../../datasources/nested-entity-data-source'; @Component({ selector: 'app-album-detail-page', @@ -17,32 +13,30 @@ import {AlbumState} from '../../store/states/album.state'; }) export class AlbumDetailPageComponent implements OnInit { public album: AlbumModel; - public trackIds: string[]; - public selector = TrackState.tracks; + + public trackDataSource: NestedEntityDataSource; public pageSize = 50; constructor( private store: Store, private route: ActivatedRoute, + private entityService: SpotifyEntityService, ) {} ngOnInit() { - this.route.params.subscribe((value) => { - this.store.dispatch(new GetAlbum(value.id)); - }); - - this.store.select(AlbumState.currentAlbum).subscribe((value: AlbumModel) => { - this.album = value; - this.trackIds = this.album.tracks.items.map(x => x.id); - this.onLoadRequest({page: 0, pageSize: this.pageSize}); + this.route.params.subscribe((params) => { + this.loadEntities(params.id); }); } - onLoadRequest(event: LoadRequestEvent) { - this.store.dispatch(new GetTracks(this.trackIds, event.page, event.pageSize)); + public onRowDoubleClick(event) { + this.store.dispatch(new PlayTrack(event.context, event.id)); } - onRowDoubleClick(event: TrackModel) { - this.store.dispatch(new PlayTrack(this.trackIds, event.id)); + private loadEntities(id) { + this.entityService.getEntity(id, 'album').subscribe((album: AlbumModel) => { + this.album = album; + this.trackDataSource = new NestedEntityDataSource(this.entityService, id, 'album', 'track', this.pageSize); + }); } } diff --git a/src/app/pages/album-page/albums-page.component.ts b/src/app/pages/album-page/albums-page.component.ts index 12652c4..fecab52 100644 --- a/src/app/pages/album-page/albums-page.component.ts +++ b/src/app/pages/album-page/albums-page.component.ts @@ -1,9 +1,6 @@ import { Component, OnInit } from '@angular/core'; import {Store} from '@ngxs/store'; import {Router} from '@angular/router'; -import {AlbumState} from '../../store/states/album.state'; -import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; -import {GetAlbums} from '../../store/actions/album.actions'; import {AlbumModel} from '../../store/models/album.model'; import {EntityDataSource} from '../../datasources/entity-data-source'; import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; diff --git a/src/app/pages/artist-detail/artist-detail-page.component.ts b/src/app/pages/artist-detail/artist-detail-page.component.ts index 53ebf1a..4016c04 100644 --- a/src/app/pages/artist-detail/artist-detail-page.component.ts +++ b/src/app/pages/artist-detail/artist-detail-page.component.ts @@ -3,7 +3,6 @@ import {Store} from '@ngxs/store'; import {ActivatedRoute, Router} from '@angular/router'; import {ArtistModel} from '../../store/models/artist.model'; import {AlbumModel} from '../../store/models/album.model'; -import {EntityDataSource} from '../../datasources/entity-data-source'; import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; import {NestedEntityDataSource} from '../../datasources/nested-entity-data-source'; diff --git a/src/app/pages/artists/artists-page.component.html b/src/app/pages/artists/artists-page.component.html index 293b0ab..b37f3dd 100644 --- a/src/app/pages/artists/artists-page.component.html +++ b/src/app/pages/artists/artists-page.component.html @@ -1,9 +1,5 @@ - +> diff --git a/src/app/pages/artists/artists-page.component.ts b/src/app/pages/artists/artists-page.component.ts index 545dadb..540f133 100644 --- a/src/app/pages/artists/artists-page.component.ts +++ b/src/app/pages/artists/artists-page.component.ts @@ -1,10 +1,9 @@ import {Component, OnInit} from '@angular/core'; import {Store} from '@ngxs/store'; -import {LoadRequestEvent} from '../../components/entity-list/entity-list.component'; import {ArtistModel} from '../../store/models/artist.model'; import {Router} from '@angular/router'; -import {GetArtists} from '../../store/actions/artist.actions'; -import {ArtistState} from '../../store/states/artist.state'; +import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; +import {EntityDataSource} from '../../datasources/entity-data-source'; @Component({ selector: 'app-artists-page', @@ -12,25 +11,21 @@ import {ArtistState} from '../../store/states/artist.state'; styleUrls: ['./artists-page.component.scss'] }) export class ArtistsPageComponent implements OnInit { - public ids: string[]; + public dataSource: EntityDataSource; public pageSize = 50; - public selector = ArtistState.artists; constructor( private store: Store, private router: Router, + private entityService: SpotifyEntityService, ) {} public ngOnInit(): void { this.store.select(state => state.artists.ids).subscribe((value) => { - this.ids = value; + this.dataSource = new EntityDataSource(this.entityService, value, 'artist', this.pageSize); }); } - public onLoadRequest(event: LoadRequestEvent): void { - this.store.dispatch(new GetArtists(this.ids, event.page, event.pageSize)); - } - public onRowDoubleClick(event: ArtistModel): void { this.router.navigate(['artist', event.id]); } diff --git a/src/app/pages/search/search-page.component.ts b/src/app/pages/search/search-page.component.ts index e68fe12..38b68b4 100644 --- a/src/app/pages/search/search-page.component.ts +++ b/src/app/pages/search/search-page.component.ts @@ -35,7 +35,7 @@ export class SearchPageComponent implements OnInit { } public onTrackDoubleClick(event) { - this.store.dispatch(new PlayTrack(this.trackDataSource.entities.map(x => x.id), event.id)); + this.store.dispatch(new PlayTrack(event.context, event.id)); } public onArtistDoubleClick(event) { diff --git a/src/app/pages/tracks/tracks-page.component.ts b/src/app/pages/tracks/tracks-page.component.ts index 36d7804..351dcb8 100644 --- a/src/app/pages/tracks/tracks-page.component.ts +++ b/src/app/pages/tracks/tracks-page.component.ts @@ -12,9 +12,7 @@ import {SpotifyEntityService} from '../../store/providers/spotify-entity.service styleUrls: ['./tracks-page.component.scss'] }) export class TracksPageComponent implements OnInit { - public ids: string[]; public pageSize = 50; - public selector = TrackState.tracks; public dataSource: EntityDataSource; constructor( @@ -30,7 +28,7 @@ export class TracksPageComponent implements OnInit { }); } - public onRowDoubleClick(event: TrackModel): void { - this.store.dispatch(new PlayTrack(this.ids, event.id)); + public onRowDoubleClick(event): void { + this.store.dispatch(new PlayTrack(event.context, event.id)); } } From 672fdd1fc9991be1b9496e3408c51edf00df0586 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:47:06 +0200 Subject: [PATCH 07/12] Reduce album state size --- src/app/store/actions/album.actions.ts | 27 ------------ src/app/store/states/album.state.ts | 57 +------------------------- 2 files changed, 2 insertions(+), 82 deletions(-) diff --git a/src/app/store/actions/album.actions.ts b/src/app/store/actions/album.actions.ts index 40fe308..03a8d24 100644 --- a/src/app/store/actions/album.actions.ts +++ b/src/app/store/actions/album.actions.ts @@ -1,30 +1,3 @@ -import {AlbumModel} from '../models/album.model'; -import {ArtistModel} from '../models/artist.model'; - -export class GetAlbums { - static readonly type = '[Album] GetAlbums'; - constructor( - public ids: string[], - public page: number, - public pageSize: number - ) {} -} - -export class GetAlbumsSuccess { - static readonly type = '[Album] GetAlbumsSuccess'; - constructor(public albums: AlbumModel[]) {} -} - -export class GetAlbum { - static readonly type = '[Album] GetAlbum'; - constructor(public id: string) {} -} - -export class GetAlbumSuccess { - static readonly type = '[Album] GetAlbumSuccess'; - constructor(public album: AlbumModel) {} -} - export class SaveAlbum { static readonly type = '[Album] SaveAlbum'; constructor(public id: string) {} diff --git a/src/app/store/states/album.state.ts b/src/app/store/states/album.state.ts index 50c2fc9..ebf3d98 100644 --- a/src/app/store/states/album.state.ts +++ b/src/app/store/states/album.state.ts @@ -1,8 +1,7 @@ -import {Action, createSelector, Selector, State, StateContext} from '@ngxs/store'; -import {AlbumSpotifyService} from '../providers/album-spotify.service'; +import {Action, createSelector, State, StateContext} from '@ngxs/store'; import {AlbumStateModel} from '../models/album-state.model'; import {append, patch, removeItem} from '@ngxs/store/operators'; -import {GetAlbum, GetAlbums, GetAlbumsSuccess, GetAlbumSuccess, RemoveAlbum, SaveAlbum} from '../actions/album.actions'; +import {RemoveAlbum, SaveAlbum} from '../actions/album.actions'; @State({ name: 'albums', @@ -18,58 +17,6 @@ export class AlbumState { }); } - @Selector() - static albums(state: AlbumStateModel) { - return state.albums; - } - - @Selector() - static currentAlbum(state: AlbumStateModel) { - return state.currentAlbum; - } - - constructor(private albumService: AlbumSpotifyService) {} - - @Action(GetAlbums) - public getAlbums(ctx: StateContext, action: GetAlbums) { - const start = action.page * action.pageSize; - const end = start + action.pageSize; - const pageIds = action.ids.slice(start, end); - this.albumService.getAlbums(pageIds, action.pageSize).subscribe((value: any) => { - ctx.dispatch(new GetAlbumsSuccess(value.albums)); - }); - } - - @Action(GetAlbumsSuccess) - public getAlbumsSuccess(ctx: StateContext, action: GetAlbumsSuccess) { - ctx.setState( - patch({ - albums: action.albums, - }) - ); - } - - @Action(GetAlbum) - public getArtist(ctx: StateContext, action: GetAlbum) { - const state = ctx.getState(); - ctx.patchState({ - ...state, - currentAlbumId: action.id, - }); - this.albumService.getAlbum(action.id).subscribe((value: any) => { - ctx.dispatch(new GetAlbumSuccess(value)); - }); - } - - @Action(GetAlbumSuccess) - public getArtistSuccess(ctx: StateContext, action: GetAlbumSuccess) { - const state = ctx.getState(); - ctx.patchState({ - ...state, - currentAlbum: action.album, - }); - } - @Action(SaveAlbum) public saveAlbum(ctx: StateContext, action: SaveAlbum) { ctx.setState( From e30e014ad8ca02a1c5033ddf5dfe1075a80e52b0 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:48:07 +0200 Subject: [PATCH 08/12] Remove album service --- src/app/app.module.ts | 2 -- .../providers/album-spotify.service.spec.ts | 12 ---------- .../store/providers/album-spotify.service.ts | 23 ------------------- 3 files changed, 37 deletions(-) delete mode 100644 src/app/store/providers/album-spotify.service.spec.ts delete mode 100644 src/app/store/providers/album-spotify.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 38cbc11..1ca4125 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -20,7 +20,6 @@ import {ArtistDetailPageComponent} from './pages/artist-detail/artist-detail-pag import {NgxsStoragePluginModule} from '@ngxs/storage-plugin'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import { ArtistSaveButtonComponent } from './components/artist-save-button/artist-save-button.component'; -import {AlbumSpotifyService} from './store/providers/album-spotify.service'; import {ArtistSpotifyService} from './store/providers/artist-spotify.service'; import {PlaylistSpotifyService} from './store/providers/playlist-spotify.service'; import {ProfileSpotifyService} from './store/providers/profile-spotify.service'; @@ -145,7 +144,6 @@ export function serialize(value: any) { useClass: SpotifyAuthorizationInterceptor, multi: true }, - AlbumSpotifyService, ArtistSpotifyService, PlaylistSpotifyService, ProfileSpotifyService, diff --git a/src/app/store/providers/album-spotify.service.spec.ts b/src/app/store/providers/album-spotify.service.spec.ts deleted file mode 100644 index f9f0c90..0000000 --- a/src/app/store/providers/album-spotify.service.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { AlbumSpotifyService } from './album-spotify.service'; - -describe('AlbumSpotifyService', () => { - beforeEach(() => TestBed.configureTestingModule({})); - - it('should be created', () => { - const service: AlbumSpotifyService = TestBed.get(AlbumSpotifyService); - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/store/providers/album-spotify.service.ts b/src/app/store/providers/album-spotify.service.ts deleted file mode 100644 index bbb5ef9..0000000 --- a/src/app/store/providers/album-spotify.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {Inject, Injectable} from '@angular/core'; -import {SpotifyConfig} from '../../definitions/spotify-config'; -import {HttpClient} from '@angular/common/http'; - -@Injectable({ - providedIn: 'root' -}) -export class AlbumSpotifyService { - constructor( - @Inject('SpotifyConfig') private config: SpotifyConfig, - private http: HttpClient - ) { } - - getAlbums(ids: string[], pageSize: number) { - const albums = ids.slice(0, Math.min(pageSize, ids.length)).join(); - console.log(albums); - return this.http.get(`${this.config.apiBase}/albums?ids=${albums}`); - } - - getAlbum(id: string) { - return this.http.get(`${this.config.apiBase}/albums/${id}`); - } -} From 9091ca2c58b649d0bc58d572dff4429aa7699855 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:51:35 +0200 Subject: [PATCH 09/12] Remove search state --- src/app/app.module.ts | 4 - src/app/store/actions/artist.actions.ts | 43 ---------- src/app/store/actions/search.actions.ts | 17 ---- .../providers/artist-spotify.service.spec.ts | 12 --- .../store/providers/artist-spotify.service.ts | 26 ------ src/app/store/states/artist.state.ts | 80 +------------------ src/app/store/states/search.state.ts | 1 - 7 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 src/app/store/actions/search.actions.ts delete mode 100644 src/app/store/providers/artist-spotify.service.spec.ts delete mode 100644 src/app/store/providers/artist-spotify.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1ca4125..5057a2b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,12 +15,10 @@ import { ArtistsPageComponent } from './pages/artists/artists-page.component'; import {ArtistState} from './store/states/artist.state'; import {NgxsReduxDevtoolsPluginModule} from '@ngxs/devtools-plugin'; import {FormsModule} from '@angular/forms'; -import {SearchState} from './store/states/search.state'; import {ArtistDetailPageComponent} from './pages/artist-detail/artist-detail-page.component'; import {NgxsStoragePluginModule} from '@ngxs/storage-plugin'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import { ArtistSaveButtonComponent } from './components/artist-save-button/artist-save-button.component'; -import {ArtistSpotifyService} from './store/providers/artist-spotify.service'; import {PlaylistSpotifyService} from './store/providers/playlist-spotify.service'; import {ProfileSpotifyService} from './store/providers/profile-spotify.service'; import {SearchSpotifyService} from './store/providers/search-spotify.service'; @@ -123,7 +121,6 @@ export function serialize(value: any) { NgxsModule.forRoot([ FolderState, ArtistState, - SearchState, TrackState, PlayerState, AuthenticationState, @@ -144,7 +141,6 @@ export function serialize(value: any) { useClass: SpotifyAuthorizationInterceptor, multi: true }, - ArtistSpotifyService, PlaylistSpotifyService, ProfileSpotifyService, SearchSpotifyService, diff --git a/src/app/store/actions/artist.actions.ts b/src/app/store/actions/artist.actions.ts index 490e20a..3bdb204 100644 --- a/src/app/store/actions/artist.actions.ts +++ b/src/app/store/actions/artist.actions.ts @@ -1,32 +1,3 @@ -import {ArtistModel} from '../models/artist.model'; -import {AlbumModel} from '../models/album.model'; - -export class GetArtists { - static readonly type = '[Artist] GetArtists'; - constructor( - public ids: string[], - public page: number, - public pageSize: number - ) {} -} - -export class GetArtistsSuccess { - static readonly type = '[Artist] GetArtistsSuccess'; - constructor(public artists: ArtistModel[]) {} -} - -export class GetArtist { - static readonly type = '[Artist] GetArtist'; - - constructor(public id: string) { - } -} - -export class GetArtistSuccess { - static readonly type = '[Artist] GetArtistSuccess'; - constructor(public artist: ArtistModel) {} -} - export class SaveArtist { static readonly type = '[Artist] SaveArtist'; constructor(public id: string) {} @@ -36,17 +7,3 @@ export class RemoveArtist { static readonly type = '[Artist] RemoveArtist'; constructor(public id: string) {} } - -export class GetArtistAlbums { - static readonly type = '[Artist] GetArtistAlbums'; - constructor( - public id: string, - public page: number, - public pageSize: number - ) {} -} - -export class GetArtistAlbumsSuccess { - static readonly type = '[Artist] GetArtistAlbumsSuccess'; - constructor(public albums: AlbumModel[], public total: number) {} -} diff --git a/src/app/store/actions/search.actions.ts b/src/app/store/actions/search.actions.ts deleted file mode 100644 index b4ec2a1..0000000 --- a/src/app/store/actions/search.actions.ts +++ /dev/null @@ -1,17 +0,0 @@ -export class Search { - static readonly type = '[Search] Search'; - constructor( - public query: string, - public pageSize: number, - public offset: number, - public type: string[], - ) {} -} - -export class SearchSuccess { - static readonly type = '[Search] SearchSuccess'; - constructor( - public results: any, - public type: string[], - ) {} -} diff --git a/src/app/store/providers/artist-spotify.service.spec.ts b/src/app/store/providers/artist-spotify.service.spec.ts deleted file mode 100644 index b002a2e..0000000 --- a/src/app/store/providers/artist-spotify.service.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ArtistSpotifyService } from './artist-spotify.service'; - -describe('ArtistSpotifyService', () => { - beforeEach(() => TestBed.configureTestingModule({})); - - it('should be created', () => { - const service: ArtistSpotifyService = TestBed.get(ArtistSpotifyService); - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/store/providers/artist-spotify.service.ts b/src/app/store/providers/artist-spotify.service.ts deleted file mode 100644 index 5068d13..0000000 --- a/src/app/store/providers/artist-spotify.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {Inject, Injectable} from '@angular/core'; -import {SpotifyConfig} from '../../definitions/spotify-config'; -import {HttpClient} from '@angular/common/http'; - -@Injectable({ - providedIn: 'root' -}) -export class ArtistSpotifyService { - constructor( - @Inject('SpotifyConfig') private config: SpotifyConfig, - private http: HttpClient - ) { } - - getArtist(id: string) { - return this.http.get(`${this.config.apiBase}/artists/${id}`); - } - - getArtists(ids: string[], pageSize: number) { - const artists = ids.slice(0, Math.min(pageSize, ids.length)).join(); - return this.http.get(`${this.config.apiBase}/artists?ids=${artists}`); - } - - getArtistAlbums(id: string, page: number, pageSize: number) { - return this.http.get(`${this.config.apiBase}/artists/${id}/albums?limit=${pageSize}&offset=${page}&market=from_token&include_groups=album`); - } -} diff --git a/src/app/store/states/artist.state.ts b/src/app/store/states/artist.state.ts index 9da3149..786fc9e 100644 --- a/src/app/store/states/artist.state.ts +++ b/src/app/store/states/artist.state.ts @@ -1,16 +1,10 @@ -import {Action, createSelector, Selector, State, StateContext} from '@ngxs/store'; +import {Action, createSelector, State, StateContext} from '@ngxs/store'; import {ArtistStateModel} from '../models/artist-state.model'; import { - GetArtist, - GetArtistAlbums, GetArtistAlbumsSuccess, - GetArtists, - GetArtistsSuccess, - GetArtistSuccess, RemoveArtist, SaveArtist } from '../actions/artist.actions'; import {append, patch, removeItem} from '@ngxs/store/operators'; -import {ArtistSpotifyService} from '../providers/artist-spotify.service'; @State({ name: 'artists', @@ -30,58 +24,6 @@ export class ArtistState { }); } - @Selector() - static artists(state: ArtistStateModel) { - return state.artists; - } - - @Selector() - static currentArtist(state: ArtistStateModel) { - return state.currentArtist; - } - - constructor(private artistService: ArtistSpotifyService) {} - - @Action(GetArtists) - public getArtists(ctx: StateContext, action: GetArtists) { - const start = action.page * action.pageSize; - const end = start + action.pageSize; - const pageIds = action.ids.slice(start, end); - this.artistService.getArtists(pageIds, action.pageSize).subscribe((value: any) => { - ctx.dispatch(new GetArtistsSuccess(value.artists)); - }); - } - - @Action(GetArtistsSuccess) - public getArtistsSuccess(ctx: StateContext, action: GetArtistsSuccess) { - ctx.setState( - patch({ - artists: action.artists, - }) - ); - } - - @Action(GetArtist) - public getArtist(ctx: StateContext, action: GetArtist) { - const state = ctx.getState(); - ctx.patchState({ - ...state, - currentArtistId: action.id, - }); - this.artistService.getArtist(action.id).subscribe((value: any) => { - ctx.dispatch(new GetArtistSuccess(value)); - }); - } - - @Action(GetArtistSuccess) - public getArtistSuccess(ctx: StateContext, action: GetArtistSuccess) { - const state = ctx.getState(); - ctx.patchState({ - ...state, - currentArtist: action.artist, - }); - } - @Action(SaveArtist) public saveArtist(ctx: StateContext, action: SaveArtist) { ctx.setState( @@ -99,24 +41,4 @@ export class ArtistState { }), ); } - - @Action(GetArtistAlbums) - public getArtistAlbums(ctx: StateContext, action: GetArtistAlbums) { - this.artistService.getArtistAlbums(action.id, action.page, action.pageSize).subscribe((value: any) => { - ctx.dispatch(new GetArtistAlbumsSuccess(value.items, value.total)); - }); - } - - @Action(GetArtistAlbumsSuccess) - public getArtistAlbumsSuccess(ctx: StateContext, action: GetArtistAlbumsSuccess) { - const state = ctx.getState(); - ctx.setState({ - ...state, - currentArtist: { - ...state.currentArtist, - albums: action.albums, - totalAlbums: action.total, - }, - }); - } } diff --git a/src/app/store/states/search.state.ts b/src/app/store/states/search.state.ts index b691782..4a5c3c2 100644 --- a/src/app/store/states/search.state.ts +++ b/src/app/store/states/search.state.ts @@ -1,6 +1,5 @@ import {Action, Selector, State, StateContext} from '@ngxs/store'; import {SearchStateModel} from '../models/search-state.model'; -import {Search, SearchSuccess} from '../actions/search.actions'; import {SearchSpotifyService} from '../providers/search-spotify.service'; @State({ From f7a3928c227047d21300dbcc201ce7a01e1b606c Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 20:57:06 +0200 Subject: [PATCH 10/12] Reduce track state size --- src/app/store/actions/track.actions.ts | 16 ----------- .../store/providers/track-spotify.service.ts | 9 ------ src/app/store/states/track.state.ts | 28 +------------------ 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/src/app/store/actions/track.actions.ts b/src/app/store/actions/track.actions.ts index 2efc5fe..27f6d33 100644 --- a/src/app/store/actions/track.actions.ts +++ b/src/app/store/actions/track.actions.ts @@ -1,19 +1,3 @@ -import {TrackModel} from '../models/track.model'; - -export class GetTracks { - static readonly type = '[Track] GetTracks'; - constructor( - public ids: string[], - public page: number, - public pageSize: number - ) {} -} - -export class GetTracksSuccess { - static readonly type = '[Track] GetTracksSuccess'; - constructor(public tracks: TrackModel[]) {} -} - export class SaveTrack { static readonly type = '[Track] SaveTrack'; constructor(public id: string) {} diff --git a/src/app/store/providers/track-spotify.service.ts b/src/app/store/providers/track-spotify.service.ts index 416ccbb..5c1889b 100644 --- a/src/app/store/providers/track-spotify.service.ts +++ b/src/app/store/providers/track-spotify.service.ts @@ -11,15 +11,6 @@ export class TrackSpotifyService { private http: HttpClient, ) { } - getTrack(id: string) { - return this.http.get(`${this.config.apiBase}/track/${id}`); - } - - getTracks(ids: string[], pageSize: number) { - const tracks = ids.slice(0, Math.min(pageSize, ids.length)).join(); - return this.http.get(`${this.config.apiBase}/tracks?ids=${tracks}`); - } - importTracks(offset: number) { let url = `${this.config.apiBase}/me/tracks?limit=50`; if (offset > 0) { diff --git a/src/app/store/states/track.state.ts b/src/app/store/states/track.state.ts index c9438da..8b9ac99 100644 --- a/src/app/store/states/track.state.ts +++ b/src/app/store/states/track.state.ts @@ -1,10 +1,8 @@ -import {Action, createSelector, Selector, State, StateContext} from '@ngxs/store'; +import {Action, createSelector, State, StateContext} from '@ngxs/store'; import {TrackStateModel} from '../models/track-state.model'; import {TrackSpotifyService} from '../providers/track-spotify.service'; import {append, patch, removeItem} from '@ngxs/store/operators'; import { - GetTracks, - GetTracksSuccess, ImportTracks, ImportPlaylists, ImportPlaylistsSuccess, ImportTracksSuccess, @@ -28,32 +26,8 @@ export class TrackState { }); } - @Selector() - static tracks(state: TrackStateModel) { - return state.tracks; - } - constructor(private trackService: TrackSpotifyService) {} - @Action(GetTracks) - public getTracks(ctx: StateContext, action: GetTracks) { - const start = action.page * action.pageSize; - const end = start + action.pageSize; - const pageIds = action.ids.slice(start, end); - this.trackService.getTracks(pageIds, action.pageSize).subscribe((value: any) => { - ctx.dispatch(new GetTracksSuccess(value.tracks)); - }); - } - - @Action(GetTracksSuccess) - public getTracksSuccess(ctx: StateContext, action: GetTracksSuccess) { - ctx.setState( - patch({ - tracks: action.tracks, - }) - ); - } - @Action(SaveTrack) public saveTrack(ctx: StateContext, action: SaveTrack) { ctx.setState( From 2e73421dd4e497be2edf14d73304e9c743e0b748 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 21:01:36 +0200 Subject: [PATCH 11/12] Remove entity list --- src/app/app.module.ts | 2 - .../entity-list/entity-list.component.html | 70 ------------- .../entity-list/entity-list.component.scss | 52 ---------- .../entity-list/entity-list.component.spec.ts | 25 ----- .../entity-list/entity-list.component.ts | 97 ------------------- 5 files changed, 246 deletions(-) delete mode 100644 src/app/components/entity-list/entity-list.component.html delete mode 100644 src/app/components/entity-list/entity-list.component.scss delete mode 100644 src/app/components/entity-list/entity-list.component.spec.ts delete mode 100644 src/app/components/entity-list/entity-list.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5057a2b..539e4a1 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -39,7 +39,6 @@ import {MinutesSecondsPipe} from './pipes/minutes-seconds.pipe'; import { VolumeControlComponent } from './components/volume-control/volume-control.component'; import { PlayerTrackInfoComponent } from './components/player-track-info/player-track-info.component'; import {AuthenticationState} from './store/states/authentication.state'; -import { EntityListComponent } from './components/entity-list/entity-list.component'; import { AlbumsPageComponent } from './pages/album-page/albums-page.component'; import {AlbumState} from './store/states/album.state'; import { AlbumSaveButtonComponent } from './components/album-save-button/album-save-button.component'; @@ -107,7 +106,6 @@ export function serialize(value: any) { MinutesSecondsPipe, VolumeControlComponent, PlayerTrackInfoComponent, - EntityListComponent, AlbumsPageComponent, AlbumSaveButtonComponent, AlbumDetailPageComponent, diff --git a/src/app/components/entity-list/entity-list.component.html b/src/app/components/entity-list/entity-list.component.html deleted file mode 100644 index 28ec2bc..0000000 --- a/src/app/components/entity-list/entity-list.component.html +++ /dev/null @@ -1,70 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name{{element.name}}Popularity - - Album - {{element.album.name}} - Artist - - timer{{element.duration_ms | minutesSeconds}} - - - - - -
-
- - diff --git a/src/app/components/entity-list/entity-list.component.scss b/src/app/components/entity-list/entity-list.component.scss deleted file mode 100644 index a44f6e5..0000000 --- a/src/app/components/entity-list/entity-list.component.scss +++ /dev/null @@ -1,52 +0,0 @@ -:host { - display: flex; - flex-direction: column; - height: 100%; -} - -.playing { - background: rgba(255, 255, 255, 0.13); -} - -.list-container { - flex: 1; - overflow: auto; - - border-bottom: 1px rgba(255,255,255,.12) solid; - box-sizing: content-box; -} - -.table { - width: 100%; - - tr { - height: 32px; - } - - td { - &.mat-column-image, - &.mat-column-album-image { - width: 32px; - } - - &.mat-column-popularity { - .progress-bar { - width: 100%; - } - } - - &.mat-column-track-saved, - &.mat-column-artist-saved, - &.mat-column-duration, - &.mat-column-popularity, - &.mat-column-album-saved { - width: 40px; - } - } - - img { - height: 32px; - width: auto; - display: block; - } -} diff --git a/src/app/components/entity-list/entity-list.component.spec.ts b/src/app/components/entity-list/entity-list.component.spec.ts deleted file mode 100644 index 94cc9a6..0000000 --- a/src/app/components/entity-list/entity-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { EntityListComponent } from './entity-list.component'; - -describe('EntityListComponent', () => { - let component: EntityListComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ EntityListComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(EntityListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/components/entity-list/entity-list.component.ts b/src/app/components/entity-list/entity-list.component.ts deleted file mode 100644 index a579a76..0000000 --- a/src/app/components/entity-list/entity-list.component.ts +++ /dev/null @@ -1,97 +0,0 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {SpotifyEntityModel} from '../../store/models/spotify-entity.model'; -import {Store} from '@ngxs/store'; - -export interface LoadRequestEvent { - page: number; - pageSize: number; -} - -@Component({ - selector: 'app-entity-list', - templateUrl: './entity-list.component.html', - styleUrls: ['./entity-list.component.scss'] -}) -export class EntityListComponent implements OnInit { - /** - * How many entities should show per list. - */ - @Input() public pageSize: number; - - /** - * The displayed colums. - * Columns that can be used: - * - image - * - album-image - * - name - * - popularity - * - album - * - artist - * - duration - * - saved - */ - @Input() public columns: string[] = ['name']; - - /** - * The selector to get your data from the NGXS store. - */ - @Input() public selector: any; - - /** - * The current page - */ - @Input() public page: number; - - /** - * The total of entities (not pages) - */ - @Input() public total: number; - - /** - * Emits an event with page and pageSize to be loaded. - */ - @Output() public loadRequest = new EventEmitter(); - - /** - * Emits an event containing the row object. - */ - @Output() public rowDoubleClick = new EventEmitter(); - - public entities: SpotifyEntityModel[]; - public loading = true; - - constructor( - private store: Store, - ) {} - - /** - * Get the entities from the store. - */ - public ngOnInit(): void { - this.requestLoad(); - this.store.select(this.selector).subscribe((value: SpotifyEntityModel[]) => { - this.entities = value; - this.loading = false; - }); - } - - /** - * Change page and request load - */ - public onPageChange(event): void { - this.page = event.pageIndex; - this.requestLoad(); - } - - /** - * Emit the event to request entity loading. - */ - private requestLoad(): void { - if (this.total > 0) { - this.loadRequest.emit({ - page: this.page, - pageSize: this.pageSize, - }); - } - } -} From 8eecb778b70ace88df524f7c9541ef4a013278d1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 22 Aug 2019 21:04:45 +0200 Subject: [PATCH 12/12] Remove search state --- src/app/store/states/search.state.ts | 61 ---------------------------- 1 file changed, 61 deletions(-) delete mode 100644 src/app/store/states/search.state.ts diff --git a/src/app/store/states/search.state.ts b/src/app/store/states/search.state.ts deleted file mode 100644 index 4a5c3c2..0000000 --- a/src/app/store/states/search.state.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {Action, Selector, State, StateContext} from '@ngxs/store'; -import {SearchStateModel} from '../models/search-state.model'; -import {SearchSpotifyService} from '../providers/search-spotify.service'; - -@State({ - name: 'search', - defaults: { - query: '', - results: null, - } -}) -export class SearchState { - @Selector() - static tracks(state: SearchStateModel) { - return state.results.tracks.items; - } - - @Selector() - static artists(state: SearchStateModel) { - return state.results.artists.items; - } - - @Selector() - static albums(state: SearchStateModel) { - return state.results.albums.items; - } - - @Selector() - static playlists(state: SearchStateModel) { - return state.results.playlists.items; - } - - constructor(private searchService: SearchSpotifyService) {} - - @Action(Search) - public search(ctx: StateContext, action: Search) { - const state = ctx.getState(); - ctx.patchState({ - ...state, - query: action.query, - }); - this.searchService.search(action.query, action.pageSize, action.offset * action.pageSize, action.type).subscribe((value: any) => { - ctx.dispatch(new SearchSuccess(value, action.type)); - }); - } - - @Action(SearchSuccess) - public searchSuccess(ctx: StateContext, action: SearchSuccess) { - const state = ctx.getState(); - ctx.patchState({ - ...state, - results: { - ...state.results, - tracks: action.results.tracks ? action.results.tracks : state.results.tracks, - artists: action.results.artists ? action.results.artists : state.results.artists, - albums: action.results.albums ? action.results.albums : state.results.albums, - playlists: action.results.playlists ? action.results.playlists : state.results.playlists, - }, - }); - } -}