diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 07d190d..539e4a1 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,13 +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 {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'; import {SearchSpotifyService} from './store/providers/search-spotify.service'; @@ -42,12 +39,12 @@ 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'; 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, @@ -109,11 +106,11 @@ export function serialize(value: any) { MinutesSecondsPipe, VolumeControlComponent, PlayerTrackInfoComponent, - EntityListComponent, AlbumsPageComponent, AlbumSaveButtonComponent, AlbumDetailPageComponent, ArtistNamesComponent, + VirtualScrollListComponent, ], imports: [ BrowserModule, @@ -122,7 +119,6 @@ export function serialize(value: any) { NgxsModule.forRoot([ FolderState, ArtistState, - SearchState, TrackState, PlayerState, AuthenticationState, @@ -143,8 +139,6 @@ export function serialize(value: any) { useClass: SpotifyAuthorizationInterceptor, multi: true }, - AlbumSpotifyService, - ArtistSpotifyService, PlaylistSpotifyService, ProfileSpotifyService, SearchSpotifyService, 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, - }); - } - } -} diff --git a/src/app/components/entity-list/entity-list.component.html b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html similarity index 72% rename from src/app/components/entity-list/entity-list.component.html rename to src/app/components/virtual-scroll-list/virtual-scroll-list.component.html index 28ec2bc..0db6923 100644 --- a/src/app/components/entity-list/entity-list.component.html +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.html @@ -1,5 +1,5 @@ -
- +
+
@@ -7,7 +7,8 @@ - + @@ -23,21 +24,26 @@ - + - + - + @@ -63,8 +69,9 @@ - +
Album Album {{element.album.name}} Artist Artist - + + {{artist.name}} + , + timer + timer + {{element.duration_ms | minutesSeconds}}
- + diff --git a/src/app/components/entity-list/entity-list.component.scss b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.scss similarity index 100% rename from src/app/components/entity-list/entity-list.component.scss rename to src/app/components/virtual-scroll-list/virtual-scroll-list.component.scss diff --git a/src/app/components/entity-list/entity-list.component.spec.ts b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts similarity index 50% rename from src/app/components/entity-list/entity-list.component.spec.ts rename to src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts index 94cc9a6..8f6d5ca 100644 --- a/src/app/components/entity-list/entity-list.component.spec.ts +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { EntityListComponent } from './entity-list.component'; +import { VirtualScrollListComponent } from './virtual-scroll-list.component'; -describe('EntityListComponent', () => { - let component: EntityListComponent; - let fixture: ComponentFixture; +describe('VirtualScrollListComponent', () => { + let component: VirtualScrollListComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ EntityListComponent ] + declarations: [ VirtualScrollListComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(EntityListComponent); + fixture = TestBed.createComponent(VirtualScrollListComponent); component = fixture.componentInstance; fixture.detectChanges(); }); 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..a7f76f4 --- /dev/null +++ b/src/app/components/virtual-scroll-list/virtual-scroll-list.component.ts @@ -0,0 +1,61 @@ +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'; + +@Component({ + selector: 'app-virtual-scroll-list', + templateUrl: './virtual-scroll-list.component.html', + styleUrls: ['./virtual-scroll-list.component.scss'] +}) +export class VirtualScrollListComponent implements OnInit, OnChanges { + /** + * 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 and the ids of the rest of the page + */ + @Output() public rowDoubleClick = new EventEmitter<{ + id: string, + context: string[] + }>(); + + public ngOnInit(): void { + this.dataSource.openPage(0); + } + + public ngOnChanges(): void { + this.dataSource.openPage(0); + } + + public onPageChange(event): void { + 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 new file mode 100644 index 0000000..3692366 --- /dev/null +++ b/src/app/datasources/entity-data-source.ts @@ -0,0 +1,45 @@ +import {TrackModel} from '../store/models/track.model'; +import {CollectionViewer} from '@angular/cdk/collections'; +import {BehaviorSubject, Observable} from 'rxjs'; +import {PagedDataSource} from './paged-data-source'; +import {SpotifyEntityModel} from '../store/models/spotify-entity.model'; +import {SpotifyEntityService} from '../store/providers/spotify-entity.service'; + +export class EntityDataSource extends PagedDataSource { + private entities = []; + + private subject = new BehaviorSubject(this.entities); + private observable = this.subject.asObservable(); + + constructor( + 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> { + 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.entityService.getEntities(pageIds, this.type, this.pageSize).subscribe((value: any) => { + this.entities = value[this.type + 's']; + 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 new file mode 100644 index 0000000..b0ca90f --- /dev/null +++ b/src/app/datasources/nested-entity-data-source.ts @@ -0,0 +1,43 @@ +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); + }); + } + + 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 new file mode 100644 index 0000000..28caa41 --- /dev/null +++ b/src/app/datasources/paged-data-source.ts @@ -0,0 +1,8 @@ +import {DataSource} from '@angular/cdk/table'; + +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 new file mode 100644 index 0000000..319afb8 --- /dev/null +++ b/src/app/datasources/search-data-source.ts @@ -0,0 +1,42 @@ +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; + } + + public connect(collectionViewer: CollectionViewer): Observable> { + return this.observable; + } + + public disconnect(collectionViewer: CollectionViewer): void { + this.subject.complete(); + } + + 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/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/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.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 7dc46ef..fecab52 100644 --- a/src/app/pages/album-page/albums-page.component.ts +++ b/src/app/pages/album-page/albums-page.component.ts @@ -1,10 +1,9 @@ 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'; @Component({ selector: 'app-albums-page', @@ -12,25 +11,21 @@ import {AlbumModel} from '../../store/models/album.model'; styleUrls: ['./albums-page.component.scss'] }) export class AlbumsPageComponent implements OnInit { - public ids: string[]; + public dataSource: EntityDataSource; public pageSize = 50; - public selector = AlbumState.albums; 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]); } 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..4016c04 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,10 @@ 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 {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; +import {NestedEntityDataSource} from '../../datasources/nested-entity-data-source'; @Component({ selector: 'app-artist-detail-page', @@ -17,38 +13,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/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.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..38b68b4 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,31 @@ 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, + ) {} 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'); }); } - 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(event.context, event.id)); } public onArtistDoubleClick(event) { 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..351dcb8 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 {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 {EntityDataSource} from '../../datasources/entity-data-source'; +import {SpotifyEntityService} from '../../store/providers/spotify-entity.service'; @Component({ selector: 'app-tracks-page', @@ -12,23 +12,23 @@ import {TrackState} from '../../store/states/track.state'; styleUrls: ['./tracks-page.component.scss'] }) export class TracksPageComponent implements OnInit { - public ids: string[]; public pageSize = 50; - public selector = TrackState.tracks; + public dataSource: EntityDataSource; - constructor(private store: Store) {} + constructor( + private store: Store, + private entityService: SpotifyEntityService, + ) {} public ngOnInit(): void { this.store.select(state => state.tracks.ids).subscribe((value) => { - this.ids = value; + if (value) { + this.dataSource = new EntityDataSource(this.entityService, value, 'track', 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)); + public onRowDoubleClick(event): void { + this.store.dispatch(new PlayTrack(event.context, event.id)); } } 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/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/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/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 ec79f85..0000000 --- a/src/app/store/providers/album-spotify.service.ts +++ /dev/null @@ -1,21 +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[]) { - return this.http.get(`${this.config.apiBase}/albums?ids=${ids}`); - } - - getAlbum(id: string) { - return this.http.get(`${this.config.apiBase}/albums/${id}`); - } -} 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 8cd7bf8..0000000 --- a/src/app/store/providers/artist-spotify.service.ts +++ /dev/null @@ -1,25 +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[]) { - return this.http.get(`${this.config.apiBase}/artists?ids=${ids}`); - } - - 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/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}`); } } diff --git a/src/app/store/providers/artist-spotify.service.spec.ts b/src/app/store/providers/spotify-entity.service.spec.ts similarity index 50% rename from src/app/store/providers/artist-spotify.service.spec.ts rename to src/app/store/providers/spotify-entity.service.spec.ts index b002a2e..1352041 100644 --- a/src/app/store/providers/artist-spotify.service.spec.ts +++ b/src/app/store/providers/spotify-entity.service.spec.ts @@ -1,12 +1,12 @@ import { TestBed } from '@angular/core/testing'; -import { ArtistSpotifyService } from './artist-spotify.service'; +import { SpotifyEntityService } from './spotify-entity.service'; -describe('ArtistSpotifyService', () => { +describe('SpotifyEntityService', () => { beforeEach(() => TestBed.configureTestingModule({})); it('should be created', () => { - const service: ArtistSpotifyService = TestBed.get(ArtistSpotifyService); + 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/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/album.state.ts b/src/app/store/states/album.state.ts index ddbdf49..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).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( diff --git a/src/app/store/states/artist.state.ts b/src/app/store/states/artist.state.ts index 7fb74e1..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).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 deleted file mode 100644 index b691782..0000000 --- a/src/app/store/states/search.state.ts +++ /dev/null @@ -1,62 +0,0 @@ -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({ - 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, - }, - }); - } -} 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( 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 */