mirror of
https://github.com/laurent22/joplin.git
synced 2024-11-24 08:12:24 +02:00
Fixes for release apk
This commit is contained in:
parent
8751aa1a34
commit
216a6780cb
@ -350,8 +350,8 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
|
||||
id: noteResource.id,
|
||||
data: decodedData,
|
||||
mime: noteResource.mime,
|
||||
title: noteResource.filename,
|
||||
filename: noteResource.filename,
|
||||
title: noteResource.filename ? noteResource.filename : '',
|
||||
filename: noteResource.filename ? noteResource.filename : '',
|
||||
};
|
||||
|
||||
note.resources.push(r);
|
||||
|
@ -8,6 +8,7 @@ import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js';
|
||||
import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js';
|
||||
import { FileApiDriverLocal } from 'lib/file-api-driver-local.js';
|
||||
import { OneDriveApiNodeUtils } from './onedrive-api-node-utils.js';
|
||||
import { JoplinDatabase } from 'lib/joplin-database.js';
|
||||
import { Database } from 'lib/database.js';
|
||||
import { DatabaseDriverNode } from 'lib/database-driver-node.js';
|
||||
import { BaseModel } from 'lib/base-model.js';
|
||||
@ -927,7 +928,12 @@ async function main() {
|
||||
await fs.mkdirp(resourceDir, 0o755);
|
||||
await fs.mkdirp(tempDir, 0o755);
|
||||
|
||||
// let logDatabase = new Database(new DatabaseDriverNode());
|
||||
// await logDatabase.open({ name: profileDir + '/database-log.sqlite' });
|
||||
// await logDatabase.exec(Logger.databaseCreateTableSql());
|
||||
|
||||
logger.addTarget('file', { path: profileDir + '/log.txt' });
|
||||
// logger.addTarget('database', { database: logDatabase, source: 'main' });
|
||||
logger.setLevel(logLevel);
|
||||
|
||||
dbLogger.addTarget('file', { path: profileDir + '/log-database.txt' });
|
||||
@ -947,7 +953,7 @@ async function main() {
|
||||
BaseItem.loadClass('Tag', Tag);
|
||||
BaseItem.loadClass('NoteTag', NoteTag);
|
||||
|
||||
database_ = new Database(new DatabaseDriverNode());
|
||||
database_ = new JoplinDatabase(new DatabaseDriverNode());
|
||||
database_.setLogger(dbLogger);
|
||||
await database_.open({ name: profileDir + '/database.sqlite' });
|
||||
BaseModel.db_ = database_;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import fs from 'fs-extra';
|
||||
import { Database } from 'lib/database.js';
|
||||
import { JoplinDatabase } from 'lib/joplin-database.js';
|
||||
import { DatabaseDriverNode } from 'lib/database-driver-node.js';
|
||||
import { BaseModel } from 'lib/base-model.js';
|
||||
import { Folder } from 'lib/models/folder.js';
|
||||
@ -25,8 +25,11 @@ const fsDriver = new FsDriverNode();
|
||||
Logger.fsDriver_ = fsDriver;
|
||||
Resource.fsDriver_ = fsDriver;
|
||||
|
||||
const logDir = __dirname + '/../tests/logs';
|
||||
fs.mkdirpSync(logDir, 0o755);
|
||||
|
||||
const logger = new Logger();
|
||||
logger.addTarget('file', { path: __dirname + '/../tests/logs/log.txt' });
|
||||
logger.addTarget('file', { path: logDir + '/log.txt' });
|
||||
logger.setLevel(Logger.LEVEL_DEBUG);
|
||||
|
||||
BaseItem.loadClass('Note', Note);
|
||||
@ -87,7 +90,7 @@ function setupDatabase(id = null) {
|
||||
return fs.unlink(filePath).catch(() => {
|
||||
// Don't care if the file doesn't exist
|
||||
}).then(() => {
|
||||
databases_[id] = new Database(new DatabaseDriverNode());
|
||||
databases_[id] = new JoplinDatabase(new DatabaseDriverNode());
|
||||
databases_[id].setLogger(logger);
|
||||
return databases_[id].open({ name: filePath }).then(() => {
|
||||
BaseModel.db_ = databases_[id];
|
||||
|
@ -83,62 +83,73 @@ def enableSeparateBuildPerCPUArchitecture = false
|
||||
def enableProguardInReleaseBuilds = false
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.awesomeproject"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 22
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
|
||||
def versionCodes = ["armeabi-v7a":1, "x86":2]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId "com.awesomeproject"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 22
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
if (project.hasProperty('JOPLIN_RELEASE_STORE_FILE')) {
|
||||
storeFile file(JOPLIN_RELEASE_STORE_FILE)
|
||||
storePassword JOPLIN_RELEASE_STORE_PASSWORD
|
||||
keyAlias JOPLIN_RELEASE_KEY_ALIAS
|
||||
keyPassword JOPLIN_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
|
||||
def versionCodes = ["armeabi-v7a":1, "x86":2]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':react-native-fs')
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
compile "com.android.support:appcompat-v7:23.0.1"
|
||||
compile "com.facebook.react:react-native:+" // From node_modules
|
||||
compile project(':react-native-sqlite-storage')
|
||||
compile project(':react-native-fetch-blob')
|
||||
compile project(':react-native-fs')
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
compile "com.android.support:appcompat-v7:23.0.1"
|
||||
compile "com.facebook.react:react-native:+" // From node_modules
|
||||
compile project(':react-native-sqlite-storage')
|
||||
compile project(':react-native-fetch-blob')
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
// puts all compile dependencies into folder libs for BUCK to use
|
||||
task copyDownloadableDepsToLibs(type: Copy) {
|
||||
from configurations.compile
|
||||
into 'libs'
|
||||
from configurations.compile
|
||||
into 'libs'
|
||||
}
|
||||
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
|
@ -4,12 +4,12 @@ import com.facebook.react.ReactActivity;
|
||||
|
||||
public class MainActivity extends ReactActivity {
|
||||
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript.
|
||||
* This is used to schedule rendering of the component.
|
||||
*/
|
||||
@Override
|
||||
protected String getMainComponentName() {
|
||||
return "AwesomeProject";
|
||||
}
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript.
|
||||
* This is used to schedule rendering of the component.
|
||||
*/
|
||||
@Override
|
||||
protected String getMainComponentName() {
|
||||
return "AwesomeProject";
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ class ItemListComponent extends Component {
|
||||
await Note.save({ id: note.id, todo_completed: checked });
|
||||
}
|
||||
|
||||
listView_itemLongPress(itemId) {}
|
||||
listView_itemPress(itemId) {}
|
||||
|
||||
render() {
|
||||
@ -50,8 +51,8 @@ class ItemListComponent extends Component {
|
||||
|
||||
return (
|
||||
<TouchableHighlight onPress={onPress} onLongPress={onLongPress}>
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
{ !!Number(item.is_todo) && <Checkbox checked={!!Number(item.todo_completed)} onChange={(checked) => { this.todoCheckbox_change(item.id, checked) }}/> }<Text>{item.title} [{item.id}]</Text>
|
||||
<View style={{flexDirection: 'row', paddingLeft: 10, paddingTop:5, paddingBottom:5 }}>
|
||||
{ !!Number(item.is_todo) && <Checkbox checked={!!Number(item.todo_completed)} onChange={(checked) => { this.todoCheckbox_change(item.id, checked) }}/> }<Text>{item.title}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
|
@ -41,22 +41,6 @@ class ScreenHeaderComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
async menu_synchronize() {
|
||||
if (reg.oneDriveApi().auth()) {
|
||||
const sync = await reg.synchronizer();
|
||||
try {
|
||||
sync.start();
|
||||
} catch (error) {
|
||||
Log.error(error);
|
||||
}
|
||||
} else {
|
||||
this.props.dispatch({
|
||||
type: 'Navigation/NAVIGATE',
|
||||
routeName: 'OneDriveLogin',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let key = 0;
|
||||
let menuOptionComponents = [];
|
||||
@ -72,15 +56,10 @@ class ScreenHeaderComponent extends Component {
|
||||
menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>);
|
||||
}
|
||||
|
||||
menuOptionComponents.push(
|
||||
<MenuOption value={() => this.menu_synchronize()} key={'menuOption_' + key++}>
|
||||
<Text>{_('Synchronize')}</Text>
|
||||
</MenuOption>);
|
||||
|
||||
menuOptionComponents.push(
|
||||
<MenuOption value={1} key={'menuOption_' + key++}>
|
||||
<Text>{_('Configuration')}</Text>
|
||||
</MenuOption>);
|
||||
// menuOptionComponents.push(
|
||||
// <MenuOption value={1} key={'menuOption_' + key++}>
|
||||
// <Text>{_('Configuration')}</Text>
|
||||
// </MenuOption>);
|
||||
|
||||
let title = 'title' in this.props && this.props.title !== null ? this.props.title : _(this.props.navState.routeName);
|
||||
|
||||
|
@ -85,7 +85,7 @@ class NoteScreenComponent extends React.Component {
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
{ isTodo && <Checkbox checked={!!Number(note.todo_completed)} /> }<TextInput style={{flex:1}} value={note.title} onChangeText={(text) => this.title_changeText(text)} />
|
||||
</View>
|
||||
<TextInput style={{flex: 1, textAlignVertical: 'top'}} multiline={true} value={note.body} onChangeText={(text) => this.body_changeText(text)} />
|
||||
<TextInput style={{flex: 1, textAlignVertical: 'top', fontFamily: 'monospace'}} multiline={true} value={note.body} onChangeText={(text) => this.body_changeText(text)} />
|
||||
{ todoComponents }
|
||||
<Button title="Save note" onPress={() => this.saveNoteButton_press()} />
|
||||
</View>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { WebView, Button } from 'react-native';
|
||||
import { WebView, Button, Text } from 'react-native';
|
||||
import { connect } from 'react-redux'
|
||||
import { Log } from 'lib/log.js'
|
||||
import { Setting } from 'lib/models/setting.js'
|
||||
@ -22,10 +22,14 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
this.setState({
|
||||
webviewUrl: reg.oneDriveApi().authCodeUrl(this.redirectUrl()),
|
||||
webviewUrl: this.startUrl(),
|
||||
});
|
||||
}
|
||||
|
||||
startUrl() {
|
||||
return reg.oneDriveApi().authCodeUrl(this.redirectUrl());
|
||||
}
|
||||
|
||||
redirectUrl() {
|
||||
return 'https://login.microsoftonline.com/common/oauth2/nativeclient';
|
||||
}
|
||||
@ -37,7 +41,7 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
const url = noIdeaWhatThisIs.url;
|
||||
|
||||
if (!this.authCode_ && url.indexOf(this.redirectUrl() + '?code=') === 0) {
|
||||
console.info('URL: ' + url);
|
||||
Log.info('URL: ' + url);
|
||||
|
||||
let code = url.split('?code=');
|
||||
this.authCode_ = code[1];
|
||||
@ -48,6 +52,28 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
async webview_error(error) {
|
||||
Log.error(error);
|
||||
}
|
||||
|
||||
retryButton_click() {
|
||||
// It seems the only way it would reload the page is by loading an unrelated
|
||||
// URL, waiting a bit, and then loading the actual URL. There's probably
|
||||
// a better way to do this.
|
||||
|
||||
this.setState({
|
||||
webviewUrl: 'https://microsoft.com',
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
webviewUrl: this.startUrl(),
|
||||
});
|
||||
this.forceUpdate();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
render() {
|
||||
const source = {
|
||||
uri: this.state.webviewUrl,
|
||||
@ -60,7 +86,10 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
source={source}
|
||||
style={{marginTop: 20}}
|
||||
onNavigationStateChange={(o) => { this.webview_load(o); }}
|
||||
onError={(error) => { this.webview_error(error); }}
|
||||
/>
|
||||
|
||||
<Button title="Retry" onPress={() => { this.retryButton_click(); }}></Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { connect } from 'react-redux'
|
||||
import { Button } from 'react-native';
|
||||
import { Button, Text } from 'react-native';
|
||||
import { Log } from 'lib/log.js';
|
||||
import { Note } from 'lib/models/note.js';
|
||||
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.js'
|
||||
import { reg } from 'lib/registry.js';
|
||||
import { _ } from 'lib/locale.js';
|
||||
|
||||
const React = require('react');
|
||||
const {
|
||||
@ -11,7 +13,6 @@ const {
|
||||
ScrollView,
|
||||
View,
|
||||
Image,
|
||||
Text,
|
||||
} = require('react-native');
|
||||
const { Component } = React;
|
||||
|
||||
@ -41,6 +42,11 @@ const styles = StyleSheet.create({
|
||||
|
||||
class SideMenuContentComponent extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { syncReportText: '' };
|
||||
}
|
||||
|
||||
folder_press(folder) {
|
||||
this.props.dispatch({
|
||||
type: 'SIDE_MENU_CLOSE',
|
||||
@ -49,19 +55,57 @@ class SideMenuContentComponent extends Component {
|
||||
NotesScreenUtils.openNoteList(folder.id);
|
||||
}
|
||||
|
||||
async synchronize_press() {
|
||||
if (reg.oneDriveApi().auth()) {
|
||||
let options = {
|
||||
onProgress: (report) => {
|
||||
let line = [];
|
||||
line.push(_('Items to upload: %d/%d.', report.createRemote + report.updateRemote, report.remotesToUpdate));
|
||||
line.push(_('Remote items to delete: %d/%d.', report.deleteRemote, report.remotesToDelete));
|
||||
line.push(_('Items to download: %d/%d.', report.createLocal + report.updateLocal, report.localsToUdpate));
|
||||
line.push(_('Local items to delete: %d/%d.', report.deleteLocal, report.localsToDelete));
|
||||
this.setState({ syncReportText: line.join("\n") });
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const sync = await reg.synchronizer()
|
||||
sync.start(options);
|
||||
} catch (error) {
|
||||
Log.error(error);
|
||||
}
|
||||
} else {
|
||||
this.props.dispatch({
|
||||
type: 'Navigation/NAVIGATE',
|
||||
routeName: 'OneDriveLogin',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let buttons = [];
|
||||
let keyIndex = 0;
|
||||
let key = () => {
|
||||
return 'smitem_' + (keyIndex++);
|
||||
}
|
||||
|
||||
let items = [];
|
||||
for (let i = 0; i < this.props.folders.length; i++) {
|
||||
let f = this.props.folders[i];
|
||||
let title = f.title ? f.title : '';
|
||||
buttons.push(
|
||||
<Button style={styles.button} title={title} onPress={() => { this.folder_press(f) }} key={f.id} />
|
||||
items.push(
|
||||
<Button style={styles.button} title={title} onPress={() => { this.folder_press(f) }} key={key()} />
|
||||
);
|
||||
}
|
||||
|
||||
items.push(<Text key={key()}></Text>); // DIVIDER
|
||||
|
||||
items.push(<Button style={styles.button} title="Synchronize" onPress={() => { this.synchronize_press() }} key={key()} />);
|
||||
|
||||
items.push(<Text key={key()}>{this.state.syncReportText}</Text>);
|
||||
|
||||
return (
|
||||
<ScrollView scrollsToTop={false} style={styles.menu}>
|
||||
{ buttons }
|
||||
{ items }
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
@ -2,120 +2,16 @@ import { uuid } from 'lib/uuid.js';
|
||||
import { promiseChain } from 'lib/promise-utils.js';
|
||||
import { Logger } from 'lib/logger.js'
|
||||
import { time } from 'lib/time-utils.js'
|
||||
import { _ } from 'lib/locale.js'
|
||||
import { sprintf } from 'sprintf-js';
|
||||
|
||||
const structureSql = `
|
||||
CREATE TABLE folders (
|
||||
id TEXT PRIMARY KEY,
|
||||
parent_id TEXT NOT NULL DEFAULT "",
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX folders_title ON folders (title);
|
||||
CREATE INDEX folders_updated_time ON folders (updated_time);
|
||||
CREATE INDEX folders_sync_time ON folders (sync_time);
|
||||
|
||||
CREATE TABLE notes (
|
||||
id TEXT PRIMARY KEY,
|
||||
parent_id TEXT NOT NULL DEFAULT "",
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
body TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0,
|
||||
is_conflict INT NOT NULL DEFAULT 0,
|
||||
latitude NUMERIC NOT NULL DEFAULT 0,
|
||||
longitude NUMERIC NOT NULL DEFAULT 0,
|
||||
altitude NUMERIC NOT NULL DEFAULT 0,
|
||||
author TEXT NOT NULL DEFAULT "",
|
||||
source_url TEXT NOT NULL DEFAULT "",
|
||||
is_todo INT NOT NULL DEFAULT 0,
|
||||
todo_due INT NOT NULL DEFAULT 0,
|
||||
todo_completed INT NOT NULL DEFAULT 0,
|
||||
source TEXT NOT NULL DEFAULT "",
|
||||
source_application TEXT NOT NULL DEFAULT "",
|
||||
application_data TEXT NOT NULL DEFAULT "",
|
||||
\`order\` INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX notes_title ON notes (title);
|
||||
CREATE INDEX notes_updated_time ON notes (updated_time);
|
||||
CREATE INDEX notes_sync_time ON notes (sync_time);
|
||||
CREATE INDEX notes_is_conflict ON notes (is_conflict);
|
||||
CREATE INDEX notes_is_todo ON notes (is_todo);
|
||||
CREATE INDEX notes_order ON notes (\`order\`);
|
||||
|
||||
CREATE TABLE deleted_items (
|
||||
id INTEGER PRIMARY KEY,
|
||||
item_type INT NOT NULL,
|
||||
item_id TEXT NOT NULL,
|
||||
deleted_time INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE tags (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE note_tags (
|
||||
id TEXT PRIMARY KEY,
|
||||
note_id TEXT NOT NULL,
|
||||
tag_id TEXT NOT NULL,
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE resources (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
mime TEXT NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE settings (
|
||||
\`key\` TEXT PRIMARY KEY,
|
||||
\`value\` TEXT,
|
||||
\`type\` INT
|
||||
);
|
||||
|
||||
CREATE TABLE table_fields (
|
||||
id INTEGER PRIMARY KEY,
|
||||
table_name TEXT,
|
||||
field_name TEXT,
|
||||
field_type INT,
|
||||
field_default TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE version (
|
||||
version INT
|
||||
);
|
||||
|
||||
INSERT INTO version (version) VALUES (1);
|
||||
`;
|
||||
|
||||
class Database {
|
||||
|
||||
constructor(driver) {
|
||||
this.debugMode_ = false;
|
||||
this.initialized_ = false;
|
||||
this.tableFields_ = null;
|
||||
this.driver_ = driver;
|
||||
this.inTransaction_ = false;
|
||||
|
||||
this.logger_ = new Logger();
|
||||
this.logger_.addTarget('console');
|
||||
this.logger_.setLevel(Logger.LEVEL_DEBUG);
|
||||
}
|
||||
|
||||
// Converts the SQLite error to a regular JS error
|
||||
@ -133,10 +29,6 @@ class Database {
|
||||
return this.logger_;
|
||||
}
|
||||
|
||||
initialized() {
|
||||
return this.initialized_;
|
||||
}
|
||||
|
||||
driver() {
|
||||
return this.driver_;
|
||||
}
|
||||
@ -144,7 +36,6 @@ class Database {
|
||||
async open(options) {
|
||||
await this.driver().open(options);
|
||||
this.logger().info('Database was open successfully');
|
||||
return this.initialize();
|
||||
}
|
||||
|
||||
escapeField(field) {
|
||||
@ -251,26 +142,12 @@ class Database {
|
||||
if (s == 'string') return 2;
|
||||
}
|
||||
if (type == 'fieldType') {
|
||||
if (s == 'INTEGER') s = 'INT';
|
||||
return this['TYPE_' + s];
|
||||
}
|
||||
throw new Error('Unknown enum type or value: ' + type + ', ' + s);
|
||||
}
|
||||
|
||||
tableFieldNames(tableName) {
|
||||
let tf = this.tableFields(tableName);
|
||||
let output = [];
|
||||
for (let i = 0; i < tf.length; i++) {
|
||||
output.push(tf[i].name);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
tableFields(tableName) {
|
||||
if (!this.tableFields_) throw new Error('Fields have not been loaded yet');
|
||||
if (!this.tableFields_[tableName]) throw new Error('Unknown table: ' + tableName);
|
||||
return this.tableFields_[tableName];
|
||||
}
|
||||
|
||||
static formatValue(type, value) {
|
||||
if (value === null || value === undefined) return null;
|
||||
if (type == this.TYPE_INT) return Number(value);
|
||||
@ -369,98 +246,6 @@ class Database {
|
||||
}
|
||||
}
|
||||
|
||||
refreshTableFields() {
|
||||
this.logger().info('Initializing tables...');
|
||||
let queries = [];
|
||||
queries.push(this.wrapQuery('DELETE FROM table_fields'));
|
||||
|
||||
return this.selectAll('SELECT name FROM sqlite_master WHERE type="table"').then((tableRows) => {
|
||||
let chain = [];
|
||||
for (let i = 0; i < tableRows.length; i++) {
|
||||
let tableName = tableRows[i].name;
|
||||
if (tableName == 'android_metadata') continue;
|
||||
if (tableName == 'table_fields') continue;
|
||||
chain.push(() => {
|
||||
return this.selectAll('PRAGMA table_info("' + tableName + '")').then((pragmas) => {
|
||||
for (let i = 0; i < pragmas.length; i++) {
|
||||
let item = pragmas[i];
|
||||
// In SQLite, if the default value is a string it has double quotes around it, so remove them here
|
||||
let defaultValue = item.dflt_value;
|
||||
if (typeof defaultValue == 'string' && defaultValue.length >= 2 && defaultValue[0] == '"' && defaultValue[defaultValue.length - 1] == '"') {
|
||||
defaultValue = defaultValue.substr(1, defaultValue.length - 2);
|
||||
}
|
||||
let q = Database.insertQuery('table_fields', {
|
||||
table_name: tableName,
|
||||
field_name: item.name,
|
||||
field_type: Database.enumId('fieldType', item.type),
|
||||
field_default: defaultValue,
|
||||
});
|
||||
queries.push(q);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return promiseChain(chain);
|
||||
}).then(() => {
|
||||
return this.transactionExecBatch(queries);
|
||||
});
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
this.logger().info('Checking for database schema update...');
|
||||
|
||||
for (let initLoopCount = 1; initLoopCount <= 2; initLoopCount++) {
|
||||
try {
|
||||
let row = await this.selectOne('SELECT * FROM version LIMIT 1');
|
||||
this.logger().info('Current database version', row);
|
||||
|
||||
// TODO: version update logic
|
||||
// TODO: only do this if db has been updated:
|
||||
// return this.refreshTableFields();
|
||||
} catch (error) {
|
||||
if (error && error.code != 0 && error.code != 'SQLITE_ERROR') throw this.sqliteErrorToJsError(error);
|
||||
|
||||
// Assume that error was:
|
||||
// { message: 'no such table: version (code 1): , while compiling: SELECT * FROM version', code: 0 }
|
||||
// which means the database is empty and the tables need to be created.
|
||||
// If it's any other error there's nothing we can do anyway.
|
||||
|
||||
this.logger().info('Database is new - creating the schema...');
|
||||
|
||||
let queries = this.wrapQueries(this.sqlStringToLines(structureSql));
|
||||
queries.push(this.wrapQuery('INSERT INTO settings (`key`, `value`, `type`) VALUES ("clientId", "' + uuid.create() + '", "' + Database.enumId('settings', 'string') + '")'));
|
||||
|
||||
try {
|
||||
await this.transactionExecBatch(queries);
|
||||
this.logger().info('Database schema created successfully');
|
||||
await this.refreshTableFields();
|
||||
} catch (error) {
|
||||
throw this.sqliteErrorToJsError(error);
|
||||
}
|
||||
|
||||
// Now that the database has been created, go through the normal initialisation process
|
||||
continue;
|
||||
}
|
||||
|
||||
this.tableFields_ = {};
|
||||
|
||||
let rows = await this.selectAll('SELECT * FROM table_fields');
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i];
|
||||
if (!this.tableFields_[row.table_name]) this.tableFields_[row.table_name] = [];
|
||||
this.tableFields_[row.table_name].push({
|
||||
name: row.field_name,
|
||||
type: row.field_type,
|
||||
default: Database.formatValue(row.field_type, row.field_default),
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Database.TYPE_INT = 1;
|
||||
|
248
ReactNativeClient/lib/joplin-database.js
Normal file
248
ReactNativeClient/lib/joplin-database.js
Normal file
@ -0,0 +1,248 @@
|
||||
import { uuid } from 'lib/uuid.js';
|
||||
import { promiseChain } from 'lib/promise-utils.js';
|
||||
import { time } from 'lib/time-utils.js'
|
||||
import { Database } from 'lib/database.js'
|
||||
|
||||
const structureSql = `
|
||||
CREATE TABLE folders (
|
||||
id TEXT PRIMARY KEY,
|
||||
parent_id TEXT NOT NULL DEFAULT "",
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX folders_title ON folders (title);
|
||||
CREATE INDEX folders_updated_time ON folders (updated_time);
|
||||
CREATE INDEX folders_sync_time ON folders (sync_time);
|
||||
|
||||
CREATE TABLE notes (
|
||||
id TEXT PRIMARY KEY,
|
||||
parent_id TEXT NOT NULL DEFAULT "",
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
body TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0,
|
||||
is_conflict INT NOT NULL DEFAULT 0,
|
||||
latitude NUMERIC NOT NULL DEFAULT 0,
|
||||
longitude NUMERIC NOT NULL DEFAULT 0,
|
||||
altitude NUMERIC NOT NULL DEFAULT 0,
|
||||
author TEXT NOT NULL DEFAULT "",
|
||||
source_url TEXT NOT NULL DEFAULT "",
|
||||
is_todo INT NOT NULL DEFAULT 0,
|
||||
todo_due INT NOT NULL DEFAULT 0,
|
||||
todo_completed INT NOT NULL DEFAULT 0,
|
||||
source TEXT NOT NULL DEFAULT "",
|
||||
source_application TEXT NOT NULL DEFAULT "",
|
||||
application_data TEXT NOT NULL DEFAULT "",
|
||||
\`order\` INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX notes_title ON notes (title);
|
||||
CREATE INDEX notes_updated_time ON notes (updated_time);
|
||||
CREATE INDEX notes_sync_time ON notes (sync_time);
|
||||
CREATE INDEX notes_is_conflict ON notes (is_conflict);
|
||||
CREATE INDEX notes_is_todo ON notes (is_todo);
|
||||
CREATE INDEX notes_order ON notes (\`order\`);
|
||||
|
||||
CREATE TABLE deleted_items (
|
||||
id INTEGER PRIMARY KEY,
|
||||
item_type INT NOT NULL,
|
||||
item_id TEXT NOT NULL,
|
||||
deleted_time INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE tags (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX tags_title ON tags (title);
|
||||
CREATE INDEX tags_updated_time ON tags (updated_time);
|
||||
CREATE INDEX tags_sync_time ON tags (sync_time);
|
||||
|
||||
CREATE TABLE note_tags (
|
||||
id TEXT PRIMARY KEY,
|
||||
note_id TEXT NOT NULL,
|
||||
tag_id TEXT NOT NULL,
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX note_tags_note_id ON note_tags (note_id);
|
||||
CREATE INDEX note_tags_tag_id ON note_tags (tag_id);
|
||||
CREATE INDEX note_tags_updated_time ON note_tags (updated_time);
|
||||
CREATE INDEX note_tags_sync_time ON note_tags (sync_time);
|
||||
|
||||
CREATE TABLE resources (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL DEFAULT "",
|
||||
mime TEXT NOT NULL,
|
||||
filename TEXT NOT NULL DEFAULT "",
|
||||
created_time INT NOT NULL,
|
||||
updated_time INT NOT NULL,
|
||||
sync_time INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX resources_title ON resources (title);
|
||||
CREATE INDEX resources_updated_time ON resources (updated_time);
|
||||
CREATE INDEX resources_sync_time ON resources (sync_time);
|
||||
|
||||
CREATE TABLE settings (
|
||||
\`key\` TEXT PRIMARY KEY,
|
||||
\`value\` TEXT,
|
||||
\`type\` INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE table_fields (
|
||||
id INTEGER PRIMARY KEY,
|
||||
table_name TEXT NOT NULL,
|
||||
field_name TEXT NOT NULL,
|
||||
field_type INT NOT NULL,
|
||||
field_default TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE version (
|
||||
version INT NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO version (version) VALUES (1);
|
||||
`;
|
||||
|
||||
class JoplinDatabase extends Database {
|
||||
|
||||
constructor(driver) {
|
||||
super(driver);
|
||||
this.initialized_ = false;
|
||||
this.tableFields_ = null;
|
||||
}
|
||||
|
||||
initialized() {
|
||||
return this.initialized_;
|
||||
}
|
||||
|
||||
async open(options) {
|
||||
await super.open(options);
|
||||
return this.initialize();
|
||||
}
|
||||
|
||||
tableFieldNames(tableName) {
|
||||
let tf = this.tableFields(tableName);
|
||||
let output = [];
|
||||
for (let i = 0; i < tf.length; i++) {
|
||||
output.push(tf[i].name);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
tableFields(tableName) {
|
||||
if (!this.tableFields_) throw new Error('Fields have not been loaded yet');
|
||||
if (!this.tableFields_[tableName]) throw new Error('Unknown table: ' + tableName);
|
||||
return this.tableFields_[tableName];
|
||||
}
|
||||
|
||||
refreshTableFields() {
|
||||
this.logger().info('Initializing tables...');
|
||||
let queries = [];
|
||||
queries.push(this.wrapQuery('DELETE FROM table_fields'));
|
||||
|
||||
return this.selectAll('SELECT name FROM sqlite_master WHERE type="table"').then((tableRows) => {
|
||||
let chain = [];
|
||||
for (let i = 0; i < tableRows.length; i++) {
|
||||
let tableName = tableRows[i].name;
|
||||
if (tableName == 'android_metadata') continue;
|
||||
if (tableName == 'table_fields') continue;
|
||||
chain.push(() => {
|
||||
return this.selectAll('PRAGMA table_info("' + tableName + '")').then((pragmas) => {
|
||||
for (let i = 0; i < pragmas.length; i++) {
|
||||
let item = pragmas[i];
|
||||
// In SQLite, if the default value is a string it has double quotes around it, so remove them here
|
||||
let defaultValue = item.dflt_value;
|
||||
if (typeof defaultValue == 'string' && defaultValue.length >= 2 && defaultValue[0] == '"' && defaultValue[defaultValue.length - 1] == '"') {
|
||||
defaultValue = defaultValue.substr(1, defaultValue.length - 2);
|
||||
}
|
||||
let q = Database.insertQuery('table_fields', {
|
||||
table_name: tableName,
|
||||
field_name: item.name,
|
||||
field_type: Database.enumId('fieldType', item.type),
|
||||
field_default: defaultValue,
|
||||
});
|
||||
queries.push(q);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return promiseChain(chain);
|
||||
}).then(() => {
|
||||
return this.transactionExecBatch(queries);
|
||||
});
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
this.logger().info('Checking for database schema update...');
|
||||
|
||||
for (let initLoopCount = 1; initLoopCount <= 2; initLoopCount++) {
|
||||
try {
|
||||
let row = await this.selectOne('SELECT * FROM version LIMIT 1');
|
||||
this.logger().info('Current database version', row);
|
||||
|
||||
// TODO: version update logic
|
||||
// TODO: only do this if db has been updated:
|
||||
// return this.refreshTableFields();
|
||||
} catch (error) {
|
||||
if (error && error.code != 0 && error.code != 'SQLITE_ERROR') throw this.sqliteErrorToJsError(error);
|
||||
|
||||
// Assume that error was:
|
||||
// { message: 'no such table: version (code 1): , while compiling: SELECT * FROM version', code: 0 }
|
||||
// which means the database is empty and the tables need to be created.
|
||||
// If it's any other error there's nothing we can do anyway.
|
||||
|
||||
this.logger().info('Database is new - creating the schema...');
|
||||
|
||||
let queries = this.wrapQueries(this.sqlStringToLines(structureSql));
|
||||
queries.push(this.wrapQuery('INSERT INTO settings (`key`, `value`, `type`) VALUES ("clientId", "' + uuid.create() + '", "' + Database.enumId('settings', 'string') + '")'));
|
||||
|
||||
try {
|
||||
await this.transactionExecBatch(queries);
|
||||
this.logger().info('Database schema created successfully');
|
||||
await this.refreshTableFields();
|
||||
} catch (error) {
|
||||
throw this.sqliteErrorToJsError(error);
|
||||
}
|
||||
|
||||
// Now that the database has been created, go through the normal initialisation process
|
||||
continue;
|
||||
}
|
||||
|
||||
this.tableFields_ = {};
|
||||
|
||||
let rows = await this.selectAll('SELECT * FROM table_fields');
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i];
|
||||
if (!this.tableFields_[row.table_name]) this.tableFields_[row.table_name] = [];
|
||||
this.tableFields_[row.table_name].push({
|
||||
name: row.field_name,
|
||||
type: row.field_type,
|
||||
default: Database.formatValue(row.field_type, row.field_default),
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Database.TYPE_INT = 1;
|
||||
Database.TYPE_TEXT = 2;
|
||||
Database.TYPE_NUMERIC = 3;
|
||||
|
||||
export { JoplinDatabase };
|
@ -1,5 +1,6 @@
|
||||
import moment from 'moment';
|
||||
import { _ } from 'lib/locale.js';
|
||||
import { time } from 'lib/time-utils.js';
|
||||
import { FsDriverDummy } from 'lib/fs-driver-dummy.js';
|
||||
|
||||
class Logger {
|
||||
@ -37,6 +38,36 @@ class Logger {
|
||||
this.targets_.push(target);
|
||||
}
|
||||
|
||||
objectToString(object) {
|
||||
let output = '';
|
||||
|
||||
if (typeof object === 'object') {
|
||||
if (object instanceof Error) {
|
||||
output = object.toString();
|
||||
if (object.stack) output += "\n" + object.stack;
|
||||
} else {
|
||||
output = JSON.stringify(object);
|
||||
}
|
||||
} else {
|
||||
output = object;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static databaseCreateTableSql() {
|
||||
let output = `
|
||||
CREATE TABLE logs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
source TEXT,
|
||||
level INT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
\`timestamp\` INT NOT NULL
|
||||
);
|
||||
`;
|
||||
return output.split("\n").join(' ');
|
||||
}
|
||||
|
||||
log(level, object) {
|
||||
if (this.level() < level || !this.targets_.length) return;
|
||||
|
||||
@ -47,8 +78,8 @@ class Logger {
|
||||
let line = moment().format('YYYY-MM-DD HH:mm:ss') + ': ' + levelString;
|
||||
|
||||
for (let i = 0; i < this.targets_.length; i++) {
|
||||
let t = this.targets_[i];
|
||||
if (t.type == 'console') {
|
||||
let target = this.targets_[i];
|
||||
if (target.type == 'console') {
|
||||
let fn = 'debug';
|
||||
if (level = Logger.LEVEL_ERROR) fn = 'error';
|
||||
if (level = Logger.LEVEL_WARN) fn = 'warn';
|
||||
@ -58,49 +89,18 @@ class Logger {
|
||||
} else {
|
||||
console[fn](line + object);
|
||||
}
|
||||
} else if (t.type == 'file') {
|
||||
let serializedObject = '';
|
||||
|
||||
if (typeof object === 'object') {
|
||||
if (object instanceof Error) {
|
||||
serializedObject = object.toString();
|
||||
if (object.stack) serializedObject += "\n" + object.stack;
|
||||
} else {
|
||||
serializedObject = JSON.stringify(object);
|
||||
}
|
||||
} else {
|
||||
serializedObject = object;
|
||||
}
|
||||
|
||||
Logger.fsDriver().appendFileSync(t.path, line + serializedObject + "\n");
|
||||
|
||||
// this.fileAppendQueue_.push({
|
||||
// path: t.path,
|
||||
// line: line + serializedObject + "\n",
|
||||
// });
|
||||
|
||||
// this.scheduleFileAppendQueueProcessing_();
|
||||
} else if (t.type == 'vorpal') {
|
||||
t.vorpal.log(object);
|
||||
} else if (target.type == 'file') {
|
||||
let serializedObject = this.objectToString(object);
|
||||
Logger.fsDriver().appendFileSync(target.path, line + serializedObject + "\n");
|
||||
} else if (target.type == 'vorpal') {
|
||||
target.vorpal.log(object);
|
||||
} else if (target.type == 'database') {
|
||||
let msg = this.objectToString(object);
|
||||
target.database.exec('INSERT INTO logs (`source`, `level`, `message`, `timestamp`) VALUES (?, ?, ?, ?)', [target.source, level, msg, time.unixMs()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scheduleFileAppendQueueProcessing_() {
|
||||
// if (this.fileAppendQueueTID_) return;
|
||||
|
||||
// this.fileAppendQueueTID_ = setTimeout(async () => {
|
||||
// this.fileAppendQueueTID_ = null;
|
||||
|
||||
// let queue = this.fileAppendQueue_.slice(0);
|
||||
// for (let i = 0; i < queue.length; i++) {
|
||||
// let t = queue[i];
|
||||
// await fs.appendFile(t.path, t.line);
|
||||
// }
|
||||
// this.fileAppendQueue_.splice(0, queue.length);
|
||||
// }, 1);
|
||||
// }
|
||||
|
||||
error(object) { return this.log(Logger.LEVEL_ERROR, object); }
|
||||
warn(object) { return this.log(Logger.LEVEL_WARN, object); }
|
||||
info(object) { return this.log(Logger.LEVEL_INFO, object); }
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Database } from 'lib/database.js';
|
||||
import { BaseItem } from 'lib/models/base-item.js';
|
||||
import { BaseModel } from 'lib/base-model.js';
|
||||
import lodash from 'lodash';
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { BaseModel } from 'lib/base-model.js';
|
||||
import { Database } from 'lib/database.js';
|
||||
import { BaseItem } from 'lib/models/base-item.js';
|
||||
import { NoteTag } from 'lib/models/note-tag.js';
|
||||
import { Note } from 'lib/models/note.js';
|
||||
|
@ -15,7 +15,7 @@ import { Tag } from 'lib/models/tag.js'
|
||||
import { NoteTag } from 'lib/models/note-tag.js'
|
||||
import { BaseItem } from 'lib/models/base-item.js'
|
||||
import { BaseModel } from 'lib/base-model.js'
|
||||
import { Database } from 'lib/database.js'
|
||||
import { JoplinDatabase } from 'lib/joplin-database.js'
|
||||
import { ItemList } from 'lib/components/item-list.js'
|
||||
import { NotesScreen } from 'lib/components/screens/notes.js'
|
||||
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.js'
|
||||
@ -32,6 +32,7 @@ import { SideMenu } from 'lib/components/side-menu.js';
|
||||
import { SideMenuContent } from 'lib/components/side-menu-content.js';
|
||||
import { DatabaseDriverReactNative } from 'lib/database-driver-react-native';
|
||||
import { reg } from 'lib/registry.js';
|
||||
import RNFetchBlob from 'react-native-fetch-blob';
|
||||
|
||||
let defaultState = {
|
||||
notes: [],
|
||||
@ -194,9 +195,6 @@ const AppNavigator = StackNavigator({
|
||||
OneDriveLogin: { screen: OneDriveLoginScreen },
|
||||
});
|
||||
|
||||
import RNFetchBlob from 'react-native-fetch-blob'
|
||||
|
||||
|
||||
class AppComponent extends React.Component {
|
||||
|
||||
async componentDidMount() {
|
||||
@ -235,7 +233,7 @@ class AppComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
let db = new Database(new DatabaseDriverReactNative());
|
||||
let db = new JoplinDatabase(new DatabaseDriverReactNative());
|
||||
reg.setDb(db);
|
||||
|
||||
BaseModel.dispatch = this.props.dispatch;
|
||||
@ -249,7 +247,7 @@ class AppComponent extends React.Component {
|
||||
BaseItem.loadClass('NoteTag', NoteTag);
|
||||
|
||||
try {
|
||||
await db.open({ name: '/storage/emulated/0/Download/joplin-44.sqlite' })
|
||||
await db.open({ name: '/storage/emulated/0/Download/joplin-48.sqlite' })
|
||||
Log.info('Database is ready.');
|
||||
|
||||
//await db.exec('DELETE FROM notes');
|
||||
|
@ -4,11 +4,6 @@
|
||||
{
|
||||
"path": ".",
|
||||
"folder_exclude_patterns": [
|
||||
"var",
|
||||
"vendor",
|
||||
"QtClient/build-JoplinQtClient-Visual_C_32_bits-Debug",
|
||||
"QtClient/data/resources",
|
||||
"app/data/uploads",
|
||||
"CliClient/node_modules",
|
||||
"CliClient/build",
|
||||
"CliClient/tests-build",
|
||||
@ -27,29 +22,11 @@
|
||||
"_vieux",
|
||||
],
|
||||
"file_exclude_patterns": [
|
||||
"*.pro.user",
|
||||
"*.pro.user.*",
|
||||
"*.iml",
|
||||
"*.map",
|
||||
"CliClient/app/src",
|
||||
"CliClient/app/lib",
|
||||
"*.jar",
|
||||
]
|
||||
}
|
||||
],
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name": "Build evernote-import",
|
||||
"shell_cmd": "D:\\Programmes\\cygwin\\bin\\bash.exe --login D:\\Web\\www\\joplin\\QtClient\\evernote-import\\build.sh"
|
||||
},
|
||||
{
|
||||
"name": "Qt Creator - Build and run",
|
||||
"shell_cmd": "D:\\NonPortableApps\\AutoHotkey\\AutoHotkey.exe D:\\Docs\\PROGS\\AutoHotKey\\QtRun\\QtRun.ahk"
|
||||
},
|
||||
{
|
||||
"name": "Build QtClient CLI - Linux",
|
||||
"shell_cmd": "/home/laurent/src/notes/QtClient/JoplinQtClient/build.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user