feat: add the app

This commit is contained in:
Jovan Krunić
2018-12-11 22:11:50 +01:00
parent b4268b236f
commit 8b23159e67
129 changed files with 16359 additions and 1 deletions

View File

@@ -0,0 +1,27 @@
/*
* 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 { NgModule } from '@angular/core';
import { IonicStorageModule } from '@ionic/storage';
import { StorageProvider } from './storage.provider';
@NgModule({
imports: [
IonicStorageModule.forRoot()
],
providers: [
StorageProvider
]
})
export class StorageModule {}

View File

@@ -0,0 +1,156 @@
/*
* 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 {Storage} from '@ionic/storage';
import {StorageModule} from './storage.module';
import {StorageProvider} from './storage.provider';
describe('StorageProvider', () => {
let storageProvider: StorageProvider;
let storage: Storage;
const sampleEntries: Map<string, any> = new Map([
['foo', 'Bar'],
['bar', {foo: 'BarFoo'} as any],
['foobar', 123],
]);
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [StorageModule],
providers: [
StorageProvider,
// { provide: Storage, useClass: StorageMock }
],
});
storageProvider = TestBed.get(StorageProvider);
storage = TestBed.get(Storage);
await storage.clear();
});
it('should call ready method of storage on init', () => {
spyOn(storage, 'ready');
storageProvider.init();
expect(storage.ready).toHaveBeenCalled();
});
it('should call set method of storage to put a value', () => {
spyOn(storage, 'set');
storageProvider.put('some-uid', { some: 'thing' });
expect(storage.set).toHaveBeenCalledWith('some-uid', { some: 'thing' });
});
it('should call get method of storage to get a value', () => {
spyOn(storage, 'get');
storageProvider.get<any>('some-uid');
expect(storage.get).toHaveBeenCalledWith('some-uid');
});
it('should properly put and get a value', async () => {
await storageProvider.init();
await storageProvider.put('some-uid', {some: 'thing'});
const result: Map<string, object> = await storageProvider.get<Map<string, object>>('some-uid');
expect(result).toEqual({some: 'thing'});
});
it('should throw an error when value is null', async () => {
let error: Error = new Error();
spyOn(storage, 'get').and.returnValue(Promise.resolve(null));
try {
await storageProvider.get('something-else');
} catch (err) {
error = err;
}
expect(error).toEqual(new Error('Value not found.'));
});
it('should put multiple values into the storage', async () => {
spyOn(storageProvider, 'put');
await storageProvider.putMultiple(sampleEntries);
expect((storageProvider.put as jasmine.Spy).calls.count()).toEqual(3);
expect(storageProvider.put).toHaveBeenCalledWith('foo', 'Bar');
expect(storageProvider.put).toHaveBeenCalledWith('bar', {foo: 'BarFoo'});
});
it('should get multiple values from the storage', async () => {
spyOn(storageProvider, 'get').and.callThrough();
await storageProvider.putMultiple(sampleEntries);
const entries = await storageProvider.getMultiple(['foo', 'bar']);
expect((storageProvider.get as jasmine.Spy).calls.count()).toEqual(2);
expect(storageProvider.get).toHaveBeenCalledWith('foo');
expect(storageProvider.get).toHaveBeenCalledWith('bar');
expect(Array.from(entries.values())).toEqual(['Bar', {foo: 'BarFoo'}]);
expect(Array.from(entries.keys())).toEqual(['foo', 'bar']);
});
it('should get all values from the storage', async () => {
spyOn(storageProvider, 'get').and.callThrough();
await storageProvider.putMultiple(sampleEntries);
const entries = await storageProvider.getAll();
expect(Array.from(entries.values()).map((item) => (item.foo) ? item.foo : item).sort())
.toEqual(Array.from(sampleEntries.values()).map((item) => (item.foo) ? item.foo : item).sort());
expect(Array.from(entries.keys()).sort()).toEqual(['bar', 'foo', 'foobar']);
});
it('should delete one entry', async () => {
spyOn(storage, 'remove').and.callThrough();
await storageProvider.putMultiple(sampleEntries);
let entries = await storageProvider.getAll();
expect(Array.from(entries.values()).length).toBe(3);
await storageProvider.delete('bar');
expect(storage.remove).toHaveBeenCalled();
entries = await storageProvider.getAll();
expect(Array.from(entries.values())).toEqual(['Bar', 123]);
});
it('should delete all entries in the storage', async () => {
spyOn(storage, 'clear').and.callThrough();
await storageProvider.putMultiple(sampleEntries);
let entries = await storageProvider.getAll();
expect(Array.from(entries.values()).length).toBe(3);
await storageProvider.deleteAll();
entries = await storageProvider.getAll();
expect(storage.clear).toHaveBeenCalled();
expect(Array.from(entries.values()).length).toBe(0);
});
it('should provide number of entries', async () => {
spyOn(storage, 'length').and.callThrough();
expect(await storageProvider.length()).toBe(0);
expect(storage.length).toHaveBeenCalled();
await storageProvider.putMultiple(sampleEntries);
expect(await storageProvider.length()).toBe(3);
});
it('should provide information if storage is empty', async () => {
spyOn(storage, 'length').and.callThrough();
expect(await storageProvider.isEmpty()).toBeTruthy();
expect(storage.length).toHaveBeenCalled();
await storageProvider.putMultiple(sampleEntries);
expect(await storageProvider.isEmpty()).toBeFalsy();
});
it('should provide information if storage contains a specific entry (key)', async () => {
spyOn(storage, 'keys').and.returnValue(Promise.resolve(Array.from(sampleEntries.keys())));
expect(await storageProvider.has('foo')).toBeTruthy();
expect(await storageProvider.has('something-else')).toBeFalsy();
});
});

View File

@@ -0,0 +1,137 @@
/*
* 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 {Storage} from '@ionic/storage';
/**
* Provides interaction with the (ionic) storage on the device (in the browser)
*/
@Injectable()
export class StorageProvider {
constructor(private storage: Storage) {
}
/**
* Initializes the storage (waits until it's ready)
*/
async init(): Promise<any> {
return this.storage.ready();
}
/**
* Puts a value of type T into the storage using provided key
*
* @param key Unique indentifier
* @param value Resource to store under the key
*/
async put<T>(key: string, value: T): Promise<T> {
return this.storage.set(key, value);
}
/**
* Gets a value from the storage using the provided key
*
* @param key Unique identifier of the wanted resource in storage
*/
async get<T>(key: string): Promise<T> {
const entry = await this.storage.get(key);
if (!entry) {
throw new Error('Value not found.');
}
return entry;
}
/**
* Deletes a storage entry using the key used to save it
*
* @param key Unique identifier of the resource
*/
async delete(key: string): Promise<void> {
return this.storage.remove(key);
}
/**
* Deletes all the entries in the storage (empty the storage)
*/
async deleteAll(): Promise<void> {
return this.storage.clear();
}
/**
* Saves multiple entries into the storage
*
* @param entries Resources to be put into the storage
*/
async putMultiple(entries: Map<string, any>): Promise<Map<string, any>> {
const puts: Array<Promise<any>> = [];
entries.forEach(async (value, key) => {
puts.push(this.put(key, value));
});
await Promise.all(puts);
return entries;
}
/**
* Retrieves multiple entries from the storage using their keys
*
* @param keys Unique identifiers of wanted resources from the storage
*/
async getMultiple(keys: string[]): Promise<Map<string, any>> {
const gets: Array<Promise<any>> = [];
const map = new Map();
const getToMap = async (key: string) => {
map.set(key, await this.get(key));
}
keys.forEach((key) => {
gets.push(getToMap(key));
});
await Promise.all(gets);
return map;
}
/**
* Retrieves all the storage entries
*/
async getAll(): Promise<Map<string, any>> {
const map: Map<string, any> = new Map();
await this.storage.forEach((value, key) => {
map.set(key, value);
});
return map;
}
/**
* Provides a number of entries in the storage (number of keys)
*/
async length(): Promise<number> {
return this.storage.length();
}
/**
* Provides information if storage is empty or not
*/
async isEmpty(): Promise<boolean> {
return (await this.storage.length()) === 0;
}
/**
* Provides information if storage has an entry with the given key
*
* @param key Unique identifier of the resource in storage
*/
async has(key: string): Promise<boolean> {
return (await this.storage.keys()).includes(key);
}
}