Compare commits
65 Commits
v0.10.21
...
v0.10.59-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f51ad26db7 | ||
|
|
0428917ea2 | ||
|
|
914a2554ab | ||
|
|
26bb7dc33b | ||
|
|
8e5b0eadd9 | ||
|
|
a96b91cfef | ||
|
|
03251d4c40 | ||
|
|
112609c5f1 | ||
|
|
cc7cbc2ecf | ||
|
|
946ad7c71a | ||
|
|
d7f3cfd778 | ||
|
|
a2ae2c766a | ||
|
|
f52ff730b1 | ||
|
|
9327a61a36 | ||
|
|
05997908e5 | ||
|
|
2a93dea378 | ||
|
|
fbf7b2cc43 | ||
|
|
d8b19f7d08 | ||
|
|
acc4eb5d28 | ||
|
|
bcd5cd9110 | ||
|
|
45a4034816 | ||
|
|
978a08fb06 | ||
|
|
72dc5a6c99 | ||
|
|
5340fb8af9 | ||
|
|
3ce1172c36 | ||
|
|
e4d48f43d6 | ||
|
|
3e1ea0eb0a | ||
|
|
d10d6ba7de | ||
|
|
cf832354a2 | ||
|
|
b27519b85a | ||
|
|
27af0e69ef | ||
|
|
6283bf6190 | ||
|
|
48b648e656 | ||
|
|
367a18db93 | ||
|
|
f5feb595f6 | ||
|
|
c6ec0279fc | ||
|
|
b0b5488c2e | ||
|
|
3722012da5 | ||
|
|
c5214b6c44 | ||
|
|
585ccc2b8b | ||
|
|
ab8115b89d | ||
|
|
8d8395c226 | ||
|
|
8dbec0e8f4 | ||
|
|
1c1228bb88 | ||
|
|
7d9eec262a | ||
|
|
a057fbf3bd | ||
|
|
518feadc3e | ||
|
|
b1e351ce77 | ||
|
|
c6cb2800d7 | ||
|
|
c31c7a8a67 | ||
|
|
3d6fe4c2cd | ||
|
|
da7034ae08 | ||
|
|
37de5fd4b3 | ||
|
|
e2cbef1538 | ||
|
|
4de044dc90 | ||
|
|
d5dc27d788 | ||
|
|
e80dd59da2 | ||
|
|
cbd2075156 | ||
|
|
4b5c1491d0 | ||
|
|
ea077852a1 | ||
|
|
ca20a2a1c2 | ||
|
|
37c0b6d24a | ||
|
|
0c14a42b28 | ||
|
|
f126e0a944 | ||
|
|
9519bb1218 |
5
.gitignore
vendored
@@ -32,4 +32,7 @@ INFO.md
|
||||
sync_staging.sh
|
||||
*.swp
|
||||
_vieux/
|
||||
_mydocs
|
||||
_mydocs
|
||||
.DS_Store
|
||||
Assets/DownloadBadges*.psd
|
||||
node_modules
|
||||
BIN
Assets/DemoDesktop.PNG
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
Assets/DemoDesktop.psd
Normal file
BIN
Assets/Icon-Android-1024.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
Assets/Icon-Android-512.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
Assets/Icon-Android.psd
Normal file
BIN
Assets/Icon-ios-512.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
Assets/Icon-ios.psd
Normal file
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
BIN
Assets/Screenshots/Screenshot_1511192771.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
Assets/Screenshots/Screenshot_1511192805.png
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
Assets/Screenshots/Screenshot_1511193130.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
Assets/Screenshots/Screenshot_1511193142.png
Normal file
|
After Width: | Height: | Size: 277 KiB |
BIN
Assets/Screenshots/Screenshot_1511193169.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
Assets/Screenshots/Screenshot_1511193181.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
Assets/Screenshots/Screenshot_1511193188.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
Assets/Screenshots/Screenshot_1511193192.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
Assets/Screenshots/iOS/Screenshot_iPad_Paysage.jpg
Normal file
|
After Width: | Height: | Size: 288 KiB |
BIN
Assets/Screenshots/iOS/Screenshot_iPad_Paysage.png
Normal file
|
After Width: | Height: | Size: 335 KiB |
BIN
Assets/Screenshots/iOS/Screenshot_iPad_Paysage.psd
Normal file
BIN
Assets/Screenshots/iOS/Screenshot_iPhone_Portrait.jpg
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
Assets/Screenshots/iOS/Screenshot_iPhone_Portrait.png
Normal file
|
After Width: | Height: | Size: 254 KiB |
BIN
Assets/Screenshots/iOS/Screenshot_iPhone_Portrait.psd
Normal file
2
Assets/check-square-o.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1472 930v318q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q63 0 117 25 15 7 18 23 3 17-9 29l-49 49q-10 10-23 10-3 0-9-2-23-6-45-6h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-254q0-13 9-22l64-64q10-10 23-10 6 0 12 3 20 8 20 29zm231-489l-814 814q-24 24-57 24t-57-24l-430-430q-24-24-24-57t24-57l110-110q24-24 57-24t57 24l263 263 647-647q24-24 57-24t57 24l110 110q24 24 24 57t-24 57z"/></svg>
|
||||
|
After Width: | Height: | Size: 612 B |
2
Assets/check-square.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M813 1299l614-614q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-467 467-211-211q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l358 358q19 19 45 19t45-19zm851-883v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"/></svg>
|
||||
|
After Width: | Height: | Size: 447 B |
BIN
Assets/iOSIcons/29.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Assets/iOSIcons/29x2.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Assets/iOSIcons/29x3.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
Assets/iOSIcons/40.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Assets/iOSIcons/40x2.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
Assets/iOSIcons/40x3.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
Assets/iOSIcons/57.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Assets/iOSIcons/57x2.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
Assets/iOSIcons/60x2.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
Assets/iOSIcons/60x3.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Assets/iOSIcons/AppStore.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
2
Assets/square-o.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<svg viewBox='0 0 1792 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1312 256h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-832q0-66-47-113t-113-47zm288 160v832q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z'/></svg>
|
||||
|
After Width: | Height: | Size: 370 B |
@@ -167,7 +167,7 @@ class AppGui {
|
||||
});
|
||||
this.rootWidget_.connect(noteList, (state) => {
|
||||
return {
|
||||
selectedNoteId: state.selectedNoteId,
|
||||
selectedNoteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||
items: state.notes,
|
||||
};
|
||||
});
|
||||
@@ -181,7 +181,7 @@ class AppGui {
|
||||
};
|
||||
this.rootWidget_.connect(noteText, (state) => {
|
||||
return {
|
||||
noteId: state.selectedNoteId,
|
||||
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||
notes: state.notes,
|
||||
};
|
||||
});
|
||||
@@ -195,7 +195,7 @@ class AppGui {
|
||||
borderRightWidth: 1,
|
||||
};
|
||||
this.rootWidget_.connect(noteMetadata, (state) => {
|
||||
return { noteId: state.selectedNoteId };
|
||||
return { noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null };
|
||||
});
|
||||
noteMetadata.hide();
|
||||
|
||||
|
||||
@@ -168,9 +168,9 @@ class Application extends BaseApplication {
|
||||
await doExit();
|
||||
}, 5000);
|
||||
|
||||
if (await reg.syncStarted()) {
|
||||
if (await reg.syncTarget().syncStarted()) {
|
||||
this.stdout(_('Cancelling background synchronisation... Please wait.'));
|
||||
const sync = await reg.synchronizer(Setting.value('sync.target'));
|
||||
const sync = await reg.syncTarget().synchronizer();
|
||||
await sync.cancel();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ const headerHtml = `<!doctype html>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="https://opensource.keycdn.com/fontawesome/4.7.0/font-awesome.min.css" integrity="sha384-dNpIIXE8U05kAbPhy3G1cz+yZmTzA6CY8Vg/u2L9xRnHjJiAK76m2BIEaSEV+/aU" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
body {
|
||||
@@ -90,6 +91,10 @@ const headerHtml = `<!doctype html>
|
||||
.cli-screenshot .prompt {
|
||||
color: #48C2F0;
|
||||
}
|
||||
.top-screenshot {
|
||||
margin-top: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
.header {
|
||||
position: relative;
|
||||
padding-left: 2em;
|
||||
@@ -128,16 +133,13 @@ const headerHtml = `<!doctype html>
|
||||
.nav a {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
padding: .7em 1.4em .7em 1.4em;
|
||||
}
|
||||
.nav.sticky a {
|
||||
padding: .4em 1.4em .4em 1.4em;
|
||||
padding: .6em .9em .6em .9em;
|
||||
}
|
||||
.nav ul {
|
||||
padding-left: 2em;
|
||||
margin-bottom: 0;
|
||||
display: table-cell;
|
||||
min-width: 400px;
|
||||
min-width: 165px;
|
||||
}
|
||||
.nav ul li {
|
||||
display: inline-block;
|
||||
@@ -152,15 +154,29 @@ const headerHtml = `<!doctype html>
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
padding-top: 3px;
|
||||
line-height: 0;
|
||||
}
|
||||
.twitter-share-button {
|
||||
|
||||
.nav-right .share-btn {
|
||||
display: none;
|
||||
}
|
||||
.github-share-button {
|
||||
.share-btn-github {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
.nav-right .small-share-btn {
|
||||
display: none;
|
||||
}
|
||||
.nav-right .share-btn-github {
|
||||
display: inline-block;
|
||||
}
|
||||
@media all and (min-width: 400px) {
|
||||
.nav-right .share-btn {
|
||||
display: inline-block;
|
||||
}
|
||||
.nav-right .small-share-btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -176,13 +192,14 @@ const headerHtml = `<!doctype html>
|
||||
<div class="nav-wrapper">
|
||||
<div class="nav">
|
||||
<ul>
|
||||
<li class="{{selectedHome}}"><a href="{{baseUrl}}/">Home</a></li>
|
||||
<li class="{{selectedTerminal}}"><a href="{{baseUrl}}/terminal">Terminal App Manual</a></li>
|
||||
<li class="{{selectedHome}}"><a href="{{baseUrl}}/" title="Home"><i class="fa fa-home"></i></a></li>
|
||||
<li class="{{selectedTerminal}}"><a href="{{baseUrl}}/terminal" title="Terminal"><i class="fa fa-terminal"></i></a></li>
|
||||
<li class="{{selectedDesktop}}"><a href="{{baseUrl}}/desktop" title="Desktop"><i class="fa fa-desktop"></i></a></li>
|
||||
</ul>
|
||||
<div class="nav-right">
|
||||
<iframe src="https://www.facebook.com/plugins/share_button.php?href=http%3A%2F%2Fjoplin.cozic.net&layout=button&size=small&mobile_iframe=true&width=60&height=20&appId" width="60" height="20" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>
|
||||
<a class="twitter-share-button" href="https://twitter.com/intent/tweet?url=http%3A%2F%2Fjoplin.cozic.net">Tweet</a>
|
||||
<iframe class="github-share-button" src="https://ghbtns.com/github-btn.html?user=laurent22&repo=joplin&type=star&count=true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
|
||||
<iframe class="share-btn" src="https://www.facebook.com/plugins/share_button.php?href=http%3A%2F%2Fjoplin.cozic.net&layout=button&size=small&mobile_iframe=true&width=60&height=20&appId" width="60" height="20" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>
|
||||
<iframe class="share-btn" src="https://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fjoplin.cozic.net" width="62" height="20" title="Tweet" style="border: 0; overflow: hidden;"></iframe>
|
||||
<iframe class="share-btn share-btn-github" src="https://ghbtns.com/github-btn.html?user=laurent22&repo=joplin&type=star&count=true" frameborder="0" scrolling="0" width="80px" height="20px"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -231,21 +248,6 @@ const footerHtml = `
|
||||
// `;
|
||||
|
||||
const scriptHtml = `
|
||||
<script>window.twttr = (function(d, s, id) {
|
||||
var js, fjs = d.getElementsByTagName(s)[0],
|
||||
t = window.twttr || {};
|
||||
if (d.getElementById(id)) return t;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = "https://platform.twitter.com/widgets.js";
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
t._e = [];
|
||||
t.ready = function(f) {
|
||||
t._e.push(f);
|
||||
};
|
||||
return t;
|
||||
}(document, "script", "twitter-wjs"));</script>
|
||||
|
||||
<script>
|
||||
function stickyHeader() {
|
||||
if ($(window).scrollTop() > 179) {
|
||||
@@ -268,6 +270,10 @@ const scriptHtml = `
|
||||
</script>
|
||||
`;
|
||||
|
||||
// <a href="#" class="small-share-btn" style="background-color: #365899;"><img src="images/ShareFacebook.svg" style=" width: 1.2em; height: 1.2em"/></a>
|
||||
// <a href="#" class="small-share-btn" style="background-color: #1b95e0;"><img src="images/ShareTwitter.svg" style=" width: 1.2em; height: 1.2em"/></a>
|
||||
// <a href="#" class="small-share-btn" style="background-color: #eee;"><img src="images/ShareGithub.svg" style=" width: 1.2em; height: 1.2em"/></a>
|
||||
|
||||
const rootDir = dirname(dirname(__dirname));
|
||||
|
||||
function markdownToHtml(md) {
|
||||
@@ -297,14 +303,16 @@ function renderFileToHtml(sourcePath, targetPath, params) {
|
||||
|
||||
async function main() {
|
||||
renderFileToHtml(rootDir + '/README.md', rootDir + '/docs/index.html', {
|
||||
baseUrl: '',
|
||||
selectedHome: 'selected',
|
||||
});
|
||||
|
||||
renderFileToHtml(rootDir + '/README_terminal.md', rootDir + '/docs/terminal/index.html', {
|
||||
baseUrl: '..',
|
||||
selectedTerminal: 'selected',
|
||||
});
|
||||
|
||||
renderFileToHtml(rootDir + '/README_desktop.md', rootDir + '/docs/desktop/index.html', {
|
||||
selectedDesktop: 'selected',
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
|
||||
36
CliClient/app/command-export-sync-status.js
Normal file
@@ -0,0 +1,36 @@
|
||||
const { BaseCommand } = require('./base-command.js');
|
||||
const { Database } = require('lib/database.js');
|
||||
const { app } = require('./app.js');
|
||||
const { Setting } = require('lib/models/setting.js');
|
||||
const { _ } = require('lib/locale.js');
|
||||
const { ReportService } = require('lib/services/report.js');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
class Command extends BaseCommand {
|
||||
|
||||
usage() {
|
||||
return 'export-sync-status';
|
||||
}
|
||||
|
||||
description() {
|
||||
return 'Export sync status';
|
||||
}
|
||||
|
||||
hidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
const service = new ReportService();
|
||||
const csv = await service.basicItemList({ format: 'csv' });
|
||||
const filePath = Setting.value('profileDir') + '/syncReport-' + (new Date()).getTime() + '.csv';
|
||||
await fs.writeFileSync(filePath, csv);
|
||||
this.stdout('Sync status exported to ' + filePath);
|
||||
|
||||
app().gui().showConsole();
|
||||
app().gui().maximizeConsole();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Command;
|
||||
@@ -16,7 +16,7 @@ class Command extends BaseCommand {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.syncTarget_ = null;
|
||||
this.syncTargetId_ = null;
|
||||
this.releaseLockFn_ = null;
|
||||
this.oneDriveApiUtils_ = null;
|
||||
}
|
||||
@@ -62,6 +62,27 @@ class Command extends BaseCommand {
|
||||
});
|
||||
}
|
||||
|
||||
async doAuth(syncTargetId) {
|
||||
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
||||
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
|
||||
const auth = await this.oneDriveApiUtils_.oauthDance({
|
||||
log: (...s) => { return this.stdout(...s); }
|
||||
});
|
||||
this.oneDriveApiUtils_ = null;
|
||||
return auth;
|
||||
}
|
||||
|
||||
cancelAuth() {
|
||||
if (this.oneDriveApiUtils_) {
|
||||
this.oneDriveApiUtils_.cancelOAuthDance();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
doingAuth() {
|
||||
return !!this.oneDriveApiUtils_;
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
this.releaseLockFn_ = null;
|
||||
|
||||
@@ -91,25 +112,24 @@ class Command extends BaseCommand {
|
||||
};
|
||||
|
||||
try {
|
||||
this.syncTarget_ = Setting.value('sync.target');
|
||||
if (args.options.target) this.syncTarget_ = args.options.target;
|
||||
this.syncTargetId_ = Setting.value('sync.target');
|
||||
if (args.options.target) this.syncTargetId_ = args.options.target;
|
||||
|
||||
if (this.syncTarget_ == Setting.SYNC_TARGET_ONEDRIVE && !reg.syncHasAuth(this.syncTarget_)) {
|
||||
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
||||
|
||||
if (!syncTarget.isAuthenticated()) {
|
||||
app().gui().showConsole();
|
||||
app().gui().maximizeConsole();
|
||||
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(reg.oneDriveApi());
|
||||
const auth = await this.oneDriveApiUtils_.oauthDance({
|
||||
log: (...s) => { return this.stdout(...s); }
|
||||
});
|
||||
this.oneDriveApiUtils_ = null;
|
||||
Setting.setValue('sync.3.auth', auth ? JSON.stringify(auth) : null);
|
||||
|
||||
const auth = await this.doAuth(this.syncTargetId_);
|
||||
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', auth ? JSON.stringify(auth) : null);
|
||||
if (!auth) {
|
||||
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
|
||||
return cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
let sync = await reg.synchronizer(this.syncTarget_);
|
||||
const sync = await syncTarget.synchronizer();
|
||||
|
||||
let options = {
|
||||
onProgress: (report) => {
|
||||
@@ -123,13 +143,13 @@ class Command extends BaseCommand {
|
||||
randomFailures: args.options['random-failures'] === true,
|
||||
};
|
||||
|
||||
this.stdout(_('Synchronisation target: %s (%s)', Setting.enumOptionLabel('sync.target', this.syncTarget_), this.syncTarget_));
|
||||
this.stdout(_('Synchronisation target: %s (%s)', Setting.enumOptionLabel('sync.target', this.syncTargetId_), this.syncTargetId_));
|
||||
|
||||
if (!sync) throw new Error(_('Cannot initialize synchroniser.'));
|
||||
|
||||
this.stdout(_('Starting synchronisation...'));
|
||||
|
||||
const contextKey = 'sync.' + this.syncTarget_ + '.context';
|
||||
const contextKey = 'sync.' + this.syncTargetId_ + '.context';
|
||||
let context = Setting.value(contextKey);
|
||||
|
||||
context = context ? JSON.parse(context) : {};
|
||||
@@ -156,26 +176,28 @@ class Command extends BaseCommand {
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
if (this.oneDriveApiUtils_) {
|
||||
this.oneDriveApiUtils_.cancelOAuthDance();
|
||||
if (this.doingAuth()) {
|
||||
this.cancelAuth();
|
||||
return;
|
||||
}
|
||||
|
||||
const target = this.syncTarget_ ? this.syncTarget_ : Setting.value('sync.target');
|
||||
const syncTargetId = this.syncTargetId_ ? this.syncTargetId_ : Setting.value('sync.target');
|
||||
|
||||
cliUtils.redrawDone();
|
||||
|
||||
this.stdout(_('Cancelling... Please wait.'));
|
||||
|
||||
if (reg.syncHasAuth(target)) {
|
||||
let sync = await reg.synchronizer(target);
|
||||
const syncTarget = reg.syncTarget(syncTargetId);
|
||||
|
||||
if (syncTarget.isAuthenticated()) {
|
||||
const sync = await syncTarget.synchronizer();
|
||||
if (sync) await sync.cancel();
|
||||
} else {
|
||||
if (this.releaseLockFn_) this.releaseLockFn_();
|
||||
this.releaseLockFn_ = null;
|
||||
}
|
||||
|
||||
this.syncTarget_ = null;
|
||||
this.syncTargetId_ = null;
|
||||
}
|
||||
|
||||
cancellable() {
|
||||
|
||||
@@ -562,24 +562,21 @@ msgstr ""
|
||||
msgid "Rename notebook:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Seach:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Seach"
|
||||
msgstr ""
|
||||
|
||||
msgid "Layout"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add or remove tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "Switch between note and to-do"
|
||||
msgid "Switch between note and to-do type"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete notes?"
|
||||
msgstr ""
|
||||
|
||||
msgid "No notes in here. Create one by clicking on \"New note\"."
|
||||
msgstr ""
|
||||
|
||||
@@ -614,6 +611,9 @@ msgstr ""
|
||||
msgid "Rename"
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronise"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notebooks"
|
||||
msgstr ""
|
||||
|
||||
@@ -623,9 +623,6 @@ msgstr ""
|
||||
msgid "Searches"
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronise"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Usage: %s"
|
||||
msgstr ""
|
||||
@@ -634,6 +631,15 @@ msgstr ""
|
||||
msgid "Unknown flag: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "File system"
|
||||
msgstr ""
|
||||
|
||||
msgid "OneDrive"
|
||||
msgstr ""
|
||||
|
||||
msgid "OneDrive Dev (For testing only)"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unknown log level: %s"
|
||||
msgstr ""
|
||||
@@ -647,11 +653,6 @@ msgid ""
|
||||
"synchronisation again may fix the problem."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Please set the \"sync.2.path\" config value to the desired synchronisation "
|
||||
"destination."
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Cannot access %s"
|
||||
msgstr ""
|
||||
@@ -720,10 +721,6 @@ msgstr ""
|
||||
msgid "Cannot move note to \"%s\" notebook"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Invalid option value: \"%s\". Possible values are: %s."
|
||||
msgstr ""
|
||||
|
||||
msgid "File system synchronisation target directory"
|
||||
msgstr ""
|
||||
|
||||
@@ -732,20 +729,6 @@ msgid ""
|
||||
"See `sync.target`."
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronisation target"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The target to synchonise to. If synchronising with the file system, set "
|
||||
"`sync.2.path` to specify the target directory."
|
||||
msgstr ""
|
||||
|
||||
msgid "File system"
|
||||
msgstr ""
|
||||
|
||||
msgid "OneDrive"
|
||||
msgstr ""
|
||||
|
||||
msgid "Text editor"
|
||||
msgstr ""
|
||||
|
||||
@@ -790,9 +773,24 @@ msgstr ""
|
||||
msgid "%d hours"
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show advanced options"
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronisation target"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The target to synchonise to. If synchronising with the file system, set "
|
||||
"`sync.2.path` to specify the target directory."
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Invalid option value: \"%s\". Possible values are: %s."
|
||||
msgstr ""
|
||||
|
||||
msgid "Sync status (synced items / total items)"
|
||||
msgstr ""
|
||||
|
||||
@@ -822,12 +820,25 @@ msgstr ""
|
||||
msgid "There are currently no notes. Create one by clicking on the (+) button."
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete these notes?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log"
|
||||
msgstr ""
|
||||
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Export Debug Report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Move to notebook..."
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Move %d notes to notebook \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cancel synchronisation"
|
||||
msgstr ""
|
||||
|
||||
@@ -847,6 +858,16 @@ msgstr ""
|
||||
msgid "Discard changes"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unsupported image type: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Attach image"
|
||||
msgstr ""
|
||||
|
||||
msgid "Attach any other file"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete note"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ msgid "Exit command line mode"
|
||||
msgstr "Sortir du mode de ligne de commande"
|
||||
|
||||
msgid "Edit the selected note"
|
||||
msgstr "Editer la note sélectionnée"
|
||||
msgstr "Éditer la note sélectionnée"
|
||||
|
||||
msgid "Cancel the current command."
|
||||
msgstr "Annuler la commande en cours."
|
||||
@@ -157,7 +157,7 @@ msgid ""
|
||||
"Duplicates the notes matching <note> to [notebook]. If no notebook is "
|
||||
"specified the note is duplicated in the current notebook."
|
||||
msgstr ""
|
||||
"Copie les notes correspondant à <nom> vers [carnet]. Si aucun carnet n'est "
|
||||
"Copier les notes correspondant à <nom> vers [carnet]. Si aucun carnet n'est "
|
||||
"spécifié, la note est dupliquée sur place."
|
||||
|
||||
msgid "Marks a to-do as done."
|
||||
@@ -168,7 +168,7 @@ msgid "Note is not a to-do: \"%s\""
|
||||
msgstr "La note n'est pas une tâche : \"%s\""
|
||||
|
||||
msgid "Edit note."
|
||||
msgstr "Editer la note."
|
||||
msgstr "Éditer la note."
|
||||
|
||||
msgid ""
|
||||
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
||||
@@ -185,7 +185,7 @@ msgstr "Cette note n'existe pas : \"%s\". La créer ?"
|
||||
|
||||
msgid "Starting to edit note. Close the editor to get back to the prompt."
|
||||
msgstr ""
|
||||
"Edition de la note en cours. Fermez l'éditeur de texte pour retourner à "
|
||||
"Édition de la note en cours. Fermez l'éditeur de texte pour retourner à "
|
||||
"l'invite de commande."
|
||||
|
||||
msgid "Note has been saved."
|
||||
@@ -228,8 +228,8 @@ msgid ""
|
||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
||||
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||
msgstr ""
|
||||
"Dans n'importe quelle commande, une note ou carnet peut être référé par "
|
||||
"titre ou identifiant, ou en utilisant les raccourcis `$n` et `$b` pour, "
|
||||
"Dans une commande, une note ou carnet peut être référé par titre ou "
|
||||
"identifiant, ou en utilisant les raccourcis `$n` et `$b` pour, "
|
||||
"respectivement, la note sélectionnée et le carnet sélectionné. `$c` peut "
|
||||
"être utilisé pour faire référence à l'objet sélectionné en cours."
|
||||
|
||||
@@ -286,7 +286,7 @@ msgstr "Créés : %d."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Updated: %d."
|
||||
msgstr "Mise à jour : %d."
|
||||
msgstr "Mis à jour : %d."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Skipped: %d."
|
||||
@@ -298,7 +298,7 @@ msgstr "Ressources : %d."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Tagged: %d."
|
||||
msgstr "Etiquettes : %d."
|
||||
msgstr "Étiquettes : %d."
|
||||
|
||||
msgid "Importing notes..."
|
||||
msgstr "Importation des notes..."
|
||||
@@ -510,9 +510,9 @@ msgid ""
|
||||
"any files outside this directory nor to any other personal data. No data "
|
||||
"will be shared with any third party."
|
||||
msgstr ""
|
||||
"Veuillez ouvrir le lien ci-dessous dans votre browser pour authentifier le "
|
||||
"logiciel. Joplin va créer un répertoire \"Apps/Joplin\" et lire/écrira des "
|
||||
"fichiers uniquement dans ce répertoire. Le logiciel n'aura pas d'accès à "
|
||||
"Veuillez ouvrir le lien ci-dessous dans votre navigateur pour authentifier "
|
||||
"le logiciel. Joplin va créer un répertoire \"Apps/Joplin\" et lire/écrira "
|
||||
"des fichiers uniquement dans ce répertoire. Le logiciel n'aura pas d'accès à "
|
||||
"aucun fichier en dehors de ce répertoire, ni à d'autres données "
|
||||
"personnelles. Aucune donnée ne sera partagé avec aucun tier."
|
||||
|
||||
@@ -532,7 +532,7 @@ msgid "New notebook"
|
||||
msgstr "Nouveau carnet"
|
||||
|
||||
msgid "Import Evernote notes"
|
||||
msgstr "Importer notes d'Evernotes"
|
||||
msgstr "Importer notes d'Evernote"
|
||||
|
||||
msgid "Evernote Export Files"
|
||||
msgstr "Fichiers d'export Evernote"
|
||||
@@ -541,7 +541,7 @@ msgid "Quit"
|
||||
msgstr "Quitter"
|
||||
|
||||
msgid "Edit"
|
||||
msgstr "Edition"
|
||||
msgstr "Édition"
|
||||
|
||||
msgid "Copy"
|
||||
msgstr "Copier"
|
||||
@@ -568,7 +568,7 @@ msgid "Website and documentation"
|
||||
msgstr "Documentation en ligne"
|
||||
|
||||
msgid "About Joplin"
|
||||
msgstr "A props de Joplin"
|
||||
msgstr "A propos de Joplin"
|
||||
|
||||
#, javascript-format
|
||||
msgid "%s %s (%s, %s)"
|
||||
@@ -614,24 +614,21 @@ msgstr "Séparez chaque étiquette par une virgule."
|
||||
msgid "Rename notebook:"
|
||||
msgstr "Renommer le carnet :"
|
||||
|
||||
msgid "Seach:"
|
||||
msgstr "Chercher :"
|
||||
|
||||
msgid "Seach"
|
||||
msgstr "Chercher"
|
||||
|
||||
msgid "Layout"
|
||||
msgstr "Disposition"
|
||||
|
||||
msgid "Add or remove tags"
|
||||
msgstr "Gérer les étiquettes"
|
||||
|
||||
msgid "Switch between note and to-do"
|
||||
msgid "Switch between note and to-do type"
|
||||
msgstr "Alterner entre note et tâche"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
msgid "Delete notes?"
|
||||
msgstr "Supprimer les notes ?"
|
||||
|
||||
msgid "No notes in here. Create one by clicking on \"New note\"."
|
||||
msgstr ""
|
||||
"Pas de notes ici. Créez-en une en pressant le bouton \"Nouvelle note\"."
|
||||
@@ -647,7 +644,7 @@ msgid "Refresh"
|
||||
msgstr "Rafraîchir"
|
||||
|
||||
msgid "OneDrive Login"
|
||||
msgstr "Connection OneDrive"
|
||||
msgstr "Connexion OneDrive"
|
||||
|
||||
msgid "Import"
|
||||
msgstr "Importer"
|
||||
@@ -667,18 +664,18 @@ msgstr "Enlever cette recherche de la barre latérale ?"
|
||||
msgid "Rename"
|
||||
msgstr "Renommer"
|
||||
|
||||
msgid "Synchronise"
|
||||
msgstr "Synchroniser"
|
||||
|
||||
msgid "Notebooks"
|
||||
msgstr "Carnets"
|
||||
|
||||
msgid "Tags"
|
||||
msgstr "Etiquettes"
|
||||
msgstr "Étiquettes"
|
||||
|
||||
msgid "Searches"
|
||||
msgstr "Recherches"
|
||||
|
||||
msgid "Synchronise"
|
||||
msgstr "Synchroniser"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Usage: %s"
|
||||
msgstr "Utilisation : %s"
|
||||
@@ -687,6 +684,15 @@ msgstr "Utilisation : %s"
|
||||
msgid "Unknown flag: %s"
|
||||
msgstr "Paramètre inconnu : %s"
|
||||
|
||||
msgid "File system"
|
||||
msgstr "Système de fichier"
|
||||
|
||||
msgid "OneDrive"
|
||||
msgstr "OneDrive"
|
||||
|
||||
msgid "OneDrive Dev (For testing only)"
|
||||
msgstr "OneDrive Dév (Pour tester uniquement)"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unknown log level: %s"
|
||||
msgstr "Paramètre inconnu : %s"
|
||||
@@ -699,16 +705,9 @@ msgid ""
|
||||
"Cannot refresh token: authentication data is missing. Starting the "
|
||||
"synchronisation again may fix the problem."
|
||||
msgstr ""
|
||||
"Impossible de rafraîchir la connection à OneDrive. Démarrez la "
|
||||
"Impossible de rafraîchir la connexion à OneDrive. Démarrez la "
|
||||
"synchronisation à nouveau pour corriger le problème."
|
||||
|
||||
msgid ""
|
||||
"Please set the \"sync.2.path\" config value to the desired synchronisation "
|
||||
"destination."
|
||||
msgstr ""
|
||||
"Veuillez attribuer une valeur au paramètre de configuration \"sync.2.path\" "
|
||||
"pour indiquer le dossier où devra se faire la synchronisation."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Cannot access %s"
|
||||
msgstr "Impossible d'accéder à %s"
|
||||
@@ -739,7 +738,7 @@ msgstr "Objets distants supprimés : %d."
|
||||
|
||||
#, javascript-format
|
||||
msgid "State: \"%s\"."
|
||||
msgstr "Etat : \"%s\"."
|
||||
msgstr "État : \"%s\"."
|
||||
|
||||
msgid "Cancelling..."
|
||||
msgstr "Annulation..."
|
||||
@@ -750,7 +749,7 @@ msgstr "Terminé : %s"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Synchronisation is already in progress. State: %s"
|
||||
msgstr "La synchronisation est déjà en cours. Etat : %s"
|
||||
msgstr "La synchronisation est déjà en cours. État : %s"
|
||||
|
||||
msgid "Conflicts"
|
||||
msgstr "Conflits"
|
||||
@@ -777,10 +776,6 @@ msgstr "Impossible de copier la note vers le carnet \"%s\""
|
||||
msgid "Cannot move note to \"%s\" notebook"
|
||||
msgstr "Impossible de déplacer la note vers le carnet \"%s\""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Invalid option value: \"%s\". Possible values are: %s."
|
||||
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
|
||||
|
||||
msgid "File system synchronisation target directory"
|
||||
msgstr "Cible de la synchronisation sur le disque dur"
|
||||
|
||||
@@ -791,24 +786,8 @@ msgstr ""
|
||||
"Le chemin du répertoire avec lequel synchroniser lorsque la synchronisation "
|
||||
"par système de fichier est activée. Voir `sync.target`."
|
||||
|
||||
msgid "Synchronisation target"
|
||||
msgstr "Cible de la synchronisation"
|
||||
|
||||
msgid ""
|
||||
"The target to synchonise to. If synchronising with the file system, set "
|
||||
"`sync.2.path` to specify the target directory."
|
||||
msgstr ""
|
||||
"La cible avec laquelle synchroniser. Pour synchroniser avec le système de "
|
||||
"fichier, veuillez spécifier le répertoire avec `sync.2.path`."
|
||||
|
||||
msgid "File system"
|
||||
msgstr "Système de fichier"
|
||||
|
||||
msgid "OneDrive"
|
||||
msgstr "OneDrive"
|
||||
|
||||
msgid "Text editor"
|
||||
msgstr "Editeur de texte"
|
||||
msgstr "Éditeur de texte"
|
||||
|
||||
msgid ""
|
||||
"The editor that will be used to open a note. If none is provided it will try "
|
||||
@@ -836,7 +815,7 @@ msgid "Save geo-location with notes"
|
||||
msgstr "Enregistrer l'emplacement avec les notes"
|
||||
|
||||
msgid "Synchronisation interval"
|
||||
msgstr "Interval de synchronisation"
|
||||
msgstr "Intervalle de synchronisation"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "Désactivé"
|
||||
@@ -853,9 +832,26 @@ msgstr "%d heure"
|
||||
msgid "%d hours"
|
||||
msgstr "%d heures"
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr "Mettre à jour le logiciel automatiquement"
|
||||
|
||||
msgid "Show advanced options"
|
||||
msgstr "Montrer les options avancées"
|
||||
|
||||
msgid "Synchronisation target"
|
||||
msgstr "Cible de la synchronisation"
|
||||
|
||||
msgid ""
|
||||
"The target to synchonise to. If synchronising with the file system, set "
|
||||
"`sync.2.path` to specify the target directory."
|
||||
msgstr ""
|
||||
"La cible avec laquelle synchroniser. Pour synchroniser avec le système de "
|
||||
"fichier, veuillez spécifier le répertoire avec `sync.2.path`."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Invalid option value: \"%s\". Possible values are: %s."
|
||||
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
|
||||
|
||||
msgid "Sync status (synced items / total items)"
|
||||
msgstr "Status de la synchronisation (objets synchro. / total)"
|
||||
|
||||
@@ -887,11 +883,24 @@ msgstr ""
|
||||
"Ce carnet ne contient aucune note. Créez-en une en appuyant sur le bouton "
|
||||
"(+)."
|
||||
|
||||
msgid "Delete these notes?"
|
||||
msgstr "Supprimer ces notes ?"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "Journal"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "Etat"
|
||||
msgstr "État"
|
||||
|
||||
msgid "Export Debug Report"
|
||||
msgstr "Exporter rapport de débogage"
|
||||
|
||||
msgid "Move to notebook..."
|
||||
msgstr "Déplacer la note vers carnet..."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Move %d notes to notebook \"%s\"?"
|
||||
msgstr "Déplacer %d notes vers carnet \"%s\" ?"
|
||||
|
||||
msgid "Cancel synchronisation"
|
||||
msgstr "Annuler synchronisation"
|
||||
@@ -901,7 +910,7 @@ msgid "The notebook could not be saved: %s"
|
||||
msgstr "Ce carnet n'a pas pu être sauvegardé : %s"
|
||||
|
||||
msgid "Edit notebook"
|
||||
msgstr "Editer le carnet"
|
||||
msgstr "Éditer le carnet"
|
||||
|
||||
msgid "This note has been modified:"
|
||||
msgstr "Cette note a été modifiée :"
|
||||
@@ -912,6 +921,16 @@ msgstr "Enregistrer les changements"
|
||||
msgid "Discard changes"
|
||||
msgstr "Ignorer les changements"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unsupported image type: %s"
|
||||
msgstr "Type d'image non géré : %s"
|
||||
|
||||
msgid "Attach image"
|
||||
msgstr "Joindre une image ou photo"
|
||||
|
||||
msgid "Attach any other file"
|
||||
msgstr "Joindre un fichier"
|
||||
|
||||
msgid "Delete note"
|
||||
msgstr "Supprimer la note"
|
||||
|
||||
@@ -934,7 +953,7 @@ msgid "Delete notebook"
|
||||
msgstr "Supprimer le carnet"
|
||||
|
||||
msgid "Login with OneDrive"
|
||||
msgstr "Se connecter avec OneDrive"
|
||||
msgstr "Se connecter à OneDrive"
|
||||
|
||||
msgid ""
|
||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||
@@ -951,6 +970,19 @@ msgstr ""
|
||||
msgid "Welcome"
|
||||
msgstr "Bienvenue"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Please set the \"sync.2.path\" config value to the desired "
|
||||
#~ "synchronisation destination."
|
||||
#~ msgstr ""
|
||||
#~ "Veuillez attribuer une valeur au paramètre de configuration \"sync.2.path"
|
||||
#~ "\" pour indiquer le dossier où devra se faire la synchronisation."
|
||||
|
||||
#~ msgid "Seach:"
|
||||
#~ msgstr "Chercher :"
|
||||
|
||||
#~ msgid "Seach"
|
||||
#~ msgstr "Chercher"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Command line argument \"%s\" contains both quotes and double-quotes - "
|
||||
#~ "aborting."
|
||||
|
||||
@@ -562,24 +562,21 @@ msgstr ""
|
||||
msgid "Rename notebook:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Seach:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Seach"
|
||||
msgstr ""
|
||||
|
||||
msgid "Layout"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add or remove tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "Switch between note and to-do"
|
||||
msgid "Switch between note and to-do type"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete notes?"
|
||||
msgstr ""
|
||||
|
||||
msgid "No notes in here. Create one by clicking on \"New note\"."
|
||||
msgstr ""
|
||||
|
||||
@@ -614,6 +611,9 @@ msgstr ""
|
||||
msgid "Rename"
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronise"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notebooks"
|
||||
msgstr ""
|
||||
|
||||
@@ -623,9 +623,6 @@ msgstr ""
|
||||
msgid "Searches"
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronise"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Usage: %s"
|
||||
msgstr ""
|
||||
@@ -634,6 +631,15 @@ msgstr ""
|
||||
msgid "Unknown flag: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "File system"
|
||||
msgstr ""
|
||||
|
||||
msgid "OneDrive"
|
||||
msgstr ""
|
||||
|
||||
msgid "OneDrive Dev (For testing only)"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unknown log level: %s"
|
||||
msgstr ""
|
||||
@@ -647,11 +653,6 @@ msgid ""
|
||||
"synchronisation again may fix the problem."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Please set the \"sync.2.path\" config value to the desired synchronisation "
|
||||
"destination."
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Cannot access %s"
|
||||
msgstr ""
|
||||
@@ -720,10 +721,6 @@ msgstr ""
|
||||
msgid "Cannot move note to \"%s\" notebook"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Invalid option value: \"%s\". Possible values are: %s."
|
||||
msgstr ""
|
||||
|
||||
msgid "File system synchronisation target directory"
|
||||
msgstr ""
|
||||
|
||||
@@ -732,20 +729,6 @@ msgid ""
|
||||
"See `sync.target`."
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronisation target"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The target to synchonise to. If synchronising with the file system, set "
|
||||
"`sync.2.path` to specify the target directory."
|
||||
msgstr ""
|
||||
|
||||
msgid "File system"
|
||||
msgstr ""
|
||||
|
||||
msgid "OneDrive"
|
||||
msgstr ""
|
||||
|
||||
msgid "Text editor"
|
||||
msgstr ""
|
||||
|
||||
@@ -790,9 +773,24 @@ msgstr ""
|
||||
msgid "%d hours"
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show advanced options"
|
||||
msgstr ""
|
||||
|
||||
msgid "Synchronisation target"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The target to synchonise to. If synchronising with the file system, set "
|
||||
"`sync.2.path` to specify the target directory."
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Invalid option value: \"%s\". Possible values are: %s."
|
||||
msgstr ""
|
||||
|
||||
msgid "Sync status (synced items / total items)"
|
||||
msgstr ""
|
||||
|
||||
@@ -822,12 +820,25 @@ msgstr ""
|
||||
msgid "There are currently no notes. Create one by clicking on the (+) button."
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete these notes?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log"
|
||||
msgstr ""
|
||||
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Export Debug Report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Move to notebook..."
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Move %d notes to notebook \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cancel synchronisation"
|
||||
msgstr ""
|
||||
|
||||
@@ -847,6 +858,16 @@ msgstr ""
|
||||
msgid "Discard changes"
|
||||
msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unsupported image type: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Attach image"
|
||||
msgstr ""
|
||||
|
||||
msgid "Attach any other file"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete note"
|
||||
msgstr ""
|
||||
|
||||
|
||||
10
CliClient/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "joplin",
|
||||
"version": "0.10.70",
|
||||
"version": "0.10.74",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -917,6 +917,14 @@
|
||||
"resolved": "https://registry.npmjs.org/node-bitmap/-/node-bitmap-0.0.1.tgz",
|
||||
"integrity": "sha1-GA6scAPgxwdhjvMTaPYvhLKmkJE="
|
||||
},
|
||||
"node-emoji": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz",
|
||||
"integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==",
|
||||
"requires": {
|
||||
"lodash.toarray": "4.4.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "0.10.70",
|
||||
"version": "0.10.74",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
@@ -37,6 +37,7 @@
|
||||
"md5": "^2.2.1",
|
||||
"mime": "^2.0.3",
|
||||
"moment": "^2.18.1",
|
||||
"node-emoji": "^1.8.1",
|
||||
"node-fetch": "^1.7.1",
|
||||
"node-persist": "^2.1.0",
|
||||
"os-tmpdir": "^1.0.2",
|
||||
|
||||
@@ -9,6 +9,7 @@ const { Database } = require('lib/database.js');
|
||||
const { Setting } = require('lib/models/setting.js');
|
||||
const { BaseItem } = require('lib/models/base-item.js');
|
||||
const { BaseModel } = require('lib/base-model.js');
|
||||
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
@@ -37,7 +38,7 @@ async function localItemsSameAsRemote(locals, expect) {
|
||||
expect(!!remote).toBe(true);
|
||||
if (!remote) continue;
|
||||
|
||||
if (syncTargetId() == Setting.SYNC_TARGET_FILESYSTEM) {
|
||||
if (syncTargetId() == SyncTargetRegistry.nameToId('filesystem')) {
|
||||
expect(remote.updated_time).toBe(Math.floor(dbItem.updated_time / 1000) * 1000);
|
||||
} else {
|
||||
expect(remote.updated_time).toBe(dbItem.updated_time);
|
||||
@@ -606,5 +607,25 @@ describe('Synchronizer', function() {
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('items should be downloaded again when user cancels in the middle of delta operation', async (done) => {
|
||||
let folder1 = await Folder.save({ title: "folder1" });
|
||||
let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id });
|
||||
await synchronizer().start();
|
||||
|
||||
await switchClient(2);
|
||||
|
||||
synchronizer().debugFlags_ = ['cancelDeltaLoop2'];
|
||||
let context = await synchronizer().start();
|
||||
let notes = await Note.all();
|
||||
expect(notes.length).toBe(0);
|
||||
|
||||
synchronizer().debugFlags_ = [];
|
||||
await synchronizer().start({ context: context });
|
||||
notes = await Note.all();
|
||||
expect(notes.length).toBe(1);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -16,6 +16,9 @@ const { FileApiDriverMemory } = require('lib/file-api-driver-memory.js');
|
||||
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
||||
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
|
||||
const SyncTargetMemory = require('lib/SyncTargetMemory.js');
|
||||
const SyncTargetFilesystem = require('lib/SyncTargetFilesystem.js');
|
||||
|
||||
let databases_ = [];
|
||||
let synchronizers_ = [];
|
||||
@@ -29,12 +32,13 @@ Resource.fsDriver_ = fsDriver;
|
||||
const logDir = __dirname + '/../tests/logs';
|
||||
fs.mkdirpSync(logDir, 0o755);
|
||||
|
||||
const syncTargetId_ = Setting.SYNC_TARGET_MEMORY;
|
||||
//const syncTargetId_ = Setting.SYNC_TARGET_FILESYSTEM;
|
||||
//const syncTargetId_ = Setting.SYNC_TARGET_ONEDRIVE;
|
||||
SyncTargetRegistry.addClass(SyncTargetMemory);
|
||||
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
||||
|
||||
const syncTargetId_ = SyncTargetRegistry.nameToId('memory');
|
||||
const syncDir = __dirname + '/../tests/sync';
|
||||
|
||||
const sleepTime = syncTargetId_ == Setting.SYNC_TARGET_FILESYSTEM ? 1001 : 400;
|
||||
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 400;
|
||||
|
||||
const logger = new Logger();
|
||||
logger.addTarget('file', { path: logDir + '/log.txt' });
|
||||
@@ -121,11 +125,14 @@ async function setupDatabaseAndSynchronizer(id = null) {
|
||||
await setupDatabase(id);
|
||||
|
||||
if (!synchronizers_[id]) {
|
||||
synchronizers_[id] = new Synchronizer(db(id), fileApi(), Setting.value('appType'));
|
||||
synchronizers_[id].setLogger(logger);
|
||||
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId_);
|
||||
const syncTarget = new SyncTargetClass(db(id));
|
||||
syncTarget.setFileApi(fileApi());
|
||||
syncTarget.setLogger(logger);
|
||||
synchronizers_[id] = await syncTarget.synchronizer();
|
||||
}
|
||||
|
||||
if (syncTargetId_ == Setting.SYNC_TARGET_FILESYSTEM) {
|
||||
if (syncTargetId_ == SyncTargetRegistry.nameToId('filesystem')) {
|
||||
fs.removeSync(syncDir)
|
||||
fs.mkdirpSync(syncDir, 0o755);
|
||||
} else {
|
||||
@@ -146,13 +153,12 @@ function synchronizer(id = null) {
|
||||
function fileApi() {
|
||||
if (fileApi_) return fileApi_;
|
||||
|
||||
if (syncTargetId_ == Setting.SYNC_TARGET_FILESYSTEM) {
|
||||
if (syncTargetId_ == SyncTargetRegistry.nameToId('filesystem')) {
|
||||
fs.removeSync(syncDir)
|
||||
fs.mkdirpSync(syncDir, 0o755);
|
||||
fileApi_ = new FileApi(syncDir, new FileApiDriverLocal());
|
||||
} else if (syncTargetId_ == Setting.SYNC_TARGET_MEMORY) {
|
||||
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('memory')) {
|
||||
fileApi_ = new FileApi('/root', new FileApiDriverMemory());
|
||||
fileApi_.setLogger(logger);
|
||||
}
|
||||
// } else if (syncTargetId == Setting.SYNC_TARGET_ONEDRIVE) {
|
||||
// let auth = require('./onedrive-auth.json');
|
||||
|
||||
@@ -8,7 +8,6 @@ const { BaseModel } = require('lib/base-model.js');
|
||||
const { _, setLocale } = require('lib/locale.js');
|
||||
const os = require('os');
|
||||
const fs = require('fs-extra');
|
||||
const { Logger } = require('lib/logger.js');
|
||||
const { Tag } = require('lib/models/tag.js');
|
||||
const { reg } = require('lib/registry.js');
|
||||
const { sprintf } = require('sprintf-js');
|
||||
@@ -133,7 +132,7 @@ class Application extends BaseApplication {
|
||||
}
|
||||
|
||||
if (['NOTE_UPDATE_ONE', 'NOTE_DELETE', 'FOLDER_UPDATE_ONE', 'FOLDER_DELETE'].indexOf(action.type) >= 0) {
|
||||
if (!await reg.syncStarted()) reg.scheduleSync();
|
||||
if (!await reg.syncTarget().syncStarted()) reg.scheduleSync();
|
||||
}
|
||||
|
||||
const result = await super.generalMiddleware(store, next, action);
|
||||
@@ -337,13 +336,17 @@ class Application extends BaseApplication {
|
||||
// but then doesn't install it on exit.
|
||||
if (shim.isWindows() || shim.isMac()) {
|
||||
const runAutoUpdateCheck = function() {
|
||||
bridge().checkForUpdatesAndNotify(Setting.value('profileDir') + '/log-autoupdater.txt');
|
||||
if (Setting.value('autoUpdateEnabled')) {
|
||||
bridge().checkForUpdatesAndNotify(Setting.value('profileDir') + '/log-autoupdater.txt');
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => { runAutoUpdateCheck() }, 5000);
|
||||
// For those who leave the app always open
|
||||
setInterval(() => { runAutoUpdateCheck() }, 2 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
reg.scheduleSync();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ class Bridge {
|
||||
|
||||
constructor(electronWrapper) {
|
||||
this.electronWrapper_ = electronWrapper;
|
||||
this.autoUpdateLogger_ = null;
|
||||
}
|
||||
|
||||
electronApp() {
|
||||
@@ -78,17 +79,21 @@ class Bridge {
|
||||
return require('electron').shell.openItem(fullPath)
|
||||
}
|
||||
|
||||
checkForUpdatesAndNotify(logFilePath) {
|
||||
async checkForUpdatesAndNotify(logFilePath) {
|
||||
if (!this.autoUpdater_) {
|
||||
const logger = new Logger();
|
||||
logger.addTarget('file', { path: logFilePath });
|
||||
logger.setLevel(Logger.LEVEL_DEBUG);
|
||||
logger.info('checkForUpdatesAndNotify: Intializing...');
|
||||
this.autoUpdateLogger_ = new Logger();
|
||||
this.autoUpdateLogger_.addTarget('file', { path: logFilePath });
|
||||
this.autoUpdateLogger_.setLevel(Logger.LEVEL_DEBUG);
|
||||
this.autoUpdateLogger_.info('checkForUpdatesAndNotify: Intializing...');
|
||||
this.autoUpdater_ = require("electron-updater").autoUpdater;
|
||||
this.autoUpdater_.logger = logger;
|
||||
this.autoUpdater_.logger = this.autoUpdateLogger_;
|
||||
}
|
||||
|
||||
return this.autoUpdater_.checkForUpdatesAndNotify();
|
||||
try {
|
||||
await this.autoUpdater_.checkForUpdatesAndNotify();
|
||||
} catch (error) {
|
||||
this.autoUpdateLogger_.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@ class MainScreenComponent extends React.Component {
|
||||
return (
|
||||
<div style={style}>
|
||||
<PromptDialog
|
||||
autocomplete={promptOptions && ('autocomplete' in promptOptions) ? promptOptions.autocomplete : null}
|
||||
value={promptOptions && promptOptions.value ? promptOptions.value : ''}
|
||||
theme={this.props.theme}
|
||||
style={promptStyle}
|
||||
|
||||
@@ -52,28 +52,30 @@ class NoteListComponent extends React.Component {
|
||||
}
|
||||
|
||||
itemContextMenu(event) {
|
||||
const noteId = event.target.getAttribute('data-id');
|
||||
if (!noteId) throw new Error('No data-id on element');
|
||||
const noteIds = this.props.selectedNoteIds;
|
||||
if (!noteIds.length) return;
|
||||
|
||||
const menu = new Menu()
|
||||
|
||||
menu.append(new MenuItem({label: _('Add or remove tags'), click: async () => {
|
||||
menu.append(new MenuItem({label: _('Add or remove tags'), enabled: noteIds.length === 1, click: async () => {
|
||||
this.props.dispatch({
|
||||
type: 'WINDOW_COMMAND',
|
||||
name: 'setTags',
|
||||
noteId: noteId,
|
||||
noteId: noteIds[0],
|
||||
});
|
||||
}}));
|
||||
|
||||
menu.append(new MenuItem({label: _('Switch between note and to-do'), click: async () => {
|
||||
const note = await Note.load(noteId);
|
||||
await Note.save(Note.toggleIsTodo(note));
|
||||
menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => {
|
||||
for (let i = 0; i < noteIds.length; i++) {
|
||||
const note = await Note.load(noteIds[i]);
|
||||
await Note.save(Note.toggleIsTodo(note));
|
||||
}
|
||||
}}));
|
||||
|
||||
menu.append(new MenuItem({label: _('Delete'), click: async () => {
|
||||
const ok = bridge().showConfirmMessageBox(_('Delete note?'));
|
||||
const ok = bridge().showConfirmMessageBox(noteIds.length > 1 ? _('Delete notes?') : _('Delete note?'));
|
||||
if (!ok) return;
|
||||
await Note.delete(noteId);
|
||||
await Note.batchDelete(noteIds);
|
||||
}}));
|
||||
|
||||
menu.popup(bridge().window());
|
||||
@@ -81,10 +83,33 @@ class NoteListComponent extends React.Component {
|
||||
|
||||
itemRenderer(item, theme, width) {
|
||||
const onTitleClick = async (event, item) => {
|
||||
this.props.dispatch({
|
||||
type: 'NOTE_SELECT',
|
||||
id: item.id,
|
||||
});
|
||||
if (event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
this.props.dispatch({
|
||||
type: 'NOTE_SELECT_TOGGLE',
|
||||
id: item.id,
|
||||
});
|
||||
} else if (event.shiftKey) {
|
||||
event.preventDefault();
|
||||
this.props.dispatch({
|
||||
type: 'NOTE_SELECT_EXTEND',
|
||||
id: item.id,
|
||||
});
|
||||
} else {
|
||||
this.props.dispatch({
|
||||
type: 'NOTE_SELECT',
|
||||
id: item.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const onDragStart = (event) => {
|
||||
const noteIds = this.props.selectedNoteIds;
|
||||
if (!noteIds.length) return;
|
||||
|
||||
event.dataTransfer.setDragImage(new Image(), 1, 1);
|
||||
event.dataTransfer.clearData();
|
||||
event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds));
|
||||
}
|
||||
|
||||
const onCheckboxClick = async (event) => {
|
||||
@@ -99,7 +124,7 @@ class NoteListComponent extends React.Component {
|
||||
const hPadding = 10;
|
||||
|
||||
let style = Object.assign({ width: width }, this.style().listItem);
|
||||
if (this.props.selectedNoteId === item.id) style = Object.assign(style, this.style().listItemSelected);
|
||||
if (this.props.selectedNoteIds.indexOf(item.id) >= 0) style = Object.assign(style, this.style().listItemSelected);
|
||||
|
||||
// Setting marginBottom = 1 because it makes the checkbox looks more centered, at least on Windows
|
||||
// but don't know how it will look in other OSes.
|
||||
@@ -118,12 +143,13 @@ class NoteListComponent extends React.Component {
|
||||
return <div key={item.id + '_' + item.todo_completed} style={style}>
|
||||
{checkbox}
|
||||
<a
|
||||
data-id={item.id}
|
||||
className="list-item"
|
||||
onContextMenu={(event) => this.itemContextMenu(event)}
|
||||
href="#"
|
||||
draggable={true}
|
||||
style={listItemTitleStyle}
|
||||
onClick={(event) => { onTitleClick(event, item) }}
|
||||
onDragStart={(event) => onDragStart(event) }
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
@@ -164,7 +190,7 @@ class NoteListComponent extends React.Component {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
notes: state.notes,
|
||||
selectedNoteId: state.selectedNoteId,
|
||||
selectedNoteIds: state.selectedNoteIds,
|
||||
theme: state.settings.theme,
|
||||
// uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
|
||||
};
|
||||
|
||||
@@ -59,7 +59,10 @@ class NoteTextComponent extends React.Component {
|
||||
|
||||
mdToHtml() {
|
||||
if (this.mdToHtml_) return this.mdToHtml_;
|
||||
this.mdToHtml_ = new MdToHtml({ supportsResourceLinks: true });
|
||||
this.mdToHtml_ = new MdToHtml({
|
||||
supportsResourceLinks: true,
|
||||
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
|
||||
});
|
||||
return this.mdToHtml_;
|
||||
}
|
||||
|
||||
@@ -501,7 +504,7 @@ class NoteTextComponent extends React.Component {
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
noteId: state.selectedNoteId,
|
||||
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
|
||||
folderId: state.selectedFolderId,
|
||||
itemType: state.selectedItemType,
|
||||
folders: state.folders,
|
||||
|
||||
@@ -47,7 +47,7 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
this.authCode_ = code[1];
|
||||
|
||||
try {
|
||||
await reg.oneDriveApi().execTokenRequest(this.authCode_, this.redirectUrl(), true);
|
||||
await reg.syncTarget().api().execTokenRequest(this.authCode_, this.redirectUrl(), true);
|
||||
this.props.dispatch({ type: 'NAV_BACK' });
|
||||
reg.scheduleSync(0);
|
||||
} catch (error) {
|
||||
@@ -62,11 +62,11 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
}
|
||||
|
||||
startUrl() {
|
||||
return reg.oneDriveApi().authCodeUrl(this.redirectUrl());
|
||||
return reg.syncTarget().api().authCodeUrl(this.redirectUrl());
|
||||
}
|
||||
|
||||
redirectUrl() {
|
||||
return reg.oneDriveApi().nativeClientRedirectUrl();
|
||||
return reg.syncTarget().api().nativeClientRedirectUrl();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -4,6 +4,7 @@ const shared = require('lib/components/shared/side-menu-shared.js');
|
||||
const { Synchronizer } = require('lib/synchronizer.js');
|
||||
const { BaseModel } = require('lib/base-model.js');
|
||||
const { Folder } = require('lib/models/folder.js');
|
||||
const { Note } = require('lib/models/note.js');
|
||||
const { Tag } = require('lib/models/tag.js');
|
||||
const { _ } = require('lib/locale.js');
|
||||
const { themeStyle } = require('../theme.js');
|
||||
@@ -164,7 +165,32 @@ class SideBarComponent extends React.Component {
|
||||
let style = Object.assign({}, this.style().listItem);
|
||||
if (selected) style = Object.assign(style, this.style().listItemSelected);
|
||||
if (folder.id === Folder.conflictFolderId()) style = Object.assign(style, this.style().conflictFolder);
|
||||
return <a className="list-item" href="#" data-id={folder.id} data-type={BaseModel.TYPE_FOLDER} onContextMenu={(event) => this.itemContextMenu(event)} key={folder.id} style={style} onClick={() => {this.folderItem_click(folder)}}>{folder.title}</a>
|
||||
|
||||
const onDragOver = (event, folder) => {
|
||||
if (event.dataTransfer.types.indexOf('text/x-jop-note-ids') >= 0) event.preventDefault();
|
||||
}
|
||||
|
||||
const onDrop = async (event, folder) => {
|
||||
if (event.dataTransfer.types.indexOf('text/x-jop-note-ids') < 0) return;
|
||||
event.preventDefault();
|
||||
|
||||
const noteIds = JSON.parse(event.dataTransfer.getData('text/x-jop-note-ids'));
|
||||
for (let i = 0; i < noteIds.length; i++) {
|
||||
await Note.moveToFolder(noteIds[i], folder.id);
|
||||
}
|
||||
}
|
||||
|
||||
return <a
|
||||
className="list-item"
|
||||
onDragOver={(event) => { onDragOver(event, folder) } }
|
||||
onDrop={(event) => { onDrop(event, folder) } }
|
||||
href="#"
|
||||
data-id={folder.id}
|
||||
data-type={BaseModel.TYPE_FOLDER}
|
||||
onContextMenu={(event) => this.itemContextMenu(event)}
|
||||
key={folder.id}
|
||||
style={style} onClick={() => {this.folderItem_click(folder)}}>{folder.title}
|
||||
</a>
|
||||
}
|
||||
|
||||
tagItem(tag, selected) {
|
||||
@@ -189,9 +215,12 @@ class SideBarComponent extends React.Component {
|
||||
return <div style={style} key={key}>{icon}{label}</div>
|
||||
}
|
||||
|
||||
synchronizeButton(label) {
|
||||
synchronizeButton(type) {
|
||||
const style = this.style().button;
|
||||
return <a className="synchronize-button" style={style} href="#" key="sync_button" onClick={() => {this.sync_click()}}>{label}</a>
|
||||
const iconName = type === 'sync' ? 'fa-refresh' : 'fa-times';
|
||||
const label = type === 'sync' ? _('Synchronise') : _('Cancel');
|
||||
const icon = <i style={{fontSize: style.fontSize, marginRight: 5}} className={"fa " + iconName}></i>
|
||||
return <a className="synchronize-button" style={style} href="#" key="sync_button" onClick={() => {this.sync_click()}}>{icon}{label}</a>
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -232,7 +261,7 @@ class SideBarComponent extends React.Component {
|
||||
syncReportText.push(<div key={i}>{lines[i]}</div>);
|
||||
}
|
||||
|
||||
items.push(this.synchronizeButton(this.props.syncStarted ? _('Cancel') : _('Synchronise')));
|
||||
items.push(this.synchronizeButton(this.props.syncStarted ? 'cancel' : 'sync'));
|
||||
|
||||
items.push(<div style={this.style().syncReport} key='sync_report'>{syncReportText}</div>);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ body {
|
||||
</style>
|
||||
|
||||
<div id="hlScriptContainer"></div>
|
||||
<div id="content"></div>
|
||||
<div id="content" ondragstart="return false;" ondrop="return false;"></div>
|
||||
|
||||
<script>
|
||||
const { ipcRenderer } = require('electron');
|
||||
@@ -71,8 +71,6 @@ function applyHljs(codeElements) {
|
||||
// / Handle dynamically loading HLJS when a code element is present
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
ipcRenderer.on('setHtml', (event, html) => {
|
||||
contentElement.innerHTML = html;
|
||||
|
||||
|
||||
@@ -9,5 +9,12 @@
|
||||
<body>
|
||||
<div id="react-root"></div>
|
||||
<script src="main-html.js"></script>
|
||||
<style>
|
||||
/* Disable dragging of links (which are often buttons) */
|
||||
a:not([draggable=true]), img:not([draggable=true]) {
|
||||
-webkit-user-drag: none;
|
||||
user-drag: none;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,6 +31,19 @@ BaseItem.loadClass('NoteTag', NoteTag);
|
||||
Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
||||
Setting.setConstant('appType', 'desktop');
|
||||
|
||||
// Disable drag and drop of links inside application (which would
|
||||
// open it as if the whole app was a browser)
|
||||
document.addEventListener('dragover', event => event.preventDefault());
|
||||
document.addEventListener('drop', event => event.preventDefault());
|
||||
|
||||
// Disable middle-click (which would open a new browser window, but we don't want this)
|
||||
document.addEventListener('auxclick', event => event.preventDefault());
|
||||
|
||||
// Each link (rendered as a button or list item) has its own custom click event
|
||||
// so disable the default. In particular this will disable Ctrl+Clicking a link
|
||||
// which would open a new browser window.
|
||||
document.addEventListener('click', (event) => event.preventDefault());
|
||||
|
||||
shimInit();
|
||||
|
||||
app().start(bridge().processArgv()).then(() => {
|
||||
|
||||
12
ElectronClient/app/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "0.10.21",
|
||||
"version": "0.10.25",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -10,13 +10,13 @@
|
||||
"integrity": "sha512-+rr4OgeTNrLuJAf09o3USdttEYiXvZshWMkhD6wR9v1ieXH0JM1Q2yT41/cJuJcqiPpSXlM/g3aR+Y5MWQdr0Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"7zip-bin-mac": "1.0.1"
|
||||
"7zip-bin-win": "2.1.1"
|
||||
}
|
||||
},
|
||||
"7zip-bin-mac": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/7zip-bin-mac/-/7zip-bin-mac-1.0.1.tgz",
|
||||
"integrity": "sha1-Pmh3i78JJq3GgVlCcHRQXUdVXAI=",
|
||||
"7zip-bin-win": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/7zip-bin-win/-/7zip-bin-win-2.1.1.tgz",
|
||||
"integrity": "sha512-6VGEW7PXGroTsoI2QW3b0ea95HJmbVBHvfANKLLMzSzFA1zKqVX5ybNuhmeGpf6vA0x8FJTt6twpprDANsY5WQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@types/node": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "0.10.21",
|
||||
"version": "0.10.25",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -9,6 +9,14 @@ body, textarea {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* By default, the Ice Editor displays invalid characters, such as non-breaking spaces
|
||||
as red boxes, but since those are actually valid characters and common in imported
|
||||
Evernote data, we hide them here. */
|
||||
.ace-chrome .ace_invisible_space {
|
||||
background-color: transparent !important;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.note-list .list-item:hover {
|
||||
background-color: rgba(0,160,255,0.1) !important;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,14 @@ const request = require('request');
|
||||
const url = 'https://api.github.com/repos/laurent22/joplin/releases/latest';
|
||||
const readmePath = __dirname + '/../../README.md';
|
||||
|
||||
async function msleep(ms) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
|
||||
async function gitHubLatestRelease() {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get({
|
||||
@@ -17,6 +25,7 @@ async function gitHubLatestRelease() {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else if (response.statusCode !== 200) {
|
||||
console.warn(data);
|
||||
reject(new Error('Error HTTP ' + response.statusCode));
|
||||
} else {
|
||||
resolve(data);
|
||||
@@ -48,8 +57,23 @@ function setReadmeContent(content) {
|
||||
return fs.writeFileSync(readmePath, content);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const release = await gitHubLatestRelease();
|
||||
async function main(argv) {
|
||||
const waitForVersion = argv.length === 3 ? argv[2] : null;
|
||||
|
||||
if (waitForVersion) console.info('Waiting for version ' + waitForVersion + ' to be released before updating readme...');
|
||||
|
||||
let release = null;
|
||||
while (true) {
|
||||
release = await gitHubLatestRelease();
|
||||
if (!waitForVersion) break;
|
||||
|
||||
if (release.tag_name !== waitForVersion) {
|
||||
await msleep(60000 * 5);
|
||||
} else {
|
||||
console.info('Got version ' + waitForVersion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const winUrl = downloadUrl(release, 'windows');
|
||||
const macOsUrl = downloadUrl(release, 'macos');
|
||||
@@ -57,13 +81,13 @@ async function main() {
|
||||
|
||||
let content = readmeContent();
|
||||
|
||||
if (winUrl) content = content.replace(/(\(https:\/\/github.com\/laurent22\/joplin\/releases\/download\/.*?\.exe\))/, '(' + winUrl + ')');
|
||||
if (macOsUrl) content = content.replace(/(\(https:\/\/github.com\/laurent22\/joplin\/releases\/download\/.*?\.dmg\))/, '(' + macOsUrl + ')');
|
||||
if (linuxUrl) content = content.replace(/(\(https:\/\/github.com\/laurent22\/joplin\/releases\/download\/.*?\.AppImage\))/, '(' + linuxUrl + ')');
|
||||
if (winUrl) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin\/releases\/download\/.*?\.exe)/, winUrl);
|
||||
if (macOsUrl) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin\/releases\/download\/.*?\.dmg)/, macOsUrl);
|
||||
if (linuxUrl) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin\/releases\/download\/.*?\.AppImage)/, linuxUrl);
|
||||
|
||||
setReadmeContent(content);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
main(process.argv).catch((error) => {
|
||||
console.error('Fatal error', error);
|
||||
});
|
||||
@@ -9,4 +9,6 @@ git commit -m "Electron release $VERSION"
|
||||
git tag $VERSION
|
||||
git push && git push --tags
|
||||
|
||||
echo "Create a draft release at: https://github.com/laurent22/joplin/releases/tag/$VERSION"
|
||||
echo "Create a draft release at: https://github.com/laurent22/joplin/releases/tag/$VERSION"
|
||||
|
||||
node "$APP_DIR/update-readme-download.js" $VERSION
|
||||
@@ -1,47 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const https = require('https');
|
||||
const request = require('request');
|
||||
|
||||
const url = 'https://api.github.com/repos/laurent22/joplin/releases/latest';
|
||||
|
||||
async function gitHubLatestRelease() {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get({
|
||||
url: url,
|
||||
json: true,
|
||||
headers: {'User-Agent': 'Joplin Readme Updater'}
|
||||
}, (error, response, data) => {
|
||||
if (err) {
|
||||
reject(error);
|
||||
} else if (response.statusCode !== 200) {
|
||||
reject(new Error('Error HTTP ' + response.statusCode));
|
||||
} else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function downloadUrl(release, os) {
|
||||
if (!release || !release.assets || !release.assets.length) return null;
|
||||
|
||||
for (let i = 0; i < release.assets.length; i++) {
|
||||
const asset = release.assets[i];
|
||||
const name = asset.name;
|
||||
|
||||
if (name.indexOf('.dmg') > 0 && os === 'macos') return asset.browser_download_url;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const release = await gitHubLatestRelease();
|
||||
console.info(downloadUrl(release, 'windows'));
|
||||
console.info(downloadUrl(release, 'macos'));
|
||||
console.info(downloadUrl(release, 'linux'));
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('Fatal error', error);
|
||||
});
|
||||
29
README.md
@@ -8,26 +8,26 @@ The notes can be [synchronised](#synchronisation) with various targets including
|
||||
|
||||
Joplin is still under development but is out of Beta and should be suitable for every day use. The UI of the terminal client is built on top of the great [terminal-kit](https://github.com/cronvel/terminal-kit) library, the desktop client using [Electron](https://electronjs.org/), and the Android client front end is done using [React Native](https://facebook.github.io/react-native/).
|
||||
|
||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/AllClients.jpg" style="max-width: 100%">
|
||||
<div class="top-screenshot"><img src="https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/AllClients.jpg" style="max-width: 100%; max-height: 35em;"></div>
|
||||
|
||||
# Installation
|
||||
|
||||
Three types of applications are available: **desktop** (Windows, macOS and Linux), **mobile** (Android) or for **terminal** emulator (Windows, macOS and Linux). All applications have similar user interfaces and can synchronise with each others.
|
||||
Three types of applications are available: **desktop** (Windows, macOS and Linux), **mobile** (Android and iOS) and for **terminal** (Windows, macOS and Linux). All applications have similar user interfaces and can synchronise with each others.
|
||||
|
||||
## Desktop applications
|
||||
|
||||
Operating system | Link
|
||||
Operating System | Download
|
||||
-----------------|--------
|
||||
Windows | [Download Joplin for Windows](https://github.com/laurent22/joplin/releases/download/v0.10.20/Joplin-Setup-0.10.20.exe)
|
||||
macOS | [Download Joplin for macOS](https://github.com/laurent22/joplin/releases/download/v0.10.20/Joplin-0.10.20.dmg)
|
||||
Linux | [Download Joplin for Linux](https://github.com/laurent22/joplin/releases/download/v0.10.20/Joplin-0.10.20-x86_64.AppImage)
|
||||
Windows | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.25/Joplin-Setup-0.10.25.exe'><img alt='Get it on Windows' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeWindows.png'/></a>
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.25/Joplin-0.10.25.dmg'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeMacOS.png'/></a>
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.25/Joplin-0.10.25-x86_64.AppImage'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeLinux.png'/></a>
|
||||
|
||||
## Mobile applications
|
||||
|
||||
Operating system | Link
|
||||
Operating System | Download
|
||||
-----------------|--------
|
||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="60px" src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/></a>
|
||||
iOS | Coming soon!
|
||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeAndroid.png'/></a>
|
||||
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeIOS.png'/></a>
|
||||
|
||||
## Terminal application
|
||||
|
||||
@@ -108,15 +108,16 @@ This translation will apply to both the terminal and the Android application.
|
||||
|
||||
# Coming features
|
||||
|
||||
The two main features that remain to be implemented are:
|
||||
|
||||
- iOS application (80% done)
|
||||
- End to end encryption (to-do)
|
||||
- All: End to end encryption
|
||||
- Windows: Tray icon
|
||||
- Desktop apps: Tag auto-complete
|
||||
- Desktop apps: Dark theme
|
||||
- Linux: Enable auto-update for desktop app
|
||||
|
||||
# Known bugs
|
||||
|
||||
- Non-alphabetical characters such as Chinese or Arabic might create glitches in the terminal on Windows. This is a limitation of the current Windows console.
|
||||
- In the React Native app, changing the notebook of a note sometimes has no effect, due to [this bug](https://github.com/facebook/react-native/issues/15556). Due to [this other bug](https://github.com/facebook/react-native/issues/13351), changing one config value sometimes also set a different one. This is likely to be resolved soon in a future version of React Native.
|
||||
- Auto-update is not working in the Linux desktop application.
|
||||
|
||||
# License
|
||||
|
||||
|
||||
1
README_desktop.md
Normal file
@@ -0,0 +1 @@
|
||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/DemoDesktop.png" style="max-width: 100%">
|
||||
1
ReactNativeClient/.gitignore
vendored
@@ -53,6 +53,5 @@ fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
|
||||
# This is generated:
|
||||
locales
|
||||
android/build*
|
||||
android/app/build*
|
||||
|
||||
@@ -90,8 +90,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 22
|
||||
versionCode 57
|
||||
versionName "0.10.44"
|
||||
versionCode 74
|
||||
versionName "0.10.59"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
@@ -137,6 +137,8 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':react-native-fs')
|
||||
compile project(':react-native-image-picker')
|
||||
compile project(':react-native-vector-icons')
|
||||
compile project(':react-native-fs')
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="net.cozic.joplin"
|
||||
android:versionCode="2"
|
||||
android:versionName="0.8.0">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="net.cozic.joplin"
|
||||
android:versionCode="2"
|
||||
android:versionName="0.8.0">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
|
||||
<!-- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove"/>
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="22" />
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:allowBackup="true"
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:launchMode="singleInstance">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
</application>
|
||||
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:launchMode="singleInstance">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.cozic.joplin;
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.imagepicker.ImagePickerPackage;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
@@ -30,6 +31,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new ImageResizerPackage(),
|
||||
new MainReactPackage(),
|
||||
new ImagePickerPackage(),
|
||||
new ReactNativeDocumentPicker(),
|
||||
new RNFetchBlobPackage(),
|
||||
new RNFSPackage(),
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 7.8 KiB |
@@ -1,4 +1,8 @@
|
||||
rootProject.name = 'Joplin'
|
||||
include ':react-native-fs'
|
||||
project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
|
||||
include ':react-native-image-picker'
|
||||
project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android')
|
||||
include ':react-native-vector-icons'
|
||||
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
|
||||
include ':react-native-image-resizer'
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
cd android
|
||||
gradlew.bat installDebug
|
||||
gradlew.bat installDebug --console plain
|
||||
9
ReactNativeClient/build_android_prod.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
rem Clear build dir if permission issue:
|
||||
rem rmdir /S/Q android\app\build
|
||||
|
||||
setlocal
|
||||
node ..\Tools\prepare-android-prod-build.js
|
||||
cd android
|
||||
gradlew.bat assembleRelease -PbuildDir=build --console plain
|
||||
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D2A28121D9B038B00D4039D"
|
||||
BuildableName = "libReact.a"
|
||||
BlueprintName = "React-tvOS"
|
||||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOSTests.xctest"
|
||||
BlueprintName = "Joplin-tvOSTests"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOSTests.xctest"
|
||||
BlueprintName = "Joplin-tvOSTests"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Joplin-tvOS.app"
|
||||
BlueprintName = "Joplin-tvOS"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -35,11 +35,11 @@
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForTesting = "NO"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
@@ -57,16 +57,6 @@
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "JoplinTests.xctest"
|
||||
BlueprintName = "JoplinTests"
|
||||
ReferencedContainer = "container:Joplin.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
||||
|
After Width: | Height: | Size: 74 KiB |
@@ -1,34 +1,154 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"filename" : "icon-29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"filename" : "icon-29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"filename" : "icon-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"filename" : "icon-40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "57x57",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-57@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "57x57",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-57@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-50@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-50@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "72x72",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-72@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "72x72",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-72@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppStore.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 6.3 KiB |