Compare commits

...

2 Commits

Author SHA1 Message Date
Fabian
ae5257b2b3 Adding automatic theme change 2019-07-02 19:10:16 +02:00
Fabian
c3f9529feb Updaing to IDB 4x 2019-07-02 18:34:41 +02:00
8 changed files with 99 additions and 51 deletions

6
package-lock.json generated
View File

@ -3541,9 +3541,9 @@
} }
}, },
"idb": { "idb": {
"version": "3.0.2", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/idb/-/idb-3.0.2.tgz", "resolved": "https://registry.npmjs.org/idb/-/idb-4.0.3.tgz",
"integrity": "sha512-+FLa/0sTXqyux0o6C+i2lOR0VoS60LU/jzUo5xjfY6+7sEEgy4Gz1O7yFBXvjd7N0NyIGWIRg8DcQSLEG+VSPw==" "integrity": "sha512-moRlNNe0Gsvp4jAwz5cJ7scjyNTVA/cESKGCobULaljfaKZ970y8NDNCseHdMY+YxNXH58Z1V+7tTyf0GZyKqw=="
}, },
"ieee754": { "ieee754": {
"version": "1.1.13", "version": "1.1.13",

View File

@ -18,7 +18,7 @@
"@hibas123/utils": "^2.1.0", "@hibas123/utils": "^2.1.0",
"aes-js": "^3.1.2", "aes-js": "^3.1.2",
"feather-icons": "^4.22.1", "feather-icons": "^4.22.1",
"idb": "3.0.2", "idb": "^4.0.3",
"js-sha256": "^0.9.0", "js-sha256": "^0.9.0",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"secure-file-wrapper": "git+https://git.stamm.me/OpenServer/OSSecureFileWrapper.git", "secure-file-wrapper": "git+https://git.stamm.me/OpenServer/OSSecureFileWrapper.git",

View File

@ -1,6 +1,6 @@
import { h } from "preact"; import { h } from "preact";
import { Page } from "../../../page"; import { Page } from "../../../page";
import Theme from "../../../theme"; import Theme, { ThemeStates } from "../../../theme";
import Navigation from "../../../navigation"; import Navigation from "../../../navigation";
import ArrowLeft from "feather-icons/dist/icons/arrow-left.svg"; import ArrowLeft from "feather-icons/dist/icons/arrow-left.svg";
@ -10,6 +10,7 @@ export default class SettingsPage extends Page<{ state: any }, { vault: string }
} }
render() { render() {
let active = Theme.active();
return <div> return <div>
<header class="header"> <header class="header">
<a class="header-icon-button" onClick={() => history.back()}><ArrowLeft height={undefined} width={undefined} /></a> <a class="header-icon-button" onClick={() => history.back()}><ArrowLeft height={undefined} width={undefined} /></a>
@ -17,7 +18,18 @@ export default class SettingsPage extends Page<{ state: any }, { vault: string }
<span></span> <span></span>
</header> </header>
<div class="container"> <div class="container">
<button class="btn" onClick={() => Theme.toggle()}>Toggle Dark Mode</button> <div className="input-group">
<label>Select Theme: </label>
<select class="inp" onChange={(ev) => Theme.change(Number((ev.target as HTMLSelectElement).value))}>
{Object.keys(ThemeStates)
.filter(e => Number.isNaN(Number(e)))
.map(e => <option selected={ThemeStates[e] === active} value={ThemeStates[e]}>{e.charAt(0).toUpperCase() + e.slice(1).toLowerCase()}</option>)}
{/* <option value={ThemeStates.AUTO}>Auto</option>
<option value={ThemeStates.LIGHT}>Light</option>
<option value={ThemeStates.DARK}>Dark</option> */}
</select>
</div>
{/* <button class="btn" onClick={() => Theme.toggle()}>Toggle Dark Mode</button> */}
<button class="btn" onClick={() => window.navigator.serviceWorker.controller.postMessage("clear_cache")}>Clear cache</button> <button class="btn" onClick={() => window.navigator.serviceWorker.controller.postMessage("clear_cache")}>Clear cache</button>
</div> </div>
</div >; </div >;

View File

@ -3,7 +3,7 @@
padding: 0.5rem; padding: 0.5rem;
margin-top: 0 !important; margin-top: 0 !important;
align-items: flex-end; align-items: flex-end;
justify-content: end; justify-content: start;
>span { >span {
font-size: 1.5rem; font-size: 1.5rem;

View File

@ -1,14 +1,12 @@
import { Lock } from "@hibas123/utils"; import { Lock } from "@hibas123/utils";
import { DB, openDb, Transaction } from "idb"; import { openDB, IDBPDatabase, IDBPTransaction, } from "idb";
export default class IDB { export default class IDB {
initLock = new Lock(); initLock = new Lock();
db: DB; db: IDBPDatabase;
constructor(database: string, private stores: string[]) { constructor(database: string, private stores: string[]) {
let lock = this.initLock.getLock(); this.initLock.getLock().then(async l => {
lock.then(async l => {
let v = localStorage.getItem(database + "_version"); let v = localStorage.getItem(database + "_version");
let version = 0; let version = 0;
if (v) version = Number(v) if (v) version = Number(v)
@ -21,12 +19,15 @@ export default class IDB {
localStorage.setItem(database + "_version", version.toString()); localStorage.setItem(database + "_version", version.toString());
localStorage.setItem(database + "_stores", stores.join(",")); localStorage.setItem(database + "_stores", stores.join(","));
this.db = await openDb(database, version, db => { this.db = await openDB(database, version, {
console.log("IndexedDB need update") upgrade: (db) => {
stores.forEach(store => { console.log("IndexedDB need update")
if (!db.objectStoreNames.contains(store)) const check = name => (<any>db.objectStoreNames as DOMStringList).contains ? (<any>db.objectStoreNames as DOMStringList).contains(name) : db.objectStoreNames.find(e => e === name);
db.createObjectStore(store); stores.forEach(store => {
}) if (!check(store))
db.createObjectStore(store);
})
},
}) })
console.log("Got DATABASE", this.db) console.log("Got DATABASE", this.db)
l.release(); l.release();
@ -48,42 +49,42 @@ export default class IDB {
return { return {
name: name, name: name,
transaction: () => { transaction: () => {
return this.db.transaction(name, "readwrite") return <any>this.db.transaction(name, "readwrite") as IDBPTransaction<unknown, string[]>;
}, },
get: async (key: string, transaction?: Transaction): Promise<T> => { get: async (key: string, transaction?: IDBPTransaction<unknown, string[]>): Promise<T> => {
(await this.initLock.getLock()).release() (await this.initLock.getLock()).release()
return (transaction || this.db.transaction(name)) return (transaction || this.db.transaction(name))
.objectStore(name).get(key); .objectStore(name).get(key);
}, },
getAll: async (transaction?: Transaction): Promise<T[]> => { getAll: async (transaction?: IDBPTransaction<unknown, string[]>): Promise<T[]> => {
(await this.initLock.getLock()).release() (await this.initLock.getLock()).release()
return (transaction || this.db.transaction(name)) return (transaction || this.db.transaction(name))
.objectStore(name).getAll(); .objectStore(name).getAll();
}, },
set: async (key: string, val: T, transaction?: Transaction) => { set: async (key: string, val: T, transaction?: IDBPTransaction<unknown, string[]>) => {
(await this.initLock.getLock()).release() (await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name, "readwrite")); const tx = (transaction || this.db.transaction(name, "readwrite"));
tx.objectStore(name).put(val, key); tx.objectStore(name).put(val, key);
return tx.complete; return tx.done;
}, },
delete: async (key: string, transaction?: Transaction) => { delete: async (key: string, transaction?: IDBPTransaction<unknown, string[]>) => {
(await this.initLock.getLock()).release() (await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name, "readwrite")); const tx = (transaction || this.db.transaction(name, "readwrite"));
tx.objectStore(name).delete(key); tx.objectStore(name).delete(key);
return tx.complete; return tx.done;
}, },
clear: async (transaction?: Transaction) => { clear: async (transaction?: IDBPTransaction<unknown, string[]>) => {
(await this.initLock.getLock()).release() (await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name, "readwrite")); const tx = (transaction || this.db.transaction(name, "readwrite"));
tx.objectStore(name).clear(); tx.objectStore(name).clear();
return tx.complete; return tx.done;
}, },
keys: async (transaction?: Transaction): Promise<string[]> => { keys: async (transaction?: IDBPTransaction<unknown, string[]>): Promise<string[]> => {
(await this.initLock.getLock()).release() (await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name)); const tx = (transaction || this.db.transaction(name));
const keys: string[] = []; const keys: string[] = [];
@ -91,13 +92,15 @@ export default class IDB {
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari. // This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
// openKeyCursor isn't supported by Safari, so we fall back // openKeyCursor isn't supported by Safari, so we fall back
(store.iterateKeyCursor || store.iterateCursor).call(store, (cursor: any) => { store.getAllKeys()
if (!cursor) return;
keys.push(cursor.key);
cursor.continue();
});
return tx.complete.then(() => keys); // (store.iterateKeyCursor || store.iterateCursor).call(store, (cursor: any) => {
// if (!cursor) return;
// keys.push(cursor.key);
// cursor.continue();
// });
return tx.done.then(() => keys);
} }
} }
} }

View File

@ -99,17 +99,25 @@ console.log("Dark mode:", Theme.active);
let err = await Notes.getToken(code) let err = await Notes.getToken(code)
if (err) { if (err) {
Notifications.sendError("Login failed: " + err) Notifications.sendError("Login failed: " + err)
Notes.login() return Notes.login()
} else { } else {
window.history.replaceState(null, document.title, "/" + window.location.hash); window.history.replaceState(null, document.title, "/" + window.location.hash);
} }
} else { } else {
Notes.login() return Notes.login()
} }
} }
await Notes.start(); await Notes.start();
if (window.navigator.storage && navigator.storage.persist) {
navigator.storage.persisted()
.then(has => has ? true : navigator.storage.persist())
.then(is => {
console.log("Persistant Storage:", is);
})
}
Navigation.default = VaultsPage as typeof Page; Navigation.default = VaultsPage as typeof Page;
Navigation.addPage("/vault", VaultPage as typeof Page) Navigation.addPage("/vault", VaultPage as typeof Page)
Navigation.addPage("/demo", DemoPage as typeof Page) Navigation.addPage("/demo", DemoPage as typeof Page)

View File

@ -1,7 +1,7 @@
import SecureFile, { IFile } from "@hibas123/secure-file-wrapper"; import SecureFile, { IFile } from "@hibas123/secure-file-wrapper";
import { Lock, Observable } from "@hibas123/utils"; import { Lock, Observable } from "@hibas123/utils";
import * as aesjs from "aes-js"; import * as aesjs from "aes-js";
import { Transaction } from "idb"; import { IDBPTransaction } from "idb";
import { sha256 } from "js-sha256"; import { sha256 } from "js-sha256";
import * as uuidv4 from "uuid/v4"; import * as uuidv4 from "uuid/v4";
import * as config from "../config.json"; import * as config from "../config.json";
@ -480,7 +480,7 @@ class NotesProvider {
return Decoder.decode(this._decrypt(msg, this.generalEncryption)) return Decoder.decode(this._decrypt(msg, this.generalEncryption))
} }
async addop(note_id: string, type: OpLogType, values: { value: Uint8Array, preview: Uint8Array }, date: Date, transaction?: Transaction) { async addop(note_id: string, type: OpLogType, values: { value: Uint8Array, preview: Uint8Array }, date: Date, transaction?: IDBPTransaction<unknown, string[]>) {
let tx = transaction || this.oplogDB.transaction(); let tx = transaction || this.oplogDB.transaction();
let oplog = await this.oplogDB.get(note_id, tx); let oplog = await this.oplogDB.get(note_id, tx);
if (!oplog) oplog = { logs: [], id: note_id }; if (!oplog) oplog = { logs: [], id: note_id };

View File

@ -1,27 +1,52 @@
const light = require("!!raw-loader!@hibas123/theme/out/light.css").default; const light = require("!!raw-loader!@hibas123/theme/out/light.css").default;
const dark = require("!!raw-loader!@hibas123/theme/out/dark.css").default; const dark = require("!!raw-loader!@hibas123/theme/out/dark.css").default;
let isDark = localStorage.getItem("theme") === "dark"; export enum ThemeStates {
AUTO,
LIGHT,
DARK
}
let themeConfig: ThemeStates = Number(localStorage.getItem("theme"));
if (Number.isNaN(themeConfig))
themeConfig = ThemeStates.AUTO;
let isDark = false;
let mediaIsDark = false;
if (window.matchMedia) {
const mediaq = matchMedia("(prefers-color-scheme: dark)");
mediaIsDark = mediaq.matches;
mediaq.onchange = ev => {
mediaIsDark = ev.matches;
apply();
}
console.log(mediaq);
}
let styleElm: HTMLStyleElement; let styleElm: HTMLStyleElement;
function apply(force?: boolean) {
function apply() { let shouldDark = themeConfig === ThemeStates.AUTO ? mediaIsDark : themeConfig === ThemeStates.DARK;
if (styleElm) styleElm.remove(); if (force || shouldDark !== isDark) {
styleElm = document.createElement("style"); if (styleElm) styleElm.remove();
document.head.appendChild(styleElm); styleElm = document.createElement("style");
styleElm.innerHTML = isDark ? dark : light; document.head.appendChild(styleElm);
styleElm.innerHTML = shouldDark ? dark : light;
isDark = shouldDark;
}
} }
apply(); apply(true);
function toggle() {
isDark = !isDark; function change(state: ThemeStates) {
localStorage.setItem("theme", isDark ? "dark" : "light"); themeConfig = state;
localStorage.setItem("theme", String(themeConfig));
apply(); apply();
} }
export default { export default {
active: () => isDark, active: () => themeConfig,
toggle: () => toggle() change: (state: ThemeStates) => change(state)
} }