From 42d8d7bf8d0cb668170eb2fd15a94764b56d0ba4 Mon Sep 17 00:00:00 2001 From: Lars Bergqvist Date: Sat, 25 Nov 2023 12:56:41 +0100 Subject: [PATCH] Reduce network/memory load by not pre-fetching programs (#57) * lazy load programs * Do not preload programs * Re-implementation of adding a program as fav from program details * ProgramFavoritesComponent * Program favorites * test * test * Bugfix title on audioplayer --- .github/workflows/buildanddeploy.yml | 1 - src/app/app.module.ts | 4 +- .../audio-player/audio-player.component.html | 2 +- .../audio-player/audio-player.component.ts | 1 + .../channels/channel-schedule.component.ts | 2 +- .../programs/program-details.component.ts | 9 +- .../programs/program-favorites.component.html | 52 +++++++ .../programs/program-favorites.component.scss | 11 ++ .../programs/program-favorites.component.ts | 47 ++++++ .../programs/programs-list.component.html | 28 +--- .../programs/programs-list.component.ts | 60 +++----- src/app/messages/favorite-changed.message.ts | 15 ++ src/app/models/programs-result.ts | 13 ++ src/app/services/episodes.service.ts | 2 +- src/app/services/programs.service.ts | 76 ++++++++++ src/app/services/srapi.service.ts | 139 +++++++----------- src/app/translations/res-en.json | 3 +- src/app/translations/res-sv.json | 3 +- 18 files changed, 308 insertions(+), 160 deletions(-) create mode 100644 src/app/components/programs/program-favorites.component.html create mode 100644 src/app/components/programs/program-favorites.component.scss create mode 100644 src/app/components/programs/program-favorites.component.ts create mode 100644 src/app/messages/favorite-changed.message.ts create mode 100644 src/app/models/programs-result.ts create mode 100644 src/app/services/programs.service.ts diff --git a/.github/workflows/buildanddeploy.yml b/.github/workflows/buildanddeploy.yml index e3f3ba0..ac1807c 100644 --- a/.github/workflows/buildanddeploy.yml +++ b/.github/workflows/buildanddeploy.yml @@ -35,7 +35,6 @@ jobs: deploy: needs: test-and-build runs-on: ubuntu-latest - if: github.ref == 'refs/heads/master' steps: - name: Checkout uses: actions/checkout@v3 diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4d3d22d..fdbcbbf 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -35,6 +35,7 @@ import { LoggingService } from './services/logging.service'; import { MessageBrokerService } from './services/message-broker.service'; import { TranslatePipe } from './translations/translate.pipe'; import { SelectButtonModule } from 'primeng/selectbutton'; +import { ProgramFavoritesComponent } from './components/programs/program-favorites.component'; registerLocaleData(locale); @@ -54,7 +55,8 @@ registerLocaleData(locale); ProgramDetailsComponent, EpisodesListComponent, EpisodesTableComponent, - EpisodesBookmarksComponent + EpisodesBookmarksComponent, + ProgramFavoritesComponent ], imports: [ BrowserModule, diff --git a/src/app/components/audio-player/audio-player.component.html b/src/app/components/audio-player/audio-player.component.html index 59ffc37..73adbe2 100644 --- a/src/app/components/audio-player/audio-player.component.html +++ b/src/app/components/audio-player/audio-player.component.html @@ -1,5 +1,5 @@
-
{{this.prefixText}}{{currentStation}} diff --git a/src/app/components/audio-player/audio-player.component.ts b/src/app/components/audio-player/audio-player.component.ts index d073788..6e77ba9 100644 --- a/src/app/components/audio-player/audio-player.component.ts +++ b/src/app/components/audio-player/audio-player.component.ts @@ -37,6 +37,7 @@ export class AudioPlayerComponent implements OnInit { ) .subscribe(async (message: PlayAudioMessage) => { if (!message) return; + if (!message.url) return; this.episodeId = message.episodeId; this.channelId = message.channelId; if (this.episodeId) { diff --git a/src/app/components/channels/channel-schedule.component.ts b/src/app/components/channels/channel-schedule.component.ts index 160227b..2762fd4 100644 --- a/src/app/components/channels/channel-schedule.component.ts +++ b/src/app/components/channels/channel-schedule.component.ts @@ -105,7 +105,7 @@ export class ChannelScheduleComponent implements OnInit, OnDestroy { endtimeDate: convertFromJSONstring(s?.endtimeutc), program: s.program, imageurltemplate: s.imageurltemplate, - imageurl: s.imageurltemplate ? s.imageurltemplate + SRApiService.DefaultImagePreset : this.srApiService.getProgramImageUrlFromId(s.program.id) + imageurl: s.imageurltemplate ? s.imageurltemplate + SRApiService.DefaultImagePreset : this.srApiService.getChannelImageUrlFromId(channelId) })); } diff --git a/src/app/components/programs/program-details.component.ts b/src/app/components/programs/program-details.component.ts index 3ae813d..6580409 100644 --- a/src/app/components/programs/program-details.component.ts +++ b/src/app/components/programs/program-details.component.ts @@ -9,6 +9,7 @@ import { MessageBrokerService } from 'src/app/services/message-broker.service'; import { SRApiService } from 'src/app/services/srapi.service'; import { EpisodeViewModel } from '../episodes/episode-viewmodel'; import { EpisodesLoadLazyArgs } from '../episodes/episodes-table.component'; +import { ProgramsService } from 'src/app/services/programs.service'; @Component({ selector: 'app-program-details', @@ -26,7 +27,8 @@ export class ProgramDetailsComponent implements OnInit, OnDestroy { private readonly service: EpisodesService, private readonly srApiService: SRApiService, private readonly activatedRoute: ActivatedRoute, - private readonly broker: MessageBrokerService + private readonly broker: MessageBrokerService, + private readonly programsService: ProgramsService, ) {} async ngOnInit() { @@ -36,7 +38,7 @@ export class ProgramDetailsComponent implements OnInit, OnDestroy { map((route) => route.id) ) .subscribe(async (id: string) => { - const program = await this.srApiService.getProgramFromId(parseInt(id)); + const program = await this.programsService.fetchProgramWithId(parseInt(id)); if (program) { await this.show(program); } @@ -80,9 +82,10 @@ export class ProgramDetailsComponent implements OnInit, OnDestroy { onAddToFavorites(programId: number, programName: string) { this.srApiService.addProgramToFavorites(programId, programName); + this.program.fav = true; } - onRemoveFromFavorites(programId: number, programName: string) { this.srApiService.removeProgramFromFavorites(programId, programName); + this.program.fav = false; } } diff --git a/src/app/components/programs/program-favorites.component.html b/src/app/components/programs/program-favorites.component.html new file mode 100644 index 0000000..e829c4a --- /dev/null +++ b/src/app/components/programs/program-favorites.component.html @@ -0,0 +1,52 @@ + + + + + + {{'ProgramNameTitle' | translate | uppercase }} + + + {{'ChannelNameTitle' | translate | uppercase }} + + + + {{'Description' | translate | uppercase}} + + + + + +
+ + + + {{program.channel.name}} + + + {{program.name}} + + + + + + +
+ + +
+ {{program.channel.name}} +
+ + + {{program.description}} + + +
+
+ +
+
\ No newline at end of file diff --git a/src/app/components/programs/program-favorites.component.scss b/src/app/components/programs/program-favorites.component.scss new file mode 100644 index 0000000..e1f9ad2 --- /dev/null +++ b/src/app/components/programs/program-favorites.component.scss @@ -0,0 +1,11 @@ +.category { + margin-top: 10px; +} +:host ::ng-deep { + .p-datatable .p-datatable-header { + display: none; + } + .ep-desc { + display: none !important; + } +} diff --git a/src/app/components/programs/program-favorites.component.ts b/src/app/components/programs/program-favorites.component.ts new file mode 100644 index 0000000..2b17757 --- /dev/null +++ b/src/app/components/programs/program-favorites.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; +import { FavoriteChangedMessage } from 'src/app/messages/favorite-changed.message'; +import { ShowProgramDetailsMessage } from 'src/app/messages/show-programdetails.message'; +import { Program } from 'src/app/models/program'; +import { MessageBrokerService } from 'src/app/services/message-broker.service'; +import { ProgramsService } from 'src/app/services/programs.service'; + +@Component({ + selector: 'app-program-favorites', + templateUrl: './program-favorites.component.html', + styleUrls: ['./program-favorites.component.scss'] +}) +export class ProgramFavoritesComponent implements OnInit { + programs: Program[]; + totalHits = 0; + pageSize = 100; + private unsubscribe$ = new Subject(); + + constructor( + private readonly service: ProgramsService, + private readonly broker: MessageBrokerService + ) {} + + ngOnInit(): void { + const messages = this.broker.getMessage(); + messages + .pipe( + takeUntil(this.unsubscribe$), + filter((message) => message instanceof FavoriteChangedMessage) + ) + .subscribe((message: FavoriteChangedMessage) => { + this.fetch(); + }); + + this.fetch(); + } + + async fetch() { + this.programs = await this.service.fetchAllFavoritePrograms(); + } + + onProgramDetails(program: Program) { + this.broker.sendMessage(new ShowProgramDetailsMessage(program.id)); + } +} diff --git a/src/app/components/programs/programs-list.component.html b/src/app/components/programs/programs-list.component.html index 933389d..b25512c 100644 --- a/src/app/components/programs/programs-list.component.html +++ b/src/app/components/programs/programs-list.component.html @@ -1,21 +1,10 @@ + +
- -
- - - - - - - -
-
- + @@ -54,16 +43,9 @@ - - - - -
diff --git a/src/app/components/programs/programs-list.component.ts b/src/app/components/programs/programs-list.component.ts index 528bd49..3ccc851 100644 --- a/src/app/components/programs/programs-list.component.ts +++ b/src/app/components/programs/programs-list.component.ts @@ -10,6 +10,7 @@ import { MessageBrokerService } from 'src/app/services/message-broker.service'; import { SRApiService } from 'src/app/services/srapi.service'; import { TranslationService } from 'src/app/services/translation.service'; import { Program } from '../../models/program'; +import { ProgramsService } from 'src/app/services/programs.service'; @Component({ selector: 'app-programs-list', @@ -17,21 +18,22 @@ import { Program } from '../../models/program'; styleUrls: ['../common/datatable-styling.scss', './programs-list.component.scss'] }) export class ProgramsListComponent implements OnInit, OnDestroy, AfterViewInit { + totalHits = 0; + pageSize = 10; programs: Program[]; categoryOptions: SelectItem[]; private unsubscribe$ = new Subject(); private readonly storageId = 'ProgramsListState'; localState = { - showOnlyFavs: false, selectedCategory: null, - searchString: '' }; @ViewChild(Table) tableComponent: Table; constructor( private readonly srApiService: SRApiService, + private readonly programsService: ProgramsService, private readonly translationService: TranslationService, private readonly broker: MessageBrokerService, private readonly storage: LocalStorageService @@ -43,12 +45,6 @@ export class ProgramsListComponent implements OnInit, OnDestroy, AfterViewInit { this.localState = oldState; } - this.srApiService.programs$.pipe(takeUntil(this.unsubscribe$)).subscribe((values: Program[]) => { - if (values) { - this.programs = []; - this.programs.push(...values); - } - }); this.srApiService.programCategories$.pipe(takeUntil(this.unsubscribe$)).subscribe((values: ProgramCategory[]) => { if (values) { this.categoryOptions = []; @@ -57,24 +53,24 @@ export class ProgramsListComponent implements OnInit, OnDestroy, AfterViewInit { this.categoryOptions.push(...categories); } }); + + await this.fetch(0); + } + + async loadLazy(event: any) { + await this.fetch(event.first); } - ngAfterViewInit(): void { - if (this.tableComponent) { - if (this.localState.showOnlyFavs) { - this.tableComponent.filter(true, 'fav', 'equals'); - } else { - this.tableComponent.filter([true, false], 'fav', 'in'); - } + async fetch(first: number) { + const page = first / this.pageSize + 1; + let result = await this.programsService.fetchPrograms(page,this.pageSize, this.localState.selectedCategory); + this.totalHits = result.pagination.totalhits; + this.programs = result.programs; + } - if (this.localState.selectedCategory) { - this.tableComponent.filter(this.localState.selectedCategory, 'programcategory.id', 'equals'); - } - if (this.localState.searchString) { - this.tableComponent.filterGlobal(this.localState.searchString, 'contains'); - } - } + ngAfterViewInit(): void { + } ngOnDestroy() { @@ -83,30 +79,14 @@ export class ProgramsListComponent implements OnInit, OnDestroy, AfterViewInit { this.unsubscribe$.complete(); } - onShowEpisodes(program: Program) { + onProgramDetails(program: Program) { this.broker.sendMessage(new ShowProgramDetailsMessage(program.id)); } - onFilterFavClicked(event, dt) { - this.localState.showOnlyFavs = event.checked; - if (this.localState.showOnlyFavs) { - dt.filter(true, 'fav', 'equals'); - } else { - dt.filter([true, false], 'fav', 'in'); - } - } - - onAddToFavorites(programId: number, programName: string) { - this.srApiService.addProgramToFavorites(programId, programName); - } - - onRemoveFromFavorites(programId: number, programName: string) { - this.srApiService.removeProgramFromFavorites(programId, programName); - } onCategoryChanged(event, dt) { if (event.value !== '') { - dt.filter(event.value, 'programcategory.id', 'equals'); + dt.filter(event.value); } } } diff --git a/src/app/messages/favorite-changed.message.ts b/src/app/messages/favorite-changed.message.ts new file mode 100644 index 0000000..5ea20c6 --- /dev/null +++ b/src/app/messages/favorite-changed.message.ts @@ -0,0 +1,15 @@ +import { Message } from './message'; + +export class FavoriteChangedMessage extends Message { + programId: number; + isFavorite: boolean; + constructor(programId: number, isFavorite: boolean) { + super(); + this.programId = programId; + this.isFavorite = isFavorite; + } + + get Type(): string { + return 'FavoriteChangedMessage'; + } +} diff --git a/src/app/models/programs-result.ts b/src/app/models/programs-result.ts new file mode 100644 index 0000000..391cfea --- /dev/null +++ b/src/app/models/programs-result.ts @@ -0,0 +1,13 @@ +import { Program } from './program'; + +export interface ProgramsResult { + programs: Program[]; + pagination: { + page: number; + size: number; + totalhits: number; + totalpages: number; + nextpage: string; + previouspage: string; + }; +} diff --git a/src/app/services/episodes.service.ts b/src/app/services/episodes.service.ts index a3b654b..3454efb 100644 --- a/src/app/services/episodes.service.ts +++ b/src/app/services/episodes.service.ts @@ -40,7 +40,7 @@ export class EpisodesService extends SRBaseService { } if (res.episode?.episodegroups) { res.episode.episodegroups.forEach(async eg => { - let eps = await this.fetchEpisodesByGroup(eg.id,1,10); + let eps = await this.fetchEpisodesByGroup(eg.id, 1, 10); eg.episodes = eps; }) } diff --git a/src/app/services/programs.service.ts b/src/app/services/programs.service.ts new file mode 100644 index 0000000..682c445 --- /dev/null +++ b/src/app/services/programs.service.ts @@ -0,0 +1,76 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { SRBaseService } from './sr-base.service'; +import { SRApiService } from './srapi.service'; +import { lastValueFrom } from 'rxjs'; +import { ProgramsResult } from '../models/programs-result'; +import { Program } from '../models/program'; + +@Injectable({ + providedIn: 'root' +}) +export class ProgramsService extends SRBaseService { + constructor(private readonly http: HttpClient, private readonly srApiService: SRApiService) { + super(); + } + + async fetchPrograms(page: number, pageSize: number, categoryId: number): Promise { + let url = `${this.BaseUrl}programs/?${this.FormatParam}&page=${page}&size=${pageSize}`; + if (categoryId) { + url = `${url}&programcategoryid=${categoryId}`; + } + const res = await lastValueFrom(this.http.get(`${url}`)); + + const progs: Program[] = res.programs.map((p: Program) => ({ + name: p.name, + id: p.id, + fav: false, + channel: { + id: p?.channel.id, + name: p?.channel.name + }, + programimage: p.programimagetemplate + SRApiService.DefaultImagePreset, + description: p.description, + programcategory: p.programcategory + })); + + res.programs = progs; + + return res; + } + + async fetchProgramWithId(programId: number): Promise { + let url = `${this.BaseUrl}programs/${programId}?${this.FormatParam}`; + const res = await lastValueFrom(this.http.get(`${url}`)); + const p = res.program; + + const prog: any = { + name: p.name, + id: p.id, + fav: this.srApiService.hasFavMarker(p.id), + channel: { + id: p?.channel.id, + name: p?.channel.name + }, + programimage: p.programimagetemplate + SRApiService.DefaultImagePreset, + description: p.description, + programcategory: p.programcategory + }; + + return prog; + } + + async fetchAllFavoritePrograms(): Promise { + let programFavIds = this.srApiService.getProgramFavorites(); + let programs: Program[] = []; + programFavIds.forEach( async id => { + let program = await this.fetchProgramWithId(id); + if (program) { + programs.push(program) + } + }); + + return programs; + } + +} diff --git a/src/app/services/srapi.service.ts b/src/app/services/srapi.service.ts index fc4aea1..7db3002 100644 --- a/src/app/services/srapi.service.ts +++ b/src/app/services/srapi.service.ts @@ -2,7 +2,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { BehaviorSubject, lastValueFrom } from 'rxjs'; import { BookmarkChangedMessage } from '../messages/bookmark-changed.message'; -import { SuccessInfoMessage } from '../messages/success-info.message'; import { Channel } from '../models/channel'; import { Program } from '../models/program'; import { ProgramCategory } from '../models/program-category'; @@ -10,6 +9,8 @@ import { LocalStorageService } from './local-storage.service'; import { MessageBrokerService } from './message-broker.service'; import { SRBaseService } from './sr-base.service'; import { TranslationService } from './translation.service'; +import { SuccessInfoMessage } from '../messages/success-info.message'; +import { FavoriteChangedMessage } from '../messages/favorite-changed.message'; @Injectable({ providedIn: 'root' @@ -17,8 +18,6 @@ import { TranslationService } from './translation.service'; export class SRApiService extends SRBaseService { private channels: Channel[]; channels$ = new BehaviorSubject(null); - private programs: Program[]; - programs$ = new BehaviorSubject(null); private programCategories: ProgramCategory[]; programCategories$ = new BehaviorSubject(null); @@ -32,8 +31,8 @@ export class SRApiService extends SRBaseService { constructor( private readonly http: HttpClient, private readonly localStorageService: LocalStorageService, - private readonly broker: MessageBrokerService, - private readonly translationService: TranslationService + private readonly translationService: TranslationService, + private readonly broker: MessageBrokerService ) { super(); this.initFavoritesFromLocalStorage(); @@ -42,7 +41,6 @@ export class SRApiService extends SRBaseService { async fetchBaseData() { await this.fetchChannelsBaseData(); - await this.fetchBaseProgramsData(); await this.fetchBaseProgramCategoriesData(); this.baseDataFetched = true; } @@ -72,24 +70,6 @@ export class SRApiService extends SRBaseService { this.channels$.next(this.channels); } - private async fetchBaseProgramsData() { - const programsRawResult = await this.getAllPrograms(); - const progs: Program[] = programsRawResult.programs.map((p: Program) => ({ - name: p.name, - id: p.id, - fav: false, - channel: { - id: p?.channel.id, - name: p?.channel.name - }, - programimage: p.programimagetemplate + SRApiService.DefaultImagePreset, - description: p.description, - programcategory: p.programcategory - })); - - this.updateProgramsWithFavs(progs); - } - private async fetchBaseProgramCategoriesData() { const categoriesRawResult = await this.getAllProgramCategories(); this.programCategories = categoriesRawResult.programcategories.map((r) => ({ @@ -105,11 +85,6 @@ export class SRApiService extends SRBaseService { return lastValueFrom(this.http.get(`${url}`)); } - private async getAllPrograms(): Promise { - const params = `?${this.FormatParam}&page=1&size=10000`; - let url = `${this.BaseUrl}programs/${params}`; - return lastValueFrom(this.http.get(`${url}`)); - } private async getAllProgramCategories(): Promise { const params = `?${this.FormatParam}&page=1&size=10000`; let url = `${this.BaseUrl}programcategories/${params}`; @@ -128,30 +103,6 @@ export class SRApiService extends SRBaseService { return category?.name; } - getProgramImageUrlFromId(programId: number): string { - if (!this.programs) return; - const program = this?.programs.find((c) => c.id === programId); - return program?.programimage; - } - - addProgramToFavorites(programId: number, programName: string) { - if (!this.programFavs.has(programId)) { - this.programFavs.add(programId); - this.storeFavsInLocalStorage(); - this.updateProgramsWithFavs(this.programs); - this.broker.sendMessage(new SuccessInfoMessage(this.translationService.translateWithArgs('AddedToFavorites', programName))); - } - } - - removeProgramFromFavorites(programId: number, programName: string) { - if (this.programFavs.has(programId)) { - this.programFavs.delete(programId); - this.storeFavsInLocalStorage(); - this.updateProgramsWithFavs(this.programs); - this.broker.sendMessage(new SuccessInfoMessage(this.translationService.translateWithArgs('RemovedFromFavorites', programName))); - } - } - addBookmarkForEpisode(episodeId: number) { if (!this.episodeBookmarks.has(episodeId)) { this.episodeBookmarks.add(episodeId); @@ -172,17 +123,18 @@ export class SRApiService extends SRBaseService { return Array.from(this.episodeBookmarks); } + getProgramFavorites(): number[] { + return Array.from(this.programFavs); + } + isEpisodeBookmarked(episodeId: number): boolean { return this.episodeBookmarks.has(episodeId); } - async getProgramFromId(programId: number): Promise { - if (!this.baseDataFetched) { - await this.fetchBaseData(); - } - - const program = this.programs.find((p) => p.id === programId); - return program; + getChannelImageUrlFromId(channelId: number): string { + if (!this.channels) return; + const channel = this?.channels.find((c) => c.id === channelId); + return channel?.image; } async getChannelFromId(channelId: number): Promise { @@ -194,13 +146,45 @@ export class SRApiService extends SRBaseService { return channel; } - private updateProgramsWithFavs(progs: Program[]) { - progs.forEach((p) => (p.fav = this.programFavs.has(p.id))); - progs.sort((a: { name: string }, b: { name: any }) => { - return a.name.localeCompare(b.name); - }); - this.programs = progs; - this.programs$.next(this.programs); + private initBookmarksFromLocalStorage() { + const bookmarksArrayStr = this.localStorageService.get('episodeBookmarks'); + if (bookmarksArrayStr) { + try { + const bookmarksArray: [] = JSON.parse(bookmarksArrayStr); + if (bookmarksArray) { + bookmarksArray.forEach((f) => { + this.episodeBookmarks.add(f); + }); + } + } catch { } + } + } + + private storeBookmarksInLocalStorage() { + let serializedSet = JSON.stringify(Array.from(this.episodeBookmarks)); + this.localStorageService.set('episodeBookmarks', serializedSet); + } + + addProgramToFavorites(programId: number, programName: string) { + if (!this.programFavs.has(programId)) { + this.programFavs.add(programId); + this.storeFavsInLocalStorage(); + this.broker.sendMessage(new FavoriteChangedMessage(programId, true)); + this.broker.sendMessage(new SuccessInfoMessage(this.translationService.translateWithArgs('AddedToFavorites', programName))); + } + } + + removeProgramFromFavorites(programId: number, programName: string) { + if (this.programFavs.has(programId)) { + this.programFavs.delete(programId); + this.storeFavsInLocalStorage(); + this.broker.sendMessage(new FavoriteChangedMessage(programId, false)); + this.broker.sendMessage(new SuccessInfoMessage(this.translationService.translateWithArgs('RemovedFromFavorites', programName))); + } + } + + hasFavMarker(programId: number): boolean { + return this.programFavs.has(programId); } private initFavoritesFromLocalStorage() { @@ -213,7 +197,7 @@ export class SRApiService extends SRBaseService { this.programFavs.add(f); }); } - } catch {} + } catch { } } } @@ -221,23 +205,4 @@ export class SRApiService extends SRBaseService { let serializedSet = JSON.stringify(Array.from(this.programFavs)); this.localStorageService.set('programfavs', serializedSet); } - - private initBookmarksFromLocalStorage() { - const bookmarksArrayStr = this.localStorageService.get('episodeBookmarks'); - if (bookmarksArrayStr) { - try { - const bookmarksArray: [] = JSON.parse(bookmarksArrayStr); - if (bookmarksArray) { - bookmarksArray.forEach((f) => { - this.episodeBookmarks.add(f); - }); - } - } catch {} - } - } - - private storeBookmarksInLocalStorage() { - let serializedSet = JSON.stringify(Array.from(this.episodeBookmarks)); - this.localStorageService.set('episodeBookmarks', serializedSet); - } } diff --git a/src/app/translations/res-en.json b/src/app/translations/res-en.json index 02d96ad..05a0c8b 100644 --- a/src/app/translations/res-en.json +++ b/src/app/translations/res-en.json @@ -56,5 +56,6 @@ "AudioPrefixEpisode": "Episode", "LinkToProgramDetailsText": "Show details and all episodes for ", "ShowOnlyCurrentAndFuture": "Show only current and upcoming", - "Categories": "Categories" + "Categories": "Categories", + "Favorites": "Favorites" } diff --git a/src/app/translations/res-sv.json b/src/app/translations/res-sv.json index 52b7e71..f959284 100644 --- a/src/app/translations/res-sv.json +++ b/src/app/translations/res-sv.json @@ -56,5 +56,6 @@ "AudioPrefixEpisode": "Avsnitt", "LinkToProgramDetailsText": "Visa detaljer och alla avsnitt för ", "ShowOnlyCurrentAndFuture": "Visa bara pågående och kommande", - "Categories": "Kategorier" + "Categories": "Kategorier", + "Favorites": "Favoriter" }