I have injected a service named muzikService
in another service named authenticationService
.
when I call loadDirectories
method from muzikService
in authenticationService
, it errs loadDirectories
is undefined. I have no problem when I build the app for production and I have used muzikService
in other components and it works fine and the loadDirectories
method is defined.
muzikService
import { EventEmitter, Inject, Injectable, OnDestroy } from '@angular/core';
import { MuzikSong } from '../interfaces/muzik-song.interface';
import { HttpClient } from '@angular/common/http';
import { Subscription } from 'rxjs';
import { FolderPath } from '../interfaces/folder-path.interface';
import { LocalSong } from '../interfaces/local-song.interface';
import { lastValueFrom } from 'rxjs/internal/lastValueFrom';
import { forkJoin } from 'rxjs/internal/observable/forkJoin';
import { AuthenticationService } from './authentication.service';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class MuzikService implements OnDestroy {
constructor(
@Inject('BACKEND_URL') private readonly BACKEND_URL: string,
private readonly http: HttpClient,
private readonly authService: AuthenticationService,
private readonly router: Router
) {
this.authService.checkToken().subscribe((value) => {
console.info(value);
if (value) this.loadDirectories();
else this.router.navigate(['auth']);
});
this.$subs$.push(
...[
this.setPlayingSong$.subscribe((value) => {
this.playingSong = value;
if (!this.playList.find((song) => song._id == value._id))
this.playList = [...this.playList, value];
}),
this.addSongToList$.subscribe((value) => {
if (!this.playList.find((song) => song._id == value._id))
this.playList = [...this.playList, value];
}),
this.removeSongFromList$.subscribe((value) => {
this.playList.splice(
this.playList.findIndex((song) => song._id == value._id),
1
);
if (this.playList.length) {
if (this.playingSong?._id == value._id) this.nextSong$.emit();
} else this.playingSong = null;
}),
]
);
}
setPlayingSong$ = new EventEmitter<MuzikSong>(false);
addSongToList$ = new EventEmitter<MuzikSong>(false);
removeSongFromList$ = new EventEmitter<MuzikSong>(false);
playSong$ = new EventEmitter<void>(false);
pauseSong$ = new EventEmitter<void>(false);
nextSong$ = new EventEmitter<void>(false);
previousSong$ = new EventEmitter<void>(false);
toggleRepeat$ = new EventEmitter<void>(false);
toggleShuffle$ = new EventEmitter<void>(false);
toggleFavorite$ = new EventEmitter<void>(false);
muteSlider$ = new EventEmitter<void>(false);
PLAYING_SONG_STATE: 'PLAYING' | 'PAUSED' | 'LOADING' = 'PAUSED';
REPEATE_STATE: 'NO_LOOP' | 'LOOP_ALL' | 'LOOP_ONE' = 'NO_LOOP';
VOLUBLE: boolean = true;
$subs$: Subscription[] = [];
folderPaths: FolderPath[] = [];
playingSong?: MuzikSong | null;
playList: MuzikSong[] = [];
allSongs: MuzikSong[] = [];
recentlyAddedSongs: MuzikSong[] = [];
favoriteSongs: MuzikSong[] = [];
mostPlayedSongs: MuzikSong[] = [];
audioCurrentTime: number | string = 0;
audioDuration: number = 0;
volume: number = 1;
getFavoriteSongs() {}
favoriteSong(id: string) {
return this.http.patch<MuzikSong>(this.BACKEND_URL + '/favorite', id);
}
unfavoriteSong(id: string) {
return this.http.patch<MuzikSong>(this.BACKEND_URL + '/unfavorite', id);
}
getDirectories() {
return this.http.get<FolderPath[]>(this.BACKEND_URL + '/folder-paths');
}
getSongs() {
return this.http.get<MuzikSong[]>(this.BACKEND_URL + '/songs');
}
loadDirectories() {
this.getDirectories().subscribe(async (folderPaths) => {
this.folderPaths = folderPaths;
if (folderPaths.length) {
Promise.all([
this.loadSavedSongs(),
lastValueFrom(this.getSongs()),
]).then(([localSongs, savedSongs]) => {
const newSongs = savedSongs.filter(
(savedSong) =>
!localSongs.find((localSong) => savedSong.file === localSong.file)
);
if (newSongs.length) {
this.saveSongs(newSongs).subscribe((savedSongs) => {
for (const song of savedSongs) {
const { image }: LocalSong = localSongs.find(
(s) => s.file == song.file
);
if (image) song.image = image;
}
this.recentlyAddedSongs = [
...savedSongs,
...this.recentlyAddedSongs,
];
this.allSongs = [...savedSongs, ...this.allSongs];
});
}
for (const savedSong of savedSongs)
savedSong.image =
localSongs.find((localSong) => localSong.file == savedSong.file)
?.image ?? '';
this.allSongs = [...savedSongs, ...this.allSongs];
console.info('folderPaths', this.folderPaths);
console.info('savedSongs', savedSongs);
console.info('localSongs', localSongs);
this.router.navigate(['']);
});
} else this.router.navigate(['select-directory']);
});
}
loadSavedSongs() {
return window.electronAPI.loadDirectories(
this.folderPaths.map((path) => path.path)
);
}
saveSongs(songs: LocalSong[]) {
return this.http.post<MuzikSong[]>(
this.BACKEND_URL + '/local-songs',
songs.map(({ title, artist, file }) => {
return { type: 'SINGLE', title, artist, file };
})
);
}
saveDirectory(directory: string) {
return this.http.post<FolderPath>(
this.BACKEND_URL + '/local-directory',
directory
);
}
async promptUserToSelectFolder() {
const { directory, songs } = await window.electronAPI.selectDirectory();
forkJoin([this.saveSongs(songs), this.saveDirectory(directory)]).subscribe(
([savedSongs, savedDirectory]) => {
for (const song of savedSongs) {
const { image }: LocalSong = songs.find((s) => s.file == song.file);
if (image) song.image = image;
}
this.recentlyAddedSongs = [...savedSongs, ...this.recentlyAddedSongs];
this.folderPaths = [...this.folderPaths, savedDirectory];
this.router.navigate(['']);
}
);
}
ngOnDestroy(): void {
for (const sub of this.$subs$) sub.unsubscribe();
}
}
authenticationService
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { User } from '../interfaces/user.interface';
import { MuzikService } from './muzik.service';
@Injectable({
providedIn: 'root',
})
export class AuthenticationService {
constructor(
@Inject('BACKEND_URL') private readonly BACKEND_URL: string,
private readonly http: HttpClient,
private readonly muzikService: MuzikService
) {}
userInfo?: User;
checkToken() {
return this.http.get<boolean>(this.BACKEND_URL + '/check-token');
}
createUser(userInfo: {
firstName?: string;
lastName?: string;
email?: string;
password?: string;
}) {
return this.http.post<User>(this.BACKEND_URL + '/create-user', userInfo);
}
logIn(logInInfo: { email?: string; password?: string }) {
this.http
.post<User | null>(this.BACKEND_URL + '/user-log-in', logInInfo)
.subscribe((value) => {
if (value) {
this.userInfo = value;
this.muzikService.loadDirectories();
}
});
}
}
when I call loadDirectories
in logIn
method it errs loadDirectories
is undefined.
I have injected muzikService
in authenticationService
and I expect all public methods and properties of muzikService
be available in authenticationService
.