mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 08:33:11 +00:00
refactor: move SettingsProvider into package 'settings'
This commit is contained in:
@@ -21,7 +21,7 @@ import {
|
||||
SCSetting,
|
||||
SCSettingMeta,
|
||||
} from '@openstapps/core';
|
||||
import {SettingsProvider} from '../../settingsProvider/settings.provider';
|
||||
import {SettingsProvider} from '../settings.provider';
|
||||
|
||||
@Component({
|
||||
selector: 'stapps-settings-item',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
@@ -15,7 +15,7 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
||||
import {SCLanguageName, SCSettingMeta} from '@openstapps/core';
|
||||
import {SettingsCache, SettingsProvider} from '../../settingsProvider/settings.provider';
|
||||
import {SettingsCache, SettingsProvider} from '../settings.provider';
|
||||
|
||||
@Component({
|
||||
selector: 'stapps-settings-page',
|
||||
|
||||
@@ -22,6 +22,7 @@ import {TranslateModule} from '@ngx-translate/core';
|
||||
|
||||
import {SettingsItemComponent} from './item/settings-item.component';
|
||||
import {SettingsPageComponent} from './page/settings-page.component';
|
||||
import {SettingsProvider} from './settings.provider';
|
||||
|
||||
const settingsRoutes: Routes = [
|
||||
{ path: 'settings', component: SettingsPageComponent },
|
||||
@@ -41,6 +42,7 @@ const settingsRoutes: Routes = [
|
||||
],
|
||||
providers: [
|
||||
Geolocation,
|
||||
SettingsProvider,
|
||||
],
|
||||
})
|
||||
export class SettingsModule {}
|
||||
|
||||
349
src/app/modules/settings/settings.provider.spec.ts
Normal file
349
src/app/modules/settings/settings.provider.spec.ts
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {SCSetting} from '@openstapps/core';
|
||||
import {StorageModule} from '../storage/storage.module';
|
||||
import {StorageProvider} from '../storage/storage.provider';
|
||||
import {SettingsProvider} from './settings.provider';
|
||||
|
||||
describe('SettingsProvider', () => {
|
||||
let settingsProvider: SettingsProvider;
|
||||
let storageModule: StorageProvider;
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [StorageModule],
|
||||
providers: [SettingsProvider, StorageProvider],
|
||||
});
|
||||
settingsProvider = TestBed.get(SettingsProvider);
|
||||
storageModule = TestBed.get(StorageProvider);
|
||||
|
||||
settingsProvider.clear();
|
||||
});
|
||||
|
||||
it('should provide and get setting', async () => {
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
const setting = await settingsProvider.getSetting(SETTING_MOCKS[0].categories[0], SETTING_MOCKS[0].name);
|
||||
await expect(setting).toBeDefined();
|
||||
});
|
||||
|
||||
it('should provide and get settings value', async () => {
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
const value = await settingsProvider.getSettingValue(SETTING_MOCKS[0].categories[0], SETTING_MOCKS[0].name);
|
||||
await expect(value).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set value of a provided setting', async () => {
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
await settingsProvider.setSettingValue(SETTING_MOCKS[0].categories[0], SETTING_MOCKS[0].name, 'updated');
|
||||
const value = await settingsProvider.getSettingValue(SETTING_MOCKS[0].categories[0], SETTING_MOCKS[0].name);
|
||||
await expect(value).toEqual('updated');
|
||||
});
|
||||
|
||||
it('should return copy of settingsCache', async () => {
|
||||
const category = SETTING_MOCKS[0].categories[0];
|
||||
const name = SETTING_MOCKS[0].name;
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
const settings = await settingsProvider.getSettingsCache();
|
||||
settings[category].settings[name].input.value = 'testValue';
|
||||
// cached setting value should still be defaultValue
|
||||
await expect((await settingsProvider.getSettingValue(category, name)))
|
||||
.toEqual(SETTING_MOCKS[0].input.defaultValue);
|
||||
});
|
||||
|
||||
it('should call storage put on provideSetting', async () => {
|
||||
spyOn(storageModule, 'put');
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
await expect(storageModule.put).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call storage put on setSettingValue', async () => {
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
spyOn(storageModule, 'put');
|
||||
await settingsProvider.setSettingValue(SETTING_MOCKS[0].categories[0], SETTING_MOCKS[0].name, '');
|
||||
await expect(storageModule.put).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clear settings', async () => {
|
||||
const category = SETTING_MOCKS[0].categories[0];
|
||||
const name = SETTING_MOCKS[0].name;
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
await settingsProvider.clear();
|
||||
const exists = await settingsProvider.settingExists(category, name);
|
||||
await expect(exists).toEqual(false);
|
||||
});
|
||||
|
||||
it('should reset settings', async () => {
|
||||
const category = SETTING_MOCKS[0].categories[0];
|
||||
const name = SETTING_MOCKS[0].name;
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(SETTING_MOCKS[0])));
|
||||
await settingsProvider.setSettingValue(category, name, 'guest');
|
||||
await settingsProvider.resetDefault();
|
||||
const value = await settingsProvider.getSettingValue(SETTING_MOCKS[0].categories[0], SETTING_MOCKS[0].name);
|
||||
await expect(value).toEqual(SETTING_MOCKS[0].input.defaultValue);
|
||||
});
|
||||
|
||||
it('should validate wrong values for inputType text', async () => {
|
||||
await testValue(SETTING_MOCKS[0], 123456789);
|
||||
await testValue(SETTING_MOCKS[0], false);
|
||||
await testValue(SETTING_MOCKS[0], []);
|
||||
});
|
||||
|
||||
it('should validate wrong values for inputType password', async () => {
|
||||
await testValue(SETTING_MOCKS[0], 123456789);
|
||||
await testValue(SETTING_MOCKS[0], false);
|
||||
await testValue(SETTING_MOCKS[0], []);
|
||||
});
|
||||
|
||||
it('should validate wrong values for inputType number', async () => {
|
||||
await testValue(SETTING_MOCKS[2], '');
|
||||
await testValue(SETTING_MOCKS[2], false);
|
||||
await testValue(SETTING_MOCKS[2], []);
|
||||
});
|
||||
|
||||
it('should validate wrong values for inputType singleChoice text', async () => {
|
||||
await testValue(SETTING_MOCKS[3], '');
|
||||
await testValue(SETTING_MOCKS[3], 123456);
|
||||
await testValue(SETTING_MOCKS[3], false);
|
||||
await testValue(SETTING_MOCKS[3], []);
|
||||
});
|
||||
|
||||
it('should validate wrong values for inputType singleChoice boolean', async () => {
|
||||
await testValue(SETTING_MOCKS[5], '');
|
||||
await testValue(SETTING_MOCKS[5], 123456);
|
||||
await testValue(SETTING_MOCKS[5], []);
|
||||
});
|
||||
|
||||
it('should validate wrong values for inputType multipleChoice', async () => {
|
||||
await testValue(SETTING_MOCKS[6], '');
|
||||
await testValue(SETTING_MOCKS[6], 123456);
|
||||
await testValue(SETTING_MOCKS[6], false);
|
||||
await testValue(SETTING_MOCKS[6], [1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
async function testValue(setting: SCSetting, value: any) {
|
||||
let error: Error;
|
||||
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(setting)));
|
||||
try {
|
||||
await settingsProvider.setSettingValue(setting.categories[0], setting.name, value);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
// @ts-ignore
|
||||
await expect(error).toBeDefined();
|
||||
// @ts-ignore
|
||||
await expect(error.message).toMatch(/Value.*not valid/);
|
||||
}
|
||||
|
||||
const SETTING_MOCKS: SCSetting[] = [
|
||||
{
|
||||
categories: ['credentials'],
|
||||
input: {
|
||||
defaultValue: '',
|
||||
inputType: 'text',
|
||||
},
|
||||
name: 'username',
|
||||
order: 0,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Anmeldedaten'],
|
||||
name: 'Benutzername',
|
||||
},
|
||||
en: {
|
||||
categories: ['Credentials'],
|
||||
name: 'Username',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
{
|
||||
categories: ['credentials'],
|
||||
description: '',
|
||||
input: {
|
||||
defaultValue: '',
|
||||
inputType: 'password',
|
||||
},
|
||||
name: 'password',
|
||||
order: 1,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Anmeldedaten'],
|
||||
name: 'Passwort',
|
||||
},
|
||||
en: {
|
||||
categories: ['Credentials'],
|
||||
name: 'Password',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
{
|
||||
categories: ['profile'],
|
||||
description: '',
|
||||
input: {
|
||||
defaultValue: 0,
|
||||
inputType: 'number',
|
||||
},
|
||||
name: 'age',
|
||||
order: 0,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Profil'],
|
||||
name: 'Alter',
|
||||
},
|
||||
en: {
|
||||
categories: ['Profile'],
|
||||
name: 'Age',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
{
|
||||
categories: ['profile'],
|
||||
description: '',
|
||||
input: {
|
||||
defaultValue: 'student',
|
||||
inputType: 'singleChoice',
|
||||
values: ['student', 'employee', 'guest'],
|
||||
},
|
||||
name: 'group',
|
||||
order: 1,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Benutzer'],
|
||||
description: 'Mit welcher Benutzergruppe soll die App verwendet werden?'
|
||||
+ ' Die Einstellung wird beispielsweise für die Vorauswahl der Preiskategorie der Mensa verwendet.',
|
||||
name: 'Gruppe',
|
||||
},
|
||||
en: {
|
||||
categories: ['User'],
|
||||
description: 'The user group the app is going to be used.'
|
||||
+ 'This settings for example is getting used for the predefined price category of mensa meals.',
|
||||
name: 'Group',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
{
|
||||
categories: ['profile'],
|
||||
description: '',
|
||||
input: {
|
||||
defaultValue: 'en',
|
||||
inputType: 'singleChoice',
|
||||
values: ['en', 'de'],
|
||||
},
|
||||
name: 'language',
|
||||
order: 0,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Benutzer'],
|
||||
description: 'Die Sprache in der die App angezeigt werden soll',
|
||||
name: 'Sprache',
|
||||
},
|
||||
en: {
|
||||
categories: ['User'],
|
||||
description: 'The language this app is going to use',
|
||||
name: 'Language',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
{
|
||||
categories: ['privacy'],
|
||||
description: '',
|
||||
input: {
|
||||
defaultValue: false,
|
||||
inputType: 'singleChoice',
|
||||
values: [true, false],
|
||||
},
|
||||
name: 'geoLocation',
|
||||
order: 0,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Privatsphäre'],
|
||||
description: 'Berechtigung für die Verwendung des Ortungsdienstes, für die Anzeige der aktuellen ' +
|
||||
'Position \'\n auf der Karte und zur Berechnung der Entfernung zu Gebäuden und Orten des Campus',
|
||||
name: 'Position',
|
||||
},
|
||||
en: {
|
||||
categories: ['Privacy'],
|
||||
description: 'Allow the App to use the device location to provide additional informationsbased ' +
|
||||
'on your actual location',
|
||||
name: 'Position',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
{
|
||||
categories: ['others'],
|
||||
description: '',
|
||||
input: {
|
||||
defaultValue: [],
|
||||
inputType: 'multipleChoice',
|
||||
values: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||
},
|
||||
name: 'numbers',
|
||||
order: 0,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'Dummy',
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
categories: ['Sonstiges'],
|
||||
description: 'Test für multiple select Feld',
|
||||
name: 'Nummern',
|
||||
},
|
||||
en: {
|
||||
categories: ['Others'],
|
||||
description: 'Test for multiple select field',
|
||||
name: 'Numbers',
|
||||
},
|
||||
},
|
||||
type: 'setting',
|
||||
uid: '',
|
||||
},
|
||||
];
|
||||
});
|
||||
297
src/app/modules/settings/settings.provider.ts
Normal file
297
src/app/modules/settings/settings.provider.ts
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Injectable} from '@angular/core';
|
||||
import {SCSetting, SCSettingMultipleChoice, SCSettingSingleChoice, SCSettingValue} from '@openstapps/core';
|
||||
import {StorageProvider} from '../storage/storage.provider';
|
||||
|
||||
export const STORAGE_KEY_SETTINGS = 'settings';
|
||||
export const STORAGE_KEY_SETTINGS_SEPARATOR = '.';
|
||||
export const STORAGE_KEY_SETTING_VALUES = STORAGE_KEY_SETTINGS + STORAGE_KEY_SETTINGS_SEPARATOR + 'values';
|
||||
|
||||
/**
|
||||
* Category structure of settings cache
|
||||
*/
|
||||
export interface CategoryWithSettings {
|
||||
category: string;
|
||||
settings: { [key: string]: SCSetting };
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure of SettingsCache
|
||||
*/
|
||||
export interface SettingsCache {
|
||||
[key: string]: CategoryWithSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider for app settings
|
||||
*/
|
||||
@Injectable()
|
||||
export class SettingsProvider {
|
||||
private categoriesOrder: string[];
|
||||
private initialized = false;
|
||||
private settingsCache: SettingsCache;
|
||||
|
||||
/**
|
||||
* Return true if all given values are valid to possible values in given settingInput
|
||||
* @param settingInput
|
||||
* @param values
|
||||
*/
|
||||
public static checkMultipleChoiceValue(settingInput: SCSettingMultipleChoice, values: SCSettingValue[]): boolean {
|
||||
for (const value of values) {
|
||||
if (!settingInput.values.includes(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given value is valid to possible values in given settingInput
|
||||
* @param settingInput
|
||||
* @param value
|
||||
*/
|
||||
public static checkSingleChoiceValue(settingInput: SCSettingSingleChoice, value: SCSettingValue): boolean {
|
||||
return settingInput.values !== undefined
|
||||
&& settingInput.values.includes(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates value for given settings inputType. Returns true if value is valid.
|
||||
* @param setting setting to check value against
|
||||
* @param value value to validate
|
||||
*/
|
||||
public static validateValue(setting: SCSetting, value: any): boolean {
|
||||
let isValueValid: boolean = false;
|
||||
switch (setting.input.inputType) {
|
||||
case 'number':
|
||||
if (typeof value === 'number') {
|
||||
isValueValid = true;
|
||||
}
|
||||
break;
|
||||
case 'multipleChoice':
|
||||
if (!value.isArray) {
|
||||
isValueValid = false;
|
||||
} else {
|
||||
isValueValid = SettingsProvider.checkMultipleChoiceValue(setting.input, value);
|
||||
}
|
||||
break;
|
||||
case 'password':
|
||||
case 'text':
|
||||
if (typeof value === 'string') {
|
||||
isValueValid = true;
|
||||
}
|
||||
break;
|
||||
case 'singleChoice':
|
||||
isValueValid = SettingsProvider.checkSingleChoiceValue(setting.input, value);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return isValueValid;
|
||||
}
|
||||
|
||||
constructor(public storage: StorageProvider) {
|
||||
this.categoriesOrder = [];
|
||||
this.settingsCache = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes settings cache from storage
|
||||
*/
|
||||
private async initSettings(): Promise<void> {
|
||||
try {
|
||||
this.settingsCache = await this.storage.get<SettingsCache>(STORAGE_KEY_SETTING_VALUES);
|
||||
for (const category of Object.keys(this.settingsCache)) {
|
||||
if (!this.categoriesOrder.includes(category)) {
|
||||
this.categoriesOrder.push(category);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.settingsCache = {};
|
||||
}
|
||||
await this.saveSettings();
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add category if not exists
|
||||
* @param category the category to provide
|
||||
*/
|
||||
private async provideCategory(category: string): Promise<void> {
|
||||
if (!this.categoryExists(category)) {
|
||||
if (!this.categoriesOrder.includes(category)) {
|
||||
this.categoriesOrder.push(category);
|
||||
}
|
||||
this.settingsCache[category] = {
|
||||
category: category,
|
||||
settings: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if category exists
|
||||
* @param category
|
||||
*/
|
||||
public categoryExists(category: string): boolean {
|
||||
return this.settingsCache[category] !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all provided settings
|
||||
*/
|
||||
public async clear(): Promise<void> {
|
||||
await this.init();
|
||||
this.settingsCache = {};
|
||||
await this.saveSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an array with the order of categories
|
||||
*/
|
||||
public getCategoriesOrder(): string[] {
|
||||
return this.categoriesOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns copy of a setting if exist
|
||||
* @param category the category of requested setting
|
||||
* @param name the name of requested setting
|
||||
*
|
||||
* @throws Exception if setting is not provided
|
||||
*/
|
||||
public async getSetting(category: string, name: string): Promise<any> {
|
||||
await this.init();
|
||||
if (this.settingExists(category, name)) {
|
||||
return JSON.parse(JSON.stringify(this.settingsCache[category].settings[name]));
|
||||
} else {
|
||||
throw new Error('Setting "' + name + '" not provided');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns copy of cached settings
|
||||
*/
|
||||
public async getSettingsCache(): Promise<SettingsCache> {
|
||||
await this.init();
|
||||
return JSON.parse(JSON.stringify(this.settingsCache));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns copy of a setting if exist
|
||||
* @param category the category of requested setting
|
||||
* @param name the name of requested setting
|
||||
*
|
||||
* @throws Exception if setting is not provided
|
||||
*/
|
||||
public async getSettingValue(category: string, name: string): Promise<any> {
|
||||
await this.init();
|
||||
if (this.settingExists(category, name)) {
|
||||
return JSON.parse(JSON.stringify(this.settingsCache[category].settings[name].input.value));
|
||||
} else {
|
||||
throw new Error('Setting "' + name + '" not provided');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initializes settingsProvider
|
||||
*/
|
||||
public async init(): Promise<void> {
|
||||
if (!this.initialized) {
|
||||
await this.initSettings();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds given setting and its category if not exist
|
||||
* @param setting the setting to add
|
||||
*/
|
||||
public async provideSetting(setting: SCSetting): Promise<void> {
|
||||
await this.init();
|
||||
if (!this.categoryExists(setting.categories[0])) {
|
||||
await this.provideCategory(setting.categories[0]);
|
||||
}
|
||||
if (!this.settingExists(setting.categories[0], setting.name)) {
|
||||
// set value to default
|
||||
if (setting.input.value === undefined) {
|
||||
setting.input.value = setting.input.defaultValue;
|
||||
}
|
||||
this.settingsCache[setting.categories[0]].settings[setting.name] = setting;
|
||||
await this.saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets values of all settings to defaultValue
|
||||
*/
|
||||
public async resetDefault(): Promise<void> {
|
||||
await this.init();
|
||||
for (const catKey of Object.keys(this.settingsCache)) {
|
||||
for (const settingKey of Object.keys(this.settingsCache[catKey].settings)) {
|
||||
const settingInput = this.settingsCache[catKey].settings[settingKey].input;
|
||||
settingInput.value = settingInput.defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves cached settings in app storage
|
||||
*/
|
||||
public async saveSettings(): Promise<void> {
|
||||
await this.storage.put(STORAGE_KEY_SETTING_VALUES, this.settingsCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the order the given categories showup in the settings page
|
||||
* @param categoryNames the order of the categories
|
||||
*/
|
||||
public setCategoriesOrder(categoryNames: string[]) {
|
||||
this.categoriesOrder = categoryNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a valid value of a setting and persists changes in storage
|
||||
* @param category
|
||||
* @param name
|
||||
* @param value
|
||||
*
|
||||
* @throws Exception if setting is not provided or value not valid to the settings inputType
|
||||
*/
|
||||
public async setSettingValue(category: string, name: string, value: any): Promise<void> {
|
||||
await this.init();
|
||||
if (this.settingExists(category, name)) {
|
||||
const setting: SCSetting = this.settingsCache[category].settings[name];
|
||||
const isValueValid = SettingsProvider.validateValue(setting, value);
|
||||
if (isValueValid) {
|
||||
this.settingsCache[category].settings[name].input.value = value;
|
||||
await this.saveSettings();
|
||||
} else {
|
||||
throw new Error('Value "' + value + '" of type ' +
|
||||
typeof value + ' is not valid for ' + setting.input.inputType);
|
||||
}
|
||||
} else {
|
||||
throw new Error('setting ' + name + ' is not provided');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if setting in category exists
|
||||
* @param category
|
||||
* @param setting
|
||||
*/
|
||||
public settingExists(category: string, setting: string): boolean {
|
||||
return this.categoryExists(category) && this.settingsCache[category].settings[setting] !== undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user