src/app/services/context/context.service.ts
import { EventEmitter, Injectable } from '@angular/core';
import { Context } from '../../interfaces/context/context';
import { ContextConfiguration } from '../../interfaces/context/context-configuration';
import { NavState } from '../../enums/nav-state';
import { PersistenceService } from '../persistence/persistence.service';
import { UiService } from '../ui/ui.service';
import { StringExService } from '../string-ex/string-ex.service';
/**
* Context service.
*/
@Injectable({
providedIn: 'root'
})
export class ContextService {
/** Persistence key. */
private get persistenceKey() {
return {
contexts: 'contexts',
selectedContext: 'selectedContext',
};
}
/* Contexts. */
#contexts?: Context[];
/* Contexts getter. */
public get contexts() {
// cache the get's
if (this.#contexts) { return this.#contexts; }
// retrieve the value
const value = JSON.parse(this.persistenceService.getItem(this.persistenceKey.contexts) ?? JSON.stringify([this.emptyContext]));
// cache the value retrieved
this.#contexts = value;
// return the value
return value;
}
/* Contexts setter. */
public set contexts(value: Context[]) {
// cache the value to store
this.#contexts = value;
// store the value
if (value) {
this.persistenceService.setItem(this.persistenceKey.contexts, JSON.stringify(value));
}
}
/** Empty context. */
private readonly emptyContext = { id: 0, name: '', storage: {} as Storage };
/** Selected context getter. */
public get selectedContext() {
// serialize as id
const selectedContext = this.persistenceService.getItem(this.persistenceKey.selectedContext);
if (!selectedContext) { return undefined; }
const selectedContextId = Number.parseInt(selectedContext, 10);
const context = this.contexts.find((_) => _.id === selectedContextId);
return context;
}
/** Selected context setter. */
public set selectedContext(value: Context | undefined) {
// save context
this.copyStorage(this.persistenceService.storage, this.selectedContext?.storage);
// serialize as id
if (typeof value === 'undefined') {
this.persistenceService.removeItem(this.persistenceKey.selectedContext);
} else {
this.persistenceService.setItem(this.persistenceKey.selectedContext, value.id.toString());
}
// persist contexts
this.contexts = this.contexts;
// retrieve context
this.copyStorage(value?.storage, this.persistenceService.storage);
}
/** Whether context switcher is in editing mode. */
public isEditing = false;
/** Nav state "context state" persistence key. */
public readonly navStatePersistenceKey = 'navState';
/** Nav state getter. */
public get navState() {
return Number.parseInt(this.persistenceService.getItem(this.navStatePersistenceKey) ?? NavState.Closed.toString(), 10);
}
/** Nav state setter. */
public set navState(value) {
this.persistenceService.setItem(this.navStatePersistenceKey, value.toString());
// emit change event
const navStateConfiguration = this.navStateConfigurations[this.navState];
this.navStateChanged$.emit(navStateConfiguration);
}
/** Nav state changed event emitter. */
public readonly navStateChanged$ = new EventEmitter<ContextConfiguration>();
/** Nav state configurations */
public get navStateConfigurations(): ContextConfiguration[] {
return [
{ width: '10px', backgroundColor: 'rgba(0,0,0,0)', name: () => '' },
{ width: '350px', backgroundColor: 'rgba(0,0,0,0.2)', name: (item: Context) => item.name },
{ width: '100px', backgroundColor: 'rgba(0,0,0,0.1)', name: (item: Context) => StringExService.glyph(item.name) },
];
}
/**
* Constructs the entities service.
* ~constructor
*
* @param uiService The ui service injected dependency.
* @param persistenceService The persistence service injected dependency.
*/
constructor(
public readonly uiService: UiService,
public readonly persistenceService: PersistenceService,
) {
}
/** Context comparer. */
public contextEquals(context1?: Context, context2?: Context) {
return context1?.id === context2?.id;
}
/** Copy relevant storage between switcher and persistence */
private copyStorage(source?: Storage, destination?: Storage) {
if (typeof source !== 'undefined') {
const { contexts, selectedContext, navState, ...serializabeStorage } = source;
if (typeof destination !== 'undefined') {
Object.entries(serializabeStorage).forEach((entry) => {
destination[entry[0]] = entry[1];
});
}
}
}
/** Get context caption */
public getCaption(item: Context) {
const name = this.navStateConfigurations[this.navState].name(item) || '‣';
return this.contextEquals(item, this.selectedContext) ? name.toUpperCase() : name;
}
/** Get context tooltip title */
public getTitle(item: Context) {
let title = '';
if (!this.isEditing) {
title += this.navStateConfigurations[NavState.Open].name(item);
if (this.navState === NavState.Open) {
title += '\n\n' + this.uiService.uiText('Click to edit.');
}
}
return title;
}
}