Skip to content

Commit

Permalink
feat(settings): refactor settings management and add store service
Browse files Browse the repository at this point in the history
Refactor the settings management in the SettingsComponent to utilize a new
SettingsStore service for better state management. Remove direct local
storage access and replace it with a method to retrieve settings from the
store. Update the backToHome method to handle dialog navigation. Add
error logging for file reading issues and introduce an input property to
determine dialog context.
  • Loading branch information
4gray committed Nov 28, 2024
1 parent 05f2ca1 commit e9a698a
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 64 deletions.
51 changes: 51 additions & 0 deletions src/app/services/settings-store.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Injectable, computed, signal } from '@angular/core';
import { StorageMap } from '@ngx-pwa/local-storage';
import { Language } from '../settings/language.enum';
import { Settings, VideoPlayer } from '../settings/settings.interface';
import { Theme } from '../settings/theme.enum';
import { STORE_KEY } from '../shared/enums/store-keys.enum';

const DEFAULT_SETTINGS: Settings = {
player: VideoPlayer.VideoJs,
language: Language.ENGLISH,
showCaptions: false,
theme: Theme.LightTheme,
mpvPlayerPath: '',
vlcPlayerPath: '',
remoteControl: false,
remoteControlPort: 3000,
epgUrl: [],
};

@Injectable({
providedIn: 'root',
})
export class SettingsStore {
private settings = signal<Settings>(DEFAULT_SETTINGS);

// Computed values for commonly used settings
readonly player = computed(() => this.settings().player);
readonly showCaptions = computed(() => this.settings().showCaptions);
readonly theme = computed(() => this.settings().theme);

constructor(private storage: StorageMap) {
this.loadSettings();
}

async loadSettings() {
const stored = await this.storage.get(STORE_KEY.Settings).toPromise();
if (stored) {
this.settings.set({ ...DEFAULT_SETTINGS, ...(stored as Settings) });
}
}

async updateSettings(settings: Partial<Settings>) {
const newSettings = { ...this.settings(), ...settings };
this.settings.set(newSettings);
await this.storage.set(STORE_KEY.Settings, newSettings).toPromise();
}

getSettings() {
return this.settings;
}
}
20 changes: 12 additions & 8 deletions src/app/settings/settings.component.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<app-header
[title]="'SETTINGS.TITLE' | translate"
[subtitle]="
('SETTINGS.SUBTITLE' | translate) +
'. ' +
('SETTINGS.DESCRIPTION' | translate)
"
></app-header>
@if (!isDialog) {
<app-header
[title]="'SETTINGS.TITLE' | translate"
[subtitle]="
('SETTINGS.SUBTITLE' | translate) +
'. ' +
('SETTINGS.DESCRIPTION' | translate)
"
/>
} @else {
<h2 mat-dialog-title>{{ 'SETTINGS.TITLE' | translate }}</h2>
}

<div class="settings-container" data-test-id="settings-container">
<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()" novalidate>
Expand Down
103 changes: 47 additions & 56 deletions src/app/settings/settings.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-base-to-string */
import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { Component, Inject, Input, OnInit, Optional } from '@angular/core';
import {
FormArray,
FormBuilder,
Expand All @@ -10,6 +11,11 @@ import {
} from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import {
MAT_DIALOG_DATA,
MatDialog,
MatDialogModule,
} from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
Expand All @@ -31,13 +37,13 @@ import { DataService } from '../services/data.service';
import { DialogService } from '../services/dialog.service';
import { EpgService } from '../services/epg.service';
import { PlaylistsService } from '../services/playlists.service';
import { SettingsStore } from '../services/settings-store.service';
import { HeaderComponent } from '../shared/components/header/header.component';
import { STORE_KEY } from '../shared/enums/store-keys.enum';
import * as PlaylistActions from '../state/actions';
import { selectIsEpgAvailable } from '../state/selectors';
import { SettingsService } from './../services/settings.service';
import { Language } from './language.enum';
import { Settings, VideoPlayer } from './settings.interface';
import { VideoPlayer } from './settings.interface';
import { Theme } from './theme.enum';

@Component({
Expand All @@ -57,9 +63,11 @@ import { Theme } from './theme.enum';
MatTooltipModule,
ReactiveFormsModule,
TranslateModule,
MatDialogModule,
],
})
export class SettingsComponent implements OnInit {
@Input() isDialog = false;
/** List with available languages as enum */
languageEnum = Language;

Expand Down Expand Up @@ -135,8 +143,13 @@ export class SettingsComponent implements OnInit {
private settingsService: SettingsService,
private snackBar: MatSnackBar,
private store: Store,
private translate: TranslateService
) {}
private translate: TranslateService,
private matDialog: MatDialog,
private settingsStore: SettingsStore,
@Optional() @Inject(MAT_DIALOG_DATA) data?: { isDialog: boolean }
) {
this.isDialog = data?.isDialog ?? false;
}

/**
* Reads the config object from the browsers
Expand All @@ -151,34 +164,12 @@ export class SettingsComponent implements OnInit {
* Sets saved settings from the indexed db store
*/
setSettings(): void {
this.settingsService
.getValueFromLocalStorage(STORE_KEY.Settings)
.subscribe((settings: Settings) => {
if (settings) {
try {
this.settingsForm.setValue({
player: settings.player
? settings.player
: VideoPlayer.VideoJs,
...(this.isTauri ? { epgUrl: [] } : {}),
language: settings.language ?? Language.ENGLISH,
showCaptions: settings.showCaptions ?? false,
theme: settings.theme ?? Theme.LightTheme,
mpvPlayerPath: settings.mpvPlayerPath ?? '',
vlcPlayerPath: settings.vlcPlayerPath ?? '',
remoteControl: settings.remoteControl ?? false,
remoteControlPort:
settings.remoteControlPort ?? 3000,
});
} catch (error) {
throw new Error(error);
}
const currentSettings = this.settingsStore.getSettings()();
this.settingsForm.patchValue(currentSettings);

if (this.isTauri) {
this.setEpgUrls(settings.epgUrl);
}
}
});
if (this.isTauri && currentSettings.epgUrl) {
this.setEpgUrls(currentSettings.epgUrl);
}
}

/**
Expand Down Expand Up @@ -247,31 +238,26 @@ export class SettingsComponent implements OnInit {
* the indexed db store
*/
onSubmit(): void {
this.settingsService
.setValueToLocalStorage(
STORE_KEY.Settings,
this.settingsForm.value,
true
)
.pipe(take(1))
.subscribe(() => {
this.applyChangedSettings();
});

this.electronService.sendIpcEvent(
SETTINGS_UPDATE,
this.settingsForm.value
);
this.settingsStore.updateSettings(this.settingsForm.value).then(() => {
this.applyChangedSettings();
this.electronService.sendIpcEvent(
SETTINGS_UPDATE,
this.settingsForm.value
);

this.electronService.sendIpcEvent(
SET_MPV_PLAYER_PATH,
this.settingsForm.value.mpvPlayerPath
);
this.electronService.sendIpcEvent(
SET_MPV_PLAYER_PATH,
this.settingsForm.value.mpvPlayerPath
);

this.electronService.sendIpcEvent(
SET_VLC_PLAYER_PATH,
this.settingsForm.value.mpvPlayerPath
);
this.electronService.sendIpcEvent(
SET_VLC_PLAYER_PATH,
this.settingsForm.value.mpvPlayerPath
);
});
if (this.isDialog) {
this.matDialog.closeAll();
}
}

/**
Expand Down Expand Up @@ -308,7 +294,11 @@ export class SettingsComponent implements OnInit {
* Navigates back to the applications homepage
*/
backToHome(): void {
this.router.navigateByUrl('/');
if (this.isDialog) {
this.matDialog.closeAll();
} else {
this.router.navigateByUrl('/');
}
}

/**
Expand Down Expand Up @@ -394,6 +384,7 @@ export class SettingsComponent implements OnInit {
duration: 2000,
}
);
console.error(error);
}
};
reader.readAsText(file);
Expand Down

0 comments on commit e9a698a

Please sign in to comment.