Tighter integration

This commit is contained in:
Mo Bitar
2018-07-09 10:17:12 -05:00
parent 6214bdf98b
commit 134e295475
24 changed files with 186 additions and 148 deletions

View File

@@ -1,4 +1,4 @@
import Storage from "./lib/storage"
import Storage from "./lib/sfjs/storageManager"
export default class OptionsState {

View File

@@ -1,10 +1,10 @@
import { StyleSheet, StatusBar, Alert, Platform, Dimensions } from 'react-native';
import App from "./app"
import ModelManager from "./lib/modelManager"
import Server from "./lib/server"
import Sync from "./lib/sync"
import Storage from "./lib/storage"
import Auth from "./lib/auth"
import ModelManager from "./lib/sfjs/modelManager"
import Server from "./lib/sfjs/httpManager"
import Sync from './lib/sfjs/syncManager'
import Storage from "./lib/sfjs/storageManager"
import Auth from "./lib/authManager"
import Theme from "./models/subclass/theme"
import KeysManager from './lib/keysManager'
@@ -22,56 +22,57 @@ export default class GlobalStyles {
async resolveInitialTheme() {
// Get the active theme from storage rather than waiting for local database to load
return Storage.get().getItem("activeTheme").then(function(themeResult) {
let runDefaultTheme = () => {
try {
var theme = this.systemTheme();
theme.setMobileActive(true);
this.activeTheme = theme;
var constants = this.defaultConstants();
this.setStyles(this.defaultRules(constants), constants, theme.getMobileRules().statusBar);
} catch (e) {
var constants = this.defaultConstants();
this.setStyles(this.defaultRules(constants), constants, Platform.OS == "android" ? "light-content" : "dark-content");
console.log("Default theme error", e);
}
var themeResult = await Storage.get().getItem("activeTheme");
let runDefaultTheme = () => {
try {
var theme = this.systemTheme();
theme.setMobileActive(true);
this.activeTheme = theme;
var constants = this.defaultConstants();
this.setStyles(this.defaultRules(constants), constants, theme.getMobileRules().statusBar);
} catch (e) {
var constants = this.defaultConstants();
this.setStyles(this.defaultRules(constants), constants, Platform.OS == "android" ? "light-content" : "dark-content");
console.log("Default theme error", e);
}
}
if(themeResult) {
// JSON stringified content is generic and includes all items property at time of stringification
// So we parse it, then set content to itself, so that the mapping can be handled correctly.
try {
var parsedTheme = JSON.parse(themeResult);
var needsMigration = false;
if(parsedTheme.mobileRules) {
// Newer versions of the app persist a Theme object where mobileRules are nested in AppData.
// We want to check if the currently saved data is of the old format, which uses theme.mobileRules
// instead of theme.getMobileRules(). If so, we want to prepare it for the new format.
needsMigration = true;
}
let content = Object.assign({}, parsedTheme);
parsedTheme.content = content;
console.log("Theme result", themeResult);
var theme = new Theme(parsedTheme);
if(needsMigration) {
theme.setMobileRules(parsedTheme.mobileRules);
theme.mobileRules = null;
}
theme.isSwapIn = true;
var constants = _.merge(this.defaultConstants(), theme.getMobileRules().constants);
var rules = _.merge(this.defaultRules(constants), theme.getMobileRules().rules);
this.setStyles(rules, constants, theme.getMobileRules().statusBar);
this.activeTheme = theme;
} catch (e) {
console.error("Error parsing initial theme", e);
runDefaultTheme();
if(themeResult) {
// JSON stringified content is generic and includes all items property at time of stringification
// So we parse it, then set content to itself, so that the mapping can be handled correctly.
try {
var parsedTheme = JSON.parse(themeResult);
var needsMigration = false;
if(parsedTheme.mobileRules) {
// Newer versions of the app persist a Theme object where mobileRules are nested in AppData.
// We want to check if the currently saved data is of the old format, which uses theme.mobileRules
// instead of theme.getMobileRules(). If so, we want to prepare it for the new format.
needsMigration = true;
}
} else {
let content = Object.assign({}, parsedTheme);
parsedTheme.content = content;
var theme = new Theme(parsedTheme);
if(needsMigration) {
theme.setMobileRules(parsedTheme.mobileRules);
theme.mobileRules = null;
}
theme.isSwapIn = true;
var constants = _.merge(this.defaultConstants(), theme.getMobileRules().constants);
var rules = _.merge(this.defaultRules(constants), theme.getMobileRules().rules);
this.setStyles(rules, constants, theme.getMobileRules().statusBar);
this.activeTheme = theme;
} catch (e) {
console.error("Error parsing initial theme", e);
runDefaultTheme();
}
}.bind(this));
} else {
runDefaultTheme();
}
}
constructor() {
@@ -136,9 +137,11 @@ export default class GlobalStyles {
var constants = this.defaultConstants();
this._systemTheme = new Theme({
name: "Default",
default: true,
uuid: 0
uuid: 0,
content: {
isDefault: true,
name: "Default",
}
});
this._systemTheme.setMobileRules({
@@ -175,7 +178,7 @@ export default class GlobalStyles {
this.activeTheme = theme;
theme.setMobileActive(true);
if(theme.default) {
if(theme.content.isDefault) {
Storage.get().removeItem("activeTheme");
} else if(writeToStorage) {
Storage.get().setItem("activeTheme", JSON.stringify(theme));
@@ -258,9 +261,7 @@ export default class GlobalStyles {
}
setStyles(rules, constants, statusBar) {
if(!statusBar) {
statusBar = "light-content";
}
if(!statusBar) { statusBar = "light-content";}
this.statusBar = statusBar;
this.constants = constants;
this.styles = {

View File

@@ -9,7 +9,7 @@ import {Navigation, ScreenVisibilityListener} from 'react-native-navigation';
import {registerScreens} from './screens';
import KeysManager from './lib/keysManager'
import Auth from './lib/auth'
import Auth from './lib/authManager'
import ReviewManager from './lib/reviewManager';
import GlobalStyles from "./Styles"
import Icons from "./Icons"

View File

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import GlobalStyles from "../../Styles"
import {Text, View} from 'react-native';
import KeysManager from "../../lib/keysManager"
import ModelManager from "../../lib/modelManager"
import ModelManager from "../../lib/sfjs/modelManager"
import SectionHeader from "../../components/SectionHeader";
import ButtonCell from "../../components/ButtonCell";

View File

@@ -18,7 +18,7 @@ global.SFAlertManager = SFAlertManager;
global.SFStorageManager = SFStorageManager;
global.SFHttpManager = SFHttpManager;
import SF from "./lib/sfjs"
import SF from "./lib/sfjs/sfjs"
global.SFJS = SF.get();
import 'sn-models';

View File

@@ -1,9 +1,10 @@
import SF from './sfjs'
import Server from './server'
import Storage from './storage'
import Sync from './sync'
import ModelManager from './modelManager'
import AlertManager from './alertManager'
import SF from './sfjs/sfjs'
import Server from './sfjs/httpManager'
import Storage from './sfjs/storageManager'
import Sync from './sfjs/syncManager'
import ModelManager from './sfjs/modelManager'
import AlertManager from './sfjs/alertManager'
import {Platform} from 'react-native';
import Keychain from "./keychain"
import KeysManager from "./keysManager"
@@ -165,7 +166,7 @@ export default class Auth {
return;
}
SF.get().crypto().computeEncryptionKeysForUser(inputtedPassword, authParams).then((keys) => {
SF.get().crypto.computeEncryptionKeysForUser(inputtedPassword, authParams).then((keys) => {
root.performLoginRequest(email, keys.pw, server, extraParams, async (response, error) => {
if(error) {
callback(null, error);
@@ -189,7 +190,7 @@ export default class Auth {
// if(__DEV__) { authParams.pw_cost = 3000; }
SF.get().crypto().generateInitialKeysAndAuthParamsForUser(email, inputtedPassword).then((results) => {
SF.get().crypto.generateInitialKeysAndAuthParamsForUser(email, inputtedPassword).then((results) => {
let keys = results.keys;
let authParams = results.authParams;

View File

@@ -1,11 +1,11 @@
/* This domain will be used to save context item client data */
let ClientDataDomain = "org.standardnotes.sn.components";
import ModelManager from './modelManager'
import GlobalStyles from '../Styles'
import App from '../app'
import Sync from './sync'
import SF from "./sfjs"
import ModelManager from './sfjs/modelManager'
import Sync from './sfjs/syncManager'
import SF from "./sfjs/sfjs"
export default class ComponentManager {
@@ -325,7 +325,7 @@ export default class ComponentManager {
}
component.window = componentWindow;
component.sessionKey = await SF.get().crypto().generateUUID();
component.sessionKey = await SF.get().crypto.generateUUID();
this.sendMessageToComponent(component, {
action: "component-registered",

View File

@@ -1,9 +1,8 @@
import {Platform} from 'react-native';
import AlertManager from './alertManager'
import ModelManager from './modelManager'
import Sync from './sync'
import {Platform, Share} from 'react-native';
import ApplicationState from '../ApplicationState'
import {Share} from 'react-native';
import AlertManager from './sfjs/alertManager'
import ModelManager from './sfjs/modelManager'
import Sync from './sfjs/syncManager'
export default class ItemActionManager {

View File

@@ -1,14 +1,14 @@
import SF from './sfjs'
import Server from './server'
import Storage from './storage'
import ModelManager from './modelManager'
import {Platform} from 'react-native';
import Keychain from "./keychain"
import FlagSecure from 'react-native-flag-secure-android';
import App from "../app"
import FlagSecure from 'react-native-flag-secure-android';
import ApplicationState from "../ApplicationState"
import FingerprintScanner from 'react-native-fingerprint-scanner';
import SF from './sfjs/sfjs'
import ModelManager from './sfjs/modelManager'
import Storage from './sfjs/storageManager'
import Keychain from "./keychain"
let OfflineParamsKey = "pc_params";
let FirstRunKey = "first_run";
let StorageEncryptionKey = "storage_encryption";

View File

@@ -1,6 +1,6 @@
import * as StoreReview from 'react-native-store-review';
import {Platform} from 'react-native';
import Storage from "./storage";
import * as StoreReview from 'react-native-store-review';
import Storage from "./sfjs/storageManager";
let NumRunsBeforeAskingForReview = [20, 65, 120]

View File

@@ -1,5 +1,5 @@
import { Alert } from 'react-native';
import App from "../app"
import App from "../../app"
export default class AlertManager extends SFAlertManager {

View File

@@ -1,4 +1,4 @@
import KeysManager from './keysManager'
import KeysManager from '../keysManager'
export default class Server extends SFHttpManager {

View File

@@ -1,17 +1,12 @@
import Storage from "./storage"
import Theme from "../models/subclass/theme"
import "../models/extend/item.js";
import Storage from "./storageManager"
import Theme from "../../models/subclass/theme"
import "../../models/extend/item.js";
SFModelManager.ContentTypeClassMapping = {
"Note" : SNNote,
"Tag" : SNTag,
"SN|SmartTag" : SNSmartTag,
"Extension" : SNExtension,
"SN|Editor" : SNEditor,
"SN|Theme" : Theme,
"SN|Component" : SNComponent,
"SF|Extension" : SNServerExtension,
"SF|MFA" : SNMfa
"SN|Component" : SNComponent
};
SFItem.AppDomain = "org.standardnotes.sn";

View File

View File

@@ -102,7 +102,9 @@ export default class Storage extends SFStorageManager {
return;
}
return Promise.all(items.map((item) => {
console.log("Saving model", JSON.stringify(item));
return AsyncStorage.setItem(this.keyForItem(item), JSON.stringify(item));
}));
}

View File

@@ -1,11 +1,12 @@
import SF from './sfjs'
import Server from './server'
import Auth from './auth'
import Server from './httpManager'
import ModelManager from './modelManager'
import Storage from './storage'
import KeysManager from './keysManager'
import Storage from './storageManager'
import AlertManager from './alertManager'
import Auth from '../authManager'
import KeysManager from '../keysManager'
export default class Sync extends SFSyncManager {
static instance = null;
@@ -23,6 +24,7 @@ export default class Sync extends SFSyncManager {
KeysManager.get().registerAccountRelatedStorageKeys(["syncToken", "cursorToken"]);
this.setKeyRequestHandler((request) => {
console.log(request);
var keys;
if(request == SFSyncManager.KeyRequestLoadSaveAccount || request == SFSyncManager.KeyRequestLoadLocal) {
keys = KeysManager.get().activeKeys();
@@ -40,7 +42,7 @@ export default class Sync extends SFSyncManager {
async resaveOfflineData() {
var items = ModelManager.get().allItems;
return this.writeItemsToStorage(items, false);
return this.writeItemsToLocalStorage(items, false);
}
async getServerURL() {

View File

@@ -1,4 +1,4 @@
import SF from "../../lib/sfjs"
import SF from "../../lib/sfjs/sfjs"
export default class Theme extends SNTheme {

View File

@@ -1,11 +1,13 @@
import React, { Component } from 'react';
import {ScrollView, View, Alert, Keyboard, Linking, Platform, Share, NativeModules} from 'react-native';
import Sync from '../lib/sync'
import Auth from '../lib/auth'
import AlertManager from '../lib/alertManager'
import Sync from '../lib/sfjs/syncManager'
import ModelManager from '../lib/sfjs/modelManager'
import AlertManager from '../lib/sfjs/alertManager'
import Auth from '../lib/authManager'
import KeysManager from '../lib/keysManager'
import ModelManager from '../lib/modelManager'
import SectionHeader from "../components/SectionHeader";
import ButtonCell from "../components/ButtonCell";
import TableSection from "../components/TableSection";

View File

@@ -1,17 +1,18 @@
import React, { Component } from 'react';
import Auth from '../lib/auth'
import SF from '../lib/sfjs'
import App from "../app"
import SF from '../lib/sfjs/sfjs'
import Storage from '../lib/sfjs/storageManager'
import Auth from '../lib/authManager'
import KeysManager from '../lib/keysManager'
import Abstract from "./Abstract"
import SectionHeader from "../components/SectionHeader";
import ButtonCell from "../components/ButtonCell";
import TableSection from "../components/TableSection";
import SectionedTableCell from "../components/SectionedTableCell";
import SectionedAccessoryTableCell from "../components/SectionedAccessoryTableCell";
import SectionedOptionsTableCell from "../components/SectionedOptionsTableCell";
import Abstract from "./Abstract"
import Storage from '../lib/storage'
import KeysManager from '../lib/keysManager'
import GlobalStyles from "../Styles"
import App from "../app"
import FingerprintScanner from 'react-native-fingerprint-scanner';
import Icon from 'react-native-vector-icons/Ionicons';
@@ -224,9 +225,9 @@ class PasscodeSection extends Abstract {
// Allow UI to update before executing block task. InteractionManager.runAfterInteractions doesn't seem to work.
setTimeout(async () => {
let identifier = await SF.get().crypto().generateUUID();
let identifier = await SF.get().crypto.generateUUID();
SF.get().crypto().generateInitialKeysAndAuthParamsForUser(identifier, passcode).then((results) => {
SF.get().crypto.generateInitialKeysAndAuthParamsForUser(identifier, passcode).then((results) => {
let keys = results.keys;
let authParams = results.authParams;
@@ -263,7 +264,7 @@ class PasscodeSection extends Abstract {
setTimeout(() => {
var authParams = KeysManager.get().offlineAuthParams;
SF.get().crypto().computeEncryptionKeysForUser(passcode, authParams).then((keys) => {
SF.get().crypto.computeEncryptionKeysForUser(passcode, authParams).then((keys) => {
if(keys.pw === KeysManager.get().offlinePasscodeHash()) {
KeysManager.get().setOfflineKeys(keys);
this.props.onAuthenticateSuccess();

View File

@@ -1,11 +1,12 @@
import React, { Component } from 'react';
import Sync from '../lib/sync'
import Auth from '../lib/auth'
import ModelManager from '../lib/modelManager'
import ComponentManager from '../lib/componentManager'
import Abstract from "./Abstract"
import Icons from '../Icons';
import App from '../app'
import Sync from '../lib/sfjs/syncManager'
import ModelManager from '../lib/sfjs/modelManager'
import Auth from '../lib/authManager'
import Abstract from "./Abstract"
import ComponentManager from '../lib/componentManager'
import Icons from '../Icons';
import LockedView from "../containers/LockedView";
import Icon from 'react-native-vector-icons/Ionicons';
@@ -202,7 +203,7 @@ export default class Compose extends Abstract {
onOptionsChange: (options) => {
if(!_.isEqual(options.selectedTags, this.previousOptions.selectedTags)) {
var tags = ModelManager.get().findItems(options.selectedTags);
this.note.replaceTags(tags);
this.replaceTagsForNote(tags);
this.note.setDirty(true);
this.changesMade();
}
@@ -211,6 +212,26 @@ export default class Compose extends Abstract {
});
}
replaceTagsForNote(newTags) {
let note = this.note;
var oldTags = note.tags.slice(); // original array will be modified in the for loop so we make a copy
for(var oldTag of oldTags) {
if(!newTags.includes(oldTag)) {
oldTag.removeItemAsRelationship(note);
oldTag.setDirty(true);
note.removeItemAsRelationship(oldTag);
}
}
for(var newTag of newTags) {
newTag.setDirty(true);
newTag.addItemAsRelationship(note);
}
note.tags = newTags;
}
onTitleChange = (text) => {
this.mergeState({title: text})
this.note.title = text;

View File

@@ -1,9 +1,10 @@
import React, { Component } from 'react';
import { TextInput, SectionList, ScrollView, View, Text, Linking, Share, Platform, StatusBar, FlatList, Dimensions } from 'react-native';
import Sync from '../lib/sync'
import ModelManager from '../lib/modelManager'
import App from "../app"
import Sync from '../lib/sfjs/syncManager'
import ModelManager from '../lib/sfjs/modelManager'
import ComponentManager from '../lib/componentManager'
import AlertManager from '../lib/alertManager'
import AlertManager from '../lib/sfjs/alertManager'
import ItemActionManager from '../lib/itemActionManager'
import SectionHeader from "../components/SectionHeader";
import ButtonCell from "../components/ButtonCell";
@@ -15,7 +16,6 @@ import Abstract from "./Abstract"
import Icons from '../Icons';
import OptionsState from "../OptionsState"
import GlobalStyles from "../Styles"
import App from "../app"
import ApplicationState from "../ApplicationState";
import ActionSheet from 'react-native-actionsheet'
@@ -52,19 +52,30 @@ export default class Filter extends Abstract {
// then wait a little to render the rest, such as a dynamic list of tags
// See https://github.com/wix/react-native-navigation/issues/358
this.syncEventHandler = Sync.get().addEventHandler((event, data) => {
if(event == "local-data-loaded") {
if(!this.props.singleSelectMode) {
// Load tags after delay
setTimeout(function () {
this.loadTags = true;
this.forceUpdate();
}.bind(this), 10);
} else {
// Load tags immediately on every render
let handleInitialDataLoad = () => {
if(this.handledDataLoad) { return; }
this.handledDataLoad = true;
if(!this.props.singleSelectMode) {
// Load tags after delay
setTimeout(function () {
this.loadTags = true;
this.forceUpdate();
}
}.bind(this), 10);
} else {
// Load tags immediately on every render
this.loadTags = true;
this.forceUpdate();
}
}
if(Sync.get().initialDataLoaded()) {
handleInitialDataLoad();
}
this.syncEventHandler = Sync.get().addEventHandler((event, data) => {
if(event == "local-data-loaded") {
handleInitialDataLoad();
}
else if(event == "sync:completed") {
@@ -196,7 +207,7 @@ export default class Filter extends Abstract {
}
createTag(text, callback) {
var tag = new SNTag({title: text});
var tag = new SNTag({content: {title: text}});
tag.initUUID().then(() => {
tag.setDirty(true);
ModelManager.get().addItem(tag);

View File

@@ -1,18 +1,21 @@
import React, { Component } from 'react';
import { StyleSheet, View, Platform, Text, StatusBar, Modal, Alert } from 'react-native';
import ModelManager from '../lib/modelManager'
import Storage from '../lib/storage'
import Sync from '../lib/sync'
import Auth from '../lib/auth'
import App from "../app"
import ModelManager from '../lib/sfjs/modelManager'
import Storage from '../lib/sfjs/storageManager'
import Sync from '../lib/sfjs/syncManager'
import AlertManager from '../lib/sfjs/alertManager'
import Auth from '../lib/authManager'
import KeysManager from '../lib/keysManager'
import AlertManager from '../lib/alertManager'
import GlobalStyles from "../Styles"
import Keychain from "../lib/keychain"
import Abstract from "./Abstract"
import GlobalStyles from "../Styles"
import Icons from '../Icons';
import NoteList from "../containers/NoteList"
import Abstract from "./Abstract"
import OptionsState from "../OptionsState"
import App from "../app"
import AuthModal from "../containers/AuthModal"
import LockedView from "../containers/LockedView"
import ApplicationState from "../ApplicationState";

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import App from '../app'
import ComponentManager from '../lib/componentManager'
import ModelManager from '../lib/modelManager'
import ModelManager from '../lib/sfjs/modelManager'
import TableSection from "../components/TableSection";
import Icons from '../Icons';
import LockedView from "../containers/LockedView";

View File

@@ -6,7 +6,7 @@ import Account from './Account'
import Authenticate from './Authenticate'
import Filter from './Filter'
import InputModal from './InputModal'
import Sync from '../lib/sync'
import Sync from '../lib/sfjs/syncManager'
import Webview from './Webview'
export function registerScreens() {