You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-30 20:39:46 +02:00
Compare commits
40 Commits
android-v1
...
cli-v1.0.1
Author | SHA1 | Date | |
---|---|---|---|
|
7b85c33213 | ||
|
4b4d0e8b25 | ||
|
4fb6af3c62 | ||
|
d7ffe7e294 | ||
|
3ff139d445 | ||
|
40443e0134 | ||
|
1f927c1285 | ||
|
5e82e62335 | ||
|
de954827df | ||
|
2cb24bf198 | ||
|
739a6a4a9c | ||
|
dfcf1193dc | ||
|
c72f92e22f | ||
|
f6d01ce7e1 | ||
|
fed9700587 | ||
|
12a3a9a89e | ||
|
590c62c371 | ||
|
df41f64b3c | ||
|
1849355245 | ||
|
fa1b471ea4 | ||
|
0a67f8c947 | ||
|
621d0260f4 | ||
|
f93fca7c5b | ||
|
f4d830c2ef | ||
|
1aa2844efa | ||
|
f22b2adaad | ||
|
b547f9aa13 | ||
|
e4166e9da7 | ||
|
1634fdb421 | ||
|
7f51035f91 | ||
|
70e71cbc2a | ||
|
ffd03bf34c | ||
|
f59a3dee78 | ||
|
3ba3037242 | ||
|
dbb269fef6 | ||
|
e209189faa | ||
|
2d7065cde2 | ||
|
59f5972c93 | ||
|
8bac5275c3 | ||
|
58d748e235 |
@@ -15,6 +15,8 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.1.1\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
|
||||
msgid "To delete a tag, untag the associated notes."
|
||||
msgstr ""
|
||||
@@ -197,8 +199,8 @@ msgid ""
|
||||
"complete database including notebooks, notes, tags and resources."
|
||||
msgstr ""
|
||||
"Exportiert Joplin-Dateien in den angegebenen Pfad. Standardmäßig wird die "
|
||||
"komplette Datenbank inklusive Notizbüchern, Notizen, Tags und Anhängen "
|
||||
"exportiert."
|
||||
"komplette Datenbank inklusive Notizbüchern, Notizen, Schlagwörtern und "
|
||||
"Anhängen exportiert."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Destination format: %s"
|
||||
@@ -305,7 +307,7 @@ msgstr "Anhänge: %d."
|
||||
|
||||
#, javascript-format
|
||||
msgid "Tagged: %d."
|
||||
msgstr "Getagged: %d."
|
||||
msgstr "Verschlagwortet: %d."
|
||||
|
||||
msgid "Importing notes..."
|
||||
msgstr "Importiere Notizen..."
|
||||
@@ -918,7 +920,7 @@ msgid "Notebook title:"
|
||||
msgstr "Notizbuch-Titel:"
|
||||
|
||||
msgid "Add or remove tags:"
|
||||
msgstr "Füge hinzu oder entferne Schlagwörter:"
|
||||
msgstr "Schlagwörter hinzufügen oder entfernen:"
|
||||
|
||||
msgid "Separate each tag by a comma."
|
||||
msgstr "Trenne jedes Schlagwort mit einem Komma."
|
||||
|
2
CliClient/package-lock.json
generated
2
CliClient/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "joplin",
|
||||
"version": "1.0.116",
|
||||
"version": "1.0.117",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "1.0.116",
|
||||
"version": "1.0.117",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
|
31
CliClient/tests/models_Resource.js
Normal file
31
CliClient/tests/models_Resource.js
Normal file
@@ -0,0 +1,31 @@
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const Note = require('lib/models/Note.js');
|
||||
const Resource = require('lib/models/Resource.js');
|
||||
const BaseModel = require('lib/BaseModel.js');
|
||||
const { shim } = require('lib/shim');
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
});
|
||||
|
||||
describe('models_Resource', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should have a "done" fetch_status when created locally', asyncTest(async () => {
|
||||
let folder1 = await Folder.save({ title: "folder1" });
|
||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
||||
let resource1 = (await Resource.all())[0];
|
||||
console.info(resource1);
|
||||
}));
|
||||
|
||||
});
|
0
CliClientDemo/publish.sh
Normal file → Executable file
0
CliClientDemo/publish.sh
Normal file → Executable file
@@ -1,20 +1,20 @@
|
||||
function randomClipperPort(state, env) {
|
||||
const startPorts = {
|
||||
prod: 41184,
|
||||
dev: 27583,
|
||||
};
|
||||
const startPorts = {
|
||||
prod: 41184,
|
||||
dev: 27583,
|
||||
};
|
||||
|
||||
const startPort = env === 'prod' ? startPorts.prod : startPorts.dev;
|
||||
const startPort = env === 'prod' ? startPorts.prod : startPorts.dev;
|
||||
|
||||
if (!state) {
|
||||
state = { offset: 0 };
|
||||
} else {
|
||||
state.offset++;
|
||||
}
|
||||
if (!state) {
|
||||
state = { offset: 0 };
|
||||
} else {
|
||||
state.offset++;
|
||||
}
|
||||
|
||||
state.port = startPort + state.offset;
|
||||
state.port = startPort + state.offset;
|
||||
|
||||
return state;
|
||||
return state;
|
||||
}
|
||||
|
||||
module.exports = randomClipperPort;
|
@@ -49,7 +49,6 @@ class Application extends BaseApplication {
|
||||
constructor() {
|
||||
super();
|
||||
this.lastMenuScreen_ = null;
|
||||
this.powerSaveBlockerId_ = null;
|
||||
}
|
||||
|
||||
hasGui() {
|
||||
@@ -221,17 +220,6 @@ class Application extends BaseApplication {
|
||||
Setting.setValue('sidebarVisibility', newState.sidebarVisibility);
|
||||
}
|
||||
|
||||
if (action.type === 'SYNC_STARTED') {
|
||||
if (!this.powerSaveBlockerId_) this.powerSaveBlockerId_ = bridge().powerSaveBlockerStart('prevent-app-suspension');
|
||||
}
|
||||
|
||||
if (action.type === 'SYNC_COMPLETED') {
|
||||
if (this.powerSaveBlockerId_) {
|
||||
bridge().powerSaveBlockerStop(this.powerSaveBlockerId_);
|
||||
this.powerSaveBlockerId_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -741,8 +729,6 @@ class Application extends BaseApplication {
|
||||
ids: Setting.value('collapsedFolderIds'),
|
||||
});
|
||||
|
||||
if (shim.isLinux()) bridge().setAllowPowerSaveBlockerToggle(true);
|
||||
|
||||
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
||||
// but then doesn't install it on exit.
|
||||
if (shim.isWindows() || shim.isMac()) {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
const { _, setLocale } = require('lib/locale.js');
|
||||
const { dirname } = require('lib/path-utils.js');
|
||||
const { Logger } = require('lib/logger.js');
|
||||
const { powerSaveBlocker } = require('electron');
|
||||
|
||||
class Bridge {
|
||||
|
||||
@@ -9,7 +8,6 @@ class Bridge {
|
||||
this.electronWrapper_ = electronWrapper;
|
||||
this.autoUpdateLogger_ = null;
|
||||
this.lastSelectedPath_ = null;
|
||||
this.allowPowerSaveBlockerToggle_ = false;
|
||||
}
|
||||
|
||||
electronApp() {
|
||||
@@ -24,10 +22,6 @@ class Bridge {
|
||||
return this.electronWrapper_.window();
|
||||
}
|
||||
|
||||
setAllowPowerSaveBlockerToggle(v) {
|
||||
this.allowPowerSaveBlockerToggle_ = v;
|
||||
}
|
||||
|
||||
windowContentSize() {
|
||||
if (!this.window()) return { width: 0, height: 0 };
|
||||
const s = this.window().getContentSize();
|
||||
@@ -126,19 +120,7 @@ class Bridge {
|
||||
const { checkForUpdates } = require('./checkForUpdates.js');
|
||||
checkForUpdates(inBackground, window, logFilePath);
|
||||
}
|
||||
|
||||
powerSaveBlockerStart(type) {
|
||||
if (!this.allowPowerSaveBlockerToggle_) return null;
|
||||
console.info('Enable powerSaveBlockerStart: ' + type);
|
||||
return powerSaveBlocker.start(type);
|
||||
}
|
||||
|
||||
powerSaveBlockerStop(id) {
|
||||
if (!this.allowPowerSaveBlockerToggle_) return null;
|
||||
console.info('Disable powerSaveBlocker: ' + id);
|
||||
return powerSaveBlocker.stop(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
let bridge_ = null;
|
||||
|
@@ -595,6 +595,8 @@ class NoteTextComponent extends React.Component {
|
||||
} else {
|
||||
require('electron').shell.openExternal(msg);
|
||||
}
|
||||
} else if (msg.indexOf('#') === 0) {
|
||||
// This is an internal anchor, which is handled by the WebView so skip this case
|
||||
} else {
|
||||
bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg));
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ const { bridge } = require("electron").remote.require("./bridge");
|
||||
const Menu = bridge().Menu;
|
||||
const MenuItem = bridge().MenuItem;
|
||||
const InteropServiceHelper = require("../InteropServiceHelper.js");
|
||||
const { shim } = require('lib/shim');
|
||||
|
||||
class SideBarComponent extends React.Component {
|
||||
|
||||
@@ -178,6 +179,35 @@ class SideBarComponent extends React.Component {
|
||||
return style;
|
||||
}
|
||||
|
||||
clearForceUpdateDuringSync() {
|
||||
if (this.forceUpdateDuringSyncIID_) {
|
||||
clearInterval(this.forceUpdateDuringSyncIID_);
|
||||
this.forceUpdateDuringSyncIID_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (shim.isLinux()) {
|
||||
// For some reason, the UI seems to sleep in some Linux distro during
|
||||
// sync. Cannot find the reason for it and cannot replicate, so here
|
||||
// as a test force the update at regular intervals.
|
||||
// https://github.com/laurent22/joplin/issues/312#issuecomment-429472193
|
||||
if (!prevProps.syncStarted && this.props.syncStarted) {
|
||||
this.clearForceUpdateDuringSync();
|
||||
|
||||
this.forceUpdateDuringSyncIID_ = setInterval(() => {
|
||||
this.forceUpdate();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
if (prevProps.syncStarted && !this.props.syncStarted) this.clearForceUpdateDuringSync();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearForceUpdateDuringSync();
|
||||
}
|
||||
|
||||
itemContextMenu(event) {
|
||||
const itemId = event.target.getAttribute("data-id");
|
||||
if (itemId === Folder.conflictFolderId()) return;
|
||||
|
@@ -276,12 +276,24 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent URLs added via <a> tags from being opened within the application itself
|
||||
document.addEventListener('click', function(event) {
|
||||
const t = event.target;
|
||||
|
||||
// Prevent URLs added via <a> tags from being opened within the application itself
|
||||
if (t && t.nodeName === 'A' && !t.hasAttribute('data-from-md')) {
|
||||
event.preventDefault();
|
||||
ipcProxySendToHost(t.getAttribute('href'));
|
||||
return;
|
||||
}
|
||||
|
||||
// IF this is an internal link, jump to the anchor directly
|
||||
if (t && t.nodeName === 'A' && t.hasAttribute('data-from-md')) {
|
||||
const href = t.getAttribute('href');
|
||||
if (href.indexOf('#') === 0) {
|
||||
event.preventDefault();
|
||||
location.hash = href;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
2
ElectronClient/app/package-lock.json
generated
2
ElectronClient/app/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "1.0.112",
|
||||
"version": "1.0.114",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "1.0.112",
|
||||
"version": "1.0.114",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
0
ElectronClient/run-prod.sh
Normal file → Executable file
0
ElectronClient/run-prod.sh
Normal file → Executable file
@@ -1,52 +1,70 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
# Title
|
||||
echo " _ _ _ _ _ _ _ "
|
||||
echo " | | | |(_) (_) | | | | | "
|
||||
echo " | | ___ _ __ | | _ _ __ _ _ __ ___| |_ __ _| | | ___ _ __ "
|
||||
echo " _ | |/ _ \| _ \| || | _ \ | | _ \ / __| __ | | |/ _ \ __| "
|
||||
echo " | |__| | (_) | |_) | || | | | | | | | | \__ \ || (_| | | | __/ | "
|
||||
echo " \____/ \___/| .__/|_||_|_| |_| |_|_| |_|___/\__\__,_|_|_|\___|_| "
|
||||
echo " | | "
|
||||
echo " |_| "
|
||||
echo " _ _ _ _ _ _ "
|
||||
echo " | | (_) (_) | | | | | "
|
||||
echo " | | ___ _ __ _ _ __ _ _ __ ___| |_ __ _| | | ___ _ __ "
|
||||
echo " _ | |/ _ \\\| '_ \| | '_ \\ | | '_ \\\/ __| __/ _\` | | |/ _ \ '__|"
|
||||
echo " | |__| | (_) | |_) | | | | | | | | | \__ \ || (_| | | | __/ | "
|
||||
echo " \____/ \___/| .__/|_|_| |_| |_|_| |_|___/\__\__,_|_|_|\___|_| "
|
||||
echo " | | "
|
||||
echo " |_| "
|
||||
echo ""
|
||||
|
||||
#-----------------------------------------------------
|
||||
# Download Joplin
|
||||
#-----------------------------------------------------
|
||||
|
||||
# Get the latest version to download
|
||||
version=$(curl --silent "https://api.github.com/repos/laurent22/joplin/releases/latest" | grep -Po '"tag_name": "v\K.*?(?=")')
|
||||
|
||||
# Delete previous version
|
||||
rm -f ~/.joplin/*.AppImage ~/.local/share/applications/*joplin.desktop
|
||||
# Check if it's in the latest version
|
||||
touch VERSION
|
||||
if [[ $(< ~/.joplin/VERSION) != "$version" ]]; then
|
||||
|
||||
# Creates the folder where the binary will be stored
|
||||
mkdir -p ~/.joplin/
|
||||
# Delete previous version
|
||||
rm -f ~/.joplin/*.AppImage ~/.local/share/applications/joplin.desktop ~/.joplin/VERSION
|
||||
|
||||
# Creates the folder where the binary will be stored
|
||||
mkdir -p ~/.joplin/
|
||||
|
||||
# Download the latest version
|
||||
wget -O ~/.joplin/Joplin.AppImage https://github.com/laurent22/joplin/releases/download/v$version/Joplin-$version-x86_64.AppImage
|
||||
|
||||
# Gives execution privileges
|
||||
chmod +x ~/.joplin/Joplin.AppImage
|
||||
|
||||
#-----------------------------------------------------
|
||||
# Icon
|
||||
#-----------------------------------------------------
|
||||
|
||||
# Download icon
|
||||
wget -O ~/.joplin/Icon512.png https://joplin.cozic.net/images/Icon512.png
|
||||
|
||||
# Detect desktop environment
|
||||
if [ "$XDG_CURRENT_DESKTOP" = "" ]
|
||||
then
|
||||
desktop=$(echo "$XDG_DATA_DIRS" | sed 's/.*\(xfce\|kde\|gnome\).*/\1/')
|
||||
else
|
||||
desktop=$XDG_CURRENT_DESKTOP
|
||||
fi
|
||||
desktop=${desktop,,} # convert to lower case
|
||||
|
||||
# Download the latest version
|
||||
wget -O ~/.joplin/Joplin-$version-x86_64.AppImage https://github.com/laurent22/joplin/releases/download/v$version/Joplin-$version-x86_64.AppImage
|
||||
|
||||
# Gives execution privileges
|
||||
chmod +x ~/.joplin/Joplin-$version-x86_64.AppImage
|
||||
|
||||
# Download icon
|
||||
wget -O ~/.joplin/Icon512.png https://joplin.cozic.net/images/Icon512.png
|
||||
|
||||
# Detect desktop environment
|
||||
if [ "$XDG_CURRENT_DESKTOP" = "" ]
|
||||
then
|
||||
desktop=$(echo "$XDG_DATA_DIRS" | sed 's/.*\(xfce\|kde\|gnome\).*/\1/')
|
||||
# Create icon for Gnome
|
||||
if [[ $desktop =~ .*gnome.* ]]
|
||||
then
|
||||
echo -e "[Desktop Entry]\nEncoding=UTF-8\nName=Joplin\nExec=/home/$USER/.joplin/Joplin-$version-x86_64.AppImage\nIcon=/home/$USER/.joplin/Icon512.png\nType=Application\nCategories=Application;" >> ~/.local/share/applications/joplin.desktop
|
||||
fi
|
||||
|
||||
#-----------------------------------------------------
|
||||
# Finish
|
||||
#-----------------------------------------------------
|
||||
|
||||
# Informs the user that it has been installed and cleans variables
|
||||
echo 'Joplin installed in the version' $version
|
||||
# Add version
|
||||
echo $version > ~/.joplin/VERSION
|
||||
else
|
||||
desktop=$XDG_CURRENT_DESKTOP
|
||||
echo 'You are now in the latest version.'
|
||||
fi
|
||||
desktop=${desktop,,} # convert to lower case
|
||||
|
||||
# Create icon for Gnome
|
||||
if [[ $desktop =~ .*gnome.* ]]
|
||||
then
|
||||
echo -e "[Desktop Entry]\nEncoding=UTF-8\nName=Joplin\nExec=/home/$USER/.joplin/Joplin-$version-x86_64.AppImage\nIcon=/home/$USER/.joplin/Icon512.png\nType=Application\nCategories=Application;" >> ~/.local/share/applications/joplin.desktop
|
||||
fi
|
||||
|
||||
# Informs the user that it has been installed and cleans variables
|
||||
echo 'Joplin installed in the version' $version
|
||||
|
||||
# start Joplin:
|
||||
~/.joplin/Joplin-$version-x86_64.AppImage
|
||||
|
||||
unset version
|
||||
|
13
README.md
13
README.md
@@ -34,9 +34,9 @@ Three types of applications are available: for the **desktop** (Windows, macOS a
|
||||
|
||||
Operating System | Download | Alternative
|
||||
-----------------|--------|-------------------
|
||||
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/Joplin-Setup-1.0.111.exe'><img alt='Get it on Windows' height="40px" src='https://joplin.cozic.net/images/BadgeWindows.png'/></a> | or Get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/JoplinPortable.exe'>Portable version</a><br>(to run from a USB key, etc.)
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/Joplin-1.0.111.dmg'><img alt='Get it on macOS' height="40px" src='https://joplin.cozic.net/images/BadgeMacOS.png'/></a> |
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/Joplin-1.0.111-x86_64.AppImage'><img alt='Get it on Linux' height="40px" src='https://joplin.cozic.net/images/BadgeLinux.png'/></a> | An Arch Linux package<br>[is also available](#terminal-application).
|
||||
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/Joplin-Setup-1.0.114.exe'><img alt='Get it on Windows' height="40px" src='https://joplin.cozic.net/images/BadgeWindows.png'/></a> | or Get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/JoplinPortable.exe'>Portable version</a><br>(to run from a USB key, etc.)
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/Joplin-1.0.114.dmg'><img alt='Get it on macOS' height="40px" src='https://joplin.cozic.net/images/BadgeMacOS.png'/></a> |
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/Joplin-1.0.114-x86_64.AppImage'><img alt='Get it on Linux' height="40px" src='https://joplin.cozic.net/images/BadgeLinux.png'/></a> | An Arch Linux package<br>[is also available](#terminal-application).
|
||||
|
||||
The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
|
||||
@@ -50,7 +50,7 @@ wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_insta
|
||||
|
||||
Operating System | Download | Alt. 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="40px" src='https://joplin.cozic.net/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.142/joplin-v1.0.142.apk)
|
||||
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://joplin.cozic.net/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.175/joplin-v1.0.175.apk)
|
||||
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://joplin.cozic.net/images/BadgeIOS.png'/></a> | -
|
||||
|
||||
## Terminal application
|
||||
@@ -173,7 +173,7 @@ If synchronisation does not work, please consult the logs in the app profile dir
|
||||
|
||||
## Dropbox synchronisation
|
||||
|
||||
When syncing with Dropbox, Joplin creates a sub-directory in Dropbox, in /Apps/Joplin and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.
|
||||
When syncing with Dropbox, Joplin creates a sub-directory in Dropbox, in `/Apps/Joplin` and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.
|
||||
|
||||
On the **desktop application** or **mobile application**, select "Dropbox" as the synchronisation target in the config screen (it is selected by default). Then, to initiate the synchronisation process, click on the "Synchronise" button in the sidebar and follow the instructions.
|
||||
|
||||
@@ -192,6 +192,7 @@ WebDAV-compatible services that are known to work with Joplin:
|
||||
- [Fastmail](https://www.fastmail.com/)
|
||||
- [HiDrive](https://www.strato.fr/stockage-en-ligne/) from Strato. [Setup help](https://github.com/laurent22/joplin/issues/309)
|
||||
- [Nginx WebDAV Module](https://nginx.org/en/docs/http/ngx_http_dav_module.html)
|
||||
- [NextCloud](https://nextcloud.com/)
|
||||
- [OwnCloud](https://owncloud.org/)
|
||||
- [Seafile](https://www.seafile.com/)
|
||||
- [Stack](https://www.transip.nl/stack/)
|
||||
@@ -259,7 +260,7 @@ Since getting the ID of a note is not straightforward, each app provides a way t
|
||||
|
||||
## Math notation
|
||||
|
||||
Math expressions can be added using the [Katex notation](https://khan.github.io/KaTeX/). To add an inline equation, wrap the expression in `$EXPRESSION$`, eg. `$\sqrt{3x-1}+(1+x)^2$`. To create an expression block, wrap it as follow:
|
||||
Math expressions can be added using the [KaTeX notation](https://khan.github.io/KaTeX/). To add an inline equation, wrap the expression in `$EXPRESSION$`, eg. `$\sqrt{3x-1}+(1+x)^2$`. To create an expression block, wrap it as follow:
|
||||
|
||||
$$
|
||||
EXPRESSION
|
||||
|
@@ -90,8 +90,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097320
|
||||
versionName "1.0.142"
|
||||
versionCode 2097411
|
||||
versionName "1.0.175"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
@@ -137,6 +137,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':react-native-camera')
|
||||
compile project(':react-native-file-viewer')
|
||||
compile project(':react-native-securerandom')
|
||||
compile project(':react-native-push-notification')
|
||||
@@ -153,6 +154,24 @@ dependencies {
|
||||
compile project(':react-native-image-resizer')
|
||||
compile project(':react-native-share-extension')
|
||||
compile "com.facebook.react:react-native:+"
|
||||
|
||||
// To fix the error below, which happened after adding react-native-camera.
|
||||
// Doesn't make any sense since rn-camera neither defines v26 nor 27 but
|
||||
// v25.0.2 in build.gradle, but anyway now it works ¯\_(ツ)_/¯
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Fatal error
|
||||
// { Error: Command failed: ./gradlew assembleRelease -PbuildDir=build --console plain
|
||||
//
|
||||
// FAILURE: Build failed with an exception.
|
||||
//
|
||||
// * What went wrong:
|
||||
// Execution failed for task ':app:preReleaseBuild'.
|
||||
// > Android dependency 'com.android.support:support-v4' has different version for the compile (26.1.0) and runtime (27.1.1) classpath. You should manually set the same version via DependencyResolution
|
||||
// --------------------------------------------------------------------------------------
|
||||
// https://github.com/react-native-community/react-native-camera/issues/1532#issuecomment-386434771
|
||||
compile ("com.android.support:support-v4:26.0.1") {
|
||||
force = true //<-- force dependency resolution to 26.0.1 in my case
|
||||
}
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
|
@@ -3,6 +3,7 @@ package net.cozic.joplin;
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import org.reactnative.camera.RNCameraPackage;
|
||||
import com.vinzscam.reactnativefileviewer.RNFileViewerPackage;
|
||||
import net.rhogan.rnsecurerandom.RNSecureRandomPackage;
|
||||
import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;
|
||||
@@ -37,6 +38,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new ImageResizerPackage(),
|
||||
new MainReactPackage(),
|
||||
new RNCameraPackage(),
|
||||
new RNFileViewerPackage(),
|
||||
new RNSecureRandomPackage(),
|
||||
new ReactNativePushNotificationPackage(),
|
||||
|
@@ -1,4 +1,6 @@
|
||||
rootProject.name = 'Joplin'
|
||||
include ':react-native-camera'
|
||||
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
|
||||
include ':react-native-file-viewer'
|
||||
project(':react-native-file-viewer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-file-viewer/android')
|
||||
include ':react-native-securerandom'
|
||||
|
0
ReactNativeClient/debug_log.sh
Normal file → Executable file
0
ReactNativeClient/debug_log.sh
Normal file → Executable file
@@ -13,6 +13,7 @@
|
||||
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
|
||||
0DAD2E67F6A14BDC8250B927 /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 82214D3345D846709A314868 /* libRNDocumentPicker.a */; };
|
||||
12AE298E1C0E445682922DAB /* libRNCamera.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E132B594F4FB4C96A2E2B0FF /* libRNCamera.a */; };
|
||||
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
|
||||
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
|
||||
@@ -342,6 +343,13 @@
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RNFileViewer;
|
||||
};
|
||||
4D8C5643217161BF00E93280 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = FC908F114F494130A324B402 /* RNCamera.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 4107012F1ACB723B00C6AA39;
|
||||
remoteInfo = RNCamera;
|
||||
};
|
||||
4DA7F80C1FC1DA9C00353191 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A4716DB8654B431D894F89E1 /* RNImagePicker.xcodeproj */;
|
||||
@@ -441,9 +449,11 @@
|
||||
CCDC2774CD86466F897D88E2 /* libRNFileViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFileViewer.a; sourceTree = "<group>"; };
|
||||
CCDE9E9AF09B45F391B1C2AF /* SQLite.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = SQLite.xcodeproj; path = "../node_modules/react-native-sqlite-storage/src/ios/SQLite.xcodeproj"; sourceTree = "<group>"; };
|
||||
DF1C50EBC11E46A3AF87F80A /* RCTImageResizer.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTImageResizer.xcodeproj; path = "../node_modules/react-native-image-resizer/ios/RCTImageResizer.xcodeproj"; sourceTree = "<group>"; };
|
||||
E132B594F4FB4C96A2E2B0FF /* libRNCamera.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCamera.a; sourceTree = "<group>"; };
|
||||
E2638D52624B477FABB52B8F /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = "<group>"; };
|
||||
F098E1ACCB594C828C851A57 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
||||
F5E37D05726A4A08B2EE323A /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFetchBlob.a; sourceTree = "<group>"; };
|
||||
FC908F114F494130A324B402 /* RNCamera.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNCamera.xcodeproj; path = "../node_modules/react-native-camera/ios/RNCamera.xcodeproj"; sourceTree = "<group>"; };
|
||||
FD370E24D76E461D960DD85D /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = "<group>"; };
|
||||
FF411B45E68B4A8CBCC35777 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -477,6 +487,7 @@
|
||||
AF99EEC6C55042F7BFC87583 /* libRNImagePicker.a in Frameworks */,
|
||||
F3D0BB525E6C490294D73075 /* libRNSecureRandom.a in Frameworks */,
|
||||
82C61D3DAE0A4666883001E9 /* libRNFileViewer.a in Frameworks */,
|
||||
12AE298E1C0E445682922DAB /* libRNCamera.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -611,6 +622,7 @@
|
||||
44A39642217548C8ADA91CBA /* libRNImagePicker.a */,
|
||||
22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */,
|
||||
CCDC2774CD86466F897D88E2 /* libRNFileViewer.a */,
|
||||
E132B594F4FB4C96A2E2B0FF /* libRNCamera.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
@@ -672,6 +684,14 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4D8C5640217161BF00E93280 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4D8C5644217161BF00E93280 /* libRNCamera.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4DA7F8091FC1DA9C00353191 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -750,6 +770,7 @@
|
||||
A4716DB8654B431D894F89E1 /* RNImagePicker.xcodeproj */,
|
||||
252BD7B86BF7435B960DA901 /* RNSecureRandom.xcodeproj */,
|
||||
59F5448FAF7345F8B568BD00 /* RNFileViewer.xcodeproj */,
|
||||
FC908F114F494130A324B402 /* RNCamera.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -907,6 +928,10 @@
|
||||
ProductGroup = 146834001AC3E56700842450 /* Products */;
|
||||
ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 4D8C5640217161BF00E93280 /* Products */;
|
||||
ProjectRef = FC908F114F494130A324B402 /* RNCamera.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 4D2A85AD1FBCE3AC0028537D /* Products */;
|
||||
ProjectRef = 02C42EA98156482DB00BF86D /* RNDocumentPicker.xcodeproj */;
|
||||
@@ -1242,6 +1267,13 @@
|
||||
remoteRef = 4D8B719B2163E8C500136BBC /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
4D8C5644217161BF00E93280 /* libRNCamera.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRNCamera.a;
|
||||
remoteRef = 4D8C5643217161BF00E93280 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
4DA7F80D1FC1DA9C00353191 /* libRNImagePicker.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@@ -1379,6 +1411,7 @@
|
||||
"$(SRCROOT)..\node_modules\neact-native-image-pickerios",
|
||||
"$(SRCROOT)..\node_modules\neact-native-securerandomios",
|
||||
"$(SRCROOT)..\node_modules\neact-native-file-viewerios",
|
||||
"$(SRCROOT)/../node_modules/react-native-camera/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1386,6 +1419,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/Joplin\"",
|
||||
"\"$(SRCROOT)/Joplin\"",
|
||||
"\"$(SRCROOT)/Joplin\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1421,6 +1455,7 @@
|
||||
"$(SRCROOT)..\node_modules\neact-native-image-pickerios",
|
||||
"$(SRCROOT)..\node_modules\neact-native-securerandomios",
|
||||
"$(SRCROOT)..\node_modules\neact-native-file-viewerios",
|
||||
"$(SRCROOT)/../node_modules/react-native-camera/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1428,6 +1463,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/Joplin\"",
|
||||
"\"$(SRCROOT)/Joplin\"",
|
||||
"\"$(SRCROOT)/Joplin\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
|
@@ -17,11 +17,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>10.0.24</string>
|
||||
<string>10.0.26</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>24</string>
|
||||
<string>26</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
|
@@ -89,13 +89,14 @@ class MdToHtml {
|
||||
if (!resource) {
|
||||
// Can happen for example if an image is attached to a note, but the resource hasn't
|
||||
// been downloaded from the sync target yet.
|
||||
console.warn('Cannot load resource: ' + id);
|
||||
console.info('Cannot load resource: ' + id);
|
||||
delete this.loadedResources_[id];
|
||||
return;
|
||||
}
|
||||
|
||||
if (resource.fetch_status !== Resource.FETCH_STATUS_DONE) {
|
||||
delete this.loadedResources_[id];
|
||||
console.warn('Resource not yet fetched: ' + id);
|
||||
console.info('Resource not yet fetched: ' + id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
83
ReactNativeClient/lib/components/CameraView.js
Normal file
83
ReactNativeClient/lib/components/CameraView.js
Normal file
@@ -0,0 +1,83 @@
|
||||
const React = require('react'); const Component = React.Component;
|
||||
const { View, Button, StyleSheet, TouchableOpacity } = require('react-native');
|
||||
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
|
||||
import { RNCamera } from 'react-native-camera';
|
||||
const Icon = require('react-native-vector-icons/Ionicons').default;
|
||||
const { _ } = require('lib/locale.js');
|
||||
|
||||
class CameraView extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
snapping: false,
|
||||
};
|
||||
|
||||
this.back_onPress = this.back_onPress.bind(this);
|
||||
this.photo_onPress = this.photo_onPress.bind(this);
|
||||
}
|
||||
|
||||
back_onPress() {
|
||||
if (this.props.onCancel) this.props.onCancel();
|
||||
}
|
||||
|
||||
async photo_onPress() {
|
||||
if (!this.camera || !this.props.onPhoto) return;
|
||||
|
||||
this.setState({ snapping: true });
|
||||
|
||||
const result = await this.camera.takePictureAsync({
|
||||
quality: 0.8,
|
||||
exif: true,
|
||||
fixOrientation: true
|
||||
});
|
||||
|
||||
if (this.props.onPhoto) this.props.onPhoto(result);
|
||||
|
||||
this.setState({ snapping: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const theme = themeStyle(this.props.theme);
|
||||
const photoIcon = this.state.snapping ? 'md-checkmark' : 'md-camera';
|
||||
|
||||
return (
|
||||
<View style={this.props.style}>
|
||||
<RNCamera
|
||||
style={{flex:1}}
|
||||
ref={ref => { this.camera = ref; }}
|
||||
type={RNCamera.Constants.Type.back}
|
||||
permissionDialogTitle={_('Permission to use camera')}
|
||||
permissionDialogMessage={_('Your permission to use your camera is required.')}
|
||||
>
|
||||
<View style={{flex:1, justifyContent:'space-between', flexDirection:'column'}}>
|
||||
<View style={{flex:1, justifyContent:'flex-start'}}>
|
||||
<TouchableOpacity onPress={this.back_onPress}>
|
||||
<View style={{ marginLeft:5, marginTop:5, borderRadius:90, width:50,height:50, display:'flex', backgroundColor:'#ffffff55', justifyContent:'center', alignItems:'center'}}>
|
||||
<Icon name={'md-arrow-back'} style={{
|
||||
fontSize: 40,
|
||||
color: 'black',
|
||||
}} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={{flex:1, justifyContent:'center', alignItems:'flex-end', flexDirection:'row'}}>
|
||||
<TouchableOpacity onPress={this.photo_onPress}>
|
||||
<View style={{marginBottom:20, borderRadius:90, width:90,height:90,backgroundColor:'#ffffffaa', display:'flex', justifyContent:'center', alignItems:'center'}}>
|
||||
<Icon name={photoIcon} style={{
|
||||
fontSize: 60,
|
||||
color: 'black',
|
||||
}} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</RNCamera>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = CameraView;
|
@@ -64,6 +64,11 @@ class NoteBodyViewer extends Component {
|
||||
return (safeGetNoteProp(this.props, 'body') + '').length !== (safeGetNoteProp(nextProps, 'body') + '').length;
|
||||
}
|
||||
|
||||
rebuildMd() {
|
||||
this.mdToHtml_.clearCache();
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const note = this.props.note;
|
||||
const style = this.props.style;
|
||||
|
@@ -22,6 +22,7 @@ const { Checkbox } = require('lib/components/checkbox.js');
|
||||
const { _ } = require('lib/locale.js');
|
||||
const { reg } = require('lib/registry.js');
|
||||
const { shim } = require('lib/shim.js');
|
||||
const ResourceFetcher = require('lib/services/ResourceFetcher');
|
||||
const { BaseScreenComponent } = require('lib/components/base-screen.js');
|
||||
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
|
||||
const { dialogs } = require('lib/dialogs.js');
|
||||
@@ -35,6 +36,7 @@ const ImagePicker = require('react-native-image-picker');
|
||||
const AlarmService = require('lib/services/AlarmService.js');
|
||||
const { SelectDateTimeDialog } = require('lib/components/select-date-time-dialog.js');
|
||||
const ShareExtension = require('react-native-share-extension').default;
|
||||
const CameraView = require('lib/components/CameraView');
|
||||
|
||||
import FileViewer from 'react-native-file-viewer';
|
||||
|
||||
@@ -59,6 +61,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
heightBumpView:0,
|
||||
noteTagDialogShown: false,
|
||||
fromShare: false,
|
||||
showCamera: false,
|
||||
};
|
||||
|
||||
// iOS doesn't support multiline text fields properly so disable it
|
||||
@@ -136,6 +139,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
}, 5);
|
||||
} else if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
||||
if (!Resource.isReady(item)) throw new Error(_('This attachment is not downloaded or not decrypted yet.'));
|
||||
const resourcePath = Resource.fullPath(item);
|
||||
await FileViewer.open(resourcePath);
|
||||
} else {
|
||||
@@ -148,6 +152,18 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
dialogs.error(this, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
this.resourceFetcher_downloadComplete = async (resource) => {
|
||||
if (!this.state.note || !this.state.note.body) return;
|
||||
const resourceIds = await Note.linkedResourceIds(this.state.note.body);
|
||||
if (resourceIds.indexOf(resource.id) >= 0) {
|
||||
this.refs.noteBodyViewer.rebuildMd();
|
||||
}
|
||||
}
|
||||
|
||||
this.attachPhoto_onPress = this.attachPhoto_onPress.bind(this);
|
||||
this.cameraView_onPhoto = this.cameraView_onPhoto.bind(this);
|
||||
this.cameraView_onCancel = this.cameraView_onCancel.bind(this);
|
||||
}
|
||||
|
||||
styles() {
|
||||
@@ -205,6 +221,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
BackButtonService.addHandler(this.backHandler);
|
||||
NavService.addHandler(this.navHandler);
|
||||
|
||||
ResourceFetcher.instance().on('downloadComplete', this.resourceFetcher_downloadComplete);
|
||||
|
||||
await shared.initState(this);
|
||||
|
||||
this.refreshNoteMetadata();
|
||||
@@ -218,6 +236,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
BackButtonService.removeHandler(this.backHandler);
|
||||
NavService.removeHandler(this.navHandler);
|
||||
|
||||
ResourceFetcher.instance().off('downloadComplete', this.resourceFetcher_downloadComplete);
|
||||
|
||||
if (Platform.OS !== 'ios' && this.state.fromShare) {
|
||||
ShareExtension.close();
|
||||
}
|
||||
@@ -321,7 +341,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
async attachFile(pickerResponse, fileType) {
|
||||
async attachFile(pickerResponse, fileType) {
|
||||
if (!pickerResponse) {
|
||||
reg.logger().warn('Got no response from picker');
|
||||
return;
|
||||
@@ -340,7 +360,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
const localFilePath = pickerResponse.uri;
|
||||
let mimeType = pickerResponse.type;
|
||||
|
||||
|
||||
if (!mimeType) {
|
||||
const ext = fileExtension(localFilePath);
|
||||
mimeType = mimeUtils.fromFileExtension(ext);
|
||||
@@ -362,7 +381,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
resource.id = uuid.create();
|
||||
resource.mime = mimeType;
|
||||
resource.title = pickerResponse.fileName ? pickerResponse.fileName : _('Untitled');
|
||||
resource.file_extension = safeFileExtension(fileExtension(pickerResponse.fileName));
|
||||
resource.file_extension = safeFileExtension(fileExtension(pickerResponse.fileName ? pickerResponse.fileName : localFilePath));
|
||||
|
||||
if (!resource.mime) resource.mime = 'application/octet-stream';
|
||||
|
||||
@@ -408,6 +427,25 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
await this.attachFile(response, 'image');
|
||||
}
|
||||
|
||||
attachPhoto_onPress() {
|
||||
this.setState({ showCamera: true });
|
||||
}
|
||||
|
||||
cameraView_onPhoto(data) {
|
||||
this.attachFile({
|
||||
uri: data.uri,
|
||||
didCancel: false,
|
||||
error: null,
|
||||
type: 'image/jpg',
|
||||
}, 'image');
|
||||
|
||||
this.setState({ showCamera: false });
|
||||
}
|
||||
|
||||
cameraView_onCancel() {
|
||||
this.setState({ showCamera: false });
|
||||
}
|
||||
|
||||
async attachFile_onPress() {
|
||||
const response = await this.pickDocument();
|
||||
await this.attachFile(response, 'all');
|
||||
@@ -463,6 +501,17 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
async showSource_onPress() {
|
||||
if (!this.state.note.id) return;
|
||||
|
||||
let note = await Note.load(this.state.note.id);
|
||||
try {
|
||||
Linking.openURL(note.source_url);
|
||||
} catch (error) {
|
||||
await dialogs.error(this, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
copyMarkdownLink_onPress() {
|
||||
const note = this.state.note;
|
||||
Clipboard.setString(Note.markdownTag(note));
|
||||
@@ -472,6 +521,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
const note = this.state.note;
|
||||
const isTodo = note && !!note.is_todo;
|
||||
const isSaved = note && note.id;
|
||||
const hasSource = note && note.source_url;
|
||||
|
||||
let output = [];
|
||||
|
||||
@@ -480,7 +530,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
let canAttachPicture = true;
|
||||
if (Platform.OS === 'android' && Platform.Version < 21) canAttachPicture = false;
|
||||
if (canAttachPicture) {
|
||||
output.push({ title: _('Attach photo'), onPress: () => { this.attachImage_onPress(); } });
|
||||
output.push({ title: _('Attach photo'), onPress: () => { this.attachPhoto_onPress(); } });
|
||||
output.push({ title: _('Attach any file'), onPress: () => { this.attachFile_onPress(); } });
|
||||
output.push({ isDivider: true });
|
||||
}
|
||||
@@ -496,6 +546,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
output.push({ isDivider: true });
|
||||
if (this.props.showAdvancedOptions) output.push({ title: this.state.showNoteMetadata ? _('Hide metadata') : _('Show metadata'), onPress: () => { this.showMetadata_onPress(); } });
|
||||
output.push({ title: _('View on map'), onPress: () => { this.showOnMap_onPress(); } });
|
||||
if (hasSource) output.push({ title: _('Go to source URL'), onPress: () => { this.showSource_onPress(); } });
|
||||
output.push({ isDivider: true });
|
||||
output.push({ title: _('Delete'), onPress: () => { this.deleteNote_onPress(); } });
|
||||
|
||||
@@ -528,6 +579,13 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
const folder = this.state.folder;
|
||||
const isNew = !note.id;
|
||||
|
||||
if (this.state.showCamera) {
|
||||
return <CameraView theme={this.props.theme} style={{flex:1}} onPhoto={this.cameraView_onPhoto} onCancel={this.cameraView_onCancel}/>
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let bodyComponent = null;
|
||||
if (this.state.mode == 'view') {
|
||||
const onCheckboxChange = (newBody) => {
|
||||
@@ -536,6 +594,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
bodyComponent = <NoteBodyViewer
|
||||
onJoplinLinkClick={this.onJoplinLinkClick_}
|
||||
ref="noteBodyViewer"
|
||||
style={this.styles().noteBodyViewer}
|
||||
webViewStyle={theme}
|
||||
note={note}
|
||||
|
@@ -397,7 +397,7 @@ class JoplinDatabase extends Database {
|
||||
}
|
||||
|
||||
if (targetVersion == 13) {
|
||||
queries.push('ALTER TABLE resources ADD COLUMN fetch_status INT NOT NULL DEFAULT "0"');
|
||||
queries.push('ALTER TABLE resources ADD COLUMN fetch_status INT NOT NULL DEFAULT "2"');
|
||||
queries.push('ALTER TABLE resources ADD COLUMN fetch_error TEXT NOT NULL DEFAULT ""');
|
||||
queries.push({ sql: 'UPDATE resources SET fetch_status = ?', params: [Resource.FETCH_STATUS_DONE] });
|
||||
}
|
||||
|
@@ -73,8 +73,12 @@ class Note extends BaseItem {
|
||||
}
|
||||
|
||||
static defaultTitle(note) {
|
||||
if (note.body && note.body.length) {
|
||||
const lines = note.body.trim().split("\n");
|
||||
return this.defaultTitleFromBody(note.body);
|
||||
}
|
||||
|
||||
static defaultTitleFromBody(body) {
|
||||
if (body && body.length) {
|
||||
const lines = body.trim().split("\n");
|
||||
let output = lines[0].trim();
|
||||
// Remove the first #, *, etc.
|
||||
while (output.length) {
|
||||
|
@@ -26,7 +26,7 @@ class Resource extends BaseItem {
|
||||
}
|
||||
|
||||
static isSupportedImageMimeType(type) {
|
||||
const imageMimeTypes = ["image/jpg", "image/jpeg", "image/png", "image/gif", "image/svg+xml"];
|
||||
const imageMimeTypes = ["image/jpg", "image/jpeg", "image/png", "image/gif", "image/svg+xml", "image/webp"];
|
||||
return imageMimeTypes.indexOf(type.toLowerCase()) >= 0;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class Resource extends BaseItem {
|
||||
const plainTextPath = this.fullPath(decryptedItem);
|
||||
const encryptedPath = this.fullPath(decryptedItem, true);
|
||||
const noExtPath = pathUtils.dirname(encryptedPath) + '/' + pathUtils.filename(encryptedPath);
|
||||
|
||||
|
||||
// When the resource blob is downloaded by the synchroniser, it's initially a file with no
|
||||
// extension (since it's encrypted, so we don't know its extension). So here rename it
|
||||
// to a file with a ".crypted" extension so that it's better identified, and then decrypt it.
|
||||
|
@@ -90,7 +90,7 @@ class Setting extends BaseModel {
|
||||
// Might be fixed in Electron 18.x but no non-beta release yet. So for now
|
||||
// by default we disable it on Linux.
|
||||
'showTrayIcon': { value: platform !== 'linux', type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Show tray icon'), description: () => {
|
||||
return platform === 'linux' ? _('Note: Does not work in all desktop environments.') : null;
|
||||
return platform === 'linux' ? _('Note: Does not work in all desktop environments.') : _('This will allow Joplin to run in the background. It is recommended to enable this setting so that your notes are constantly being synchronised, thus reducing the number of conflicts.');
|
||||
}},
|
||||
|
||||
'startMinimized': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Start application minimised in the tray icon') },
|
||||
|
@@ -7,6 +7,10 @@ shim.isNode = () => {
|
||||
};
|
||||
|
||||
shim.isReactNative = () => {
|
||||
if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('ReactNativeDebugger') >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !shim.isNode();
|
||||
};
|
||||
|
||||
@@ -14,6 +18,10 @@ shim.isLinux = () => {
|
||||
return process && process.platform === 'linux';
|
||||
}
|
||||
|
||||
shim.isFreeBSD = () => {
|
||||
return process && process.platform === 'freebsd';
|
||||
}
|
||||
|
||||
shim.isWindows = () => {
|
||||
return process && process.platform === 'win32';
|
||||
}
|
||||
@@ -27,6 +35,7 @@ shim.platformName = function() {
|
||||
if (shim.isMac()) return 'darwin';
|
||||
if (shim.isWindows()) return 'win32';
|
||||
if (shim.isLinux()) return 'linux';
|
||||
if (shim.isFreeBSD()) return 'freebsd';
|
||||
throw new Error('Cannot determine platform');
|
||||
}
|
||||
|
||||
@@ -141,4 +150,4 @@ shim.Buffer = null;
|
||||
shim.openUrl = () => { throw new Error('Not implemented'); }
|
||||
shim.waitForFrame = () => { throw new Error('Not implemented'); }
|
||||
|
||||
module.exports = { shim };
|
||||
module.exports = { shim };
|
||||
|
@@ -555,6 +555,8 @@ class Synchronizer {
|
||||
if (action == "createLocal") options.isNew = true;
|
||||
if (action == "updateLocal") options.oldItem = local;
|
||||
|
||||
const creatingNewResource = content.type_ == BaseModel.TYPE_RESOURCE && action == "createLocal";
|
||||
|
||||
// if (content.type_ == BaseModel.TYPE_RESOURCE && action == "createLocal") {
|
||||
// let localResourceContentPath = Resource.fullPath(content);
|
||||
// let remoteResourceContentPath = this.resourceDirName_ + "/" + content.id;
|
||||
@@ -571,11 +573,11 @@ class Synchronizer {
|
||||
// }
|
||||
// }
|
||||
|
||||
if (creatingNewResource) content.fetch_status = Resource.FETCH_STATUS_IDLE;
|
||||
|
||||
await ItemClass.save(content, options);
|
||||
|
||||
if (content.type_ == BaseModel.TYPE_RESOURCE && action == "createLocal") {
|
||||
this.dispatch({ type: "SYNC_CREATED_RESOURCE", id: content.id });
|
||||
}
|
||||
if (creatingNewResource) this.dispatch({ type: "SYNC_CREATED_RESOURCE", id: content.id });
|
||||
|
||||
if (!hasAutoEnabledEncryption && content.type_ === BaseModel.TYPE_MASTER_KEY && !masterKeysBefore) {
|
||||
hasAutoEnabledEncryption = true;
|
||||
|
@@ -14,6 +14,8 @@
|
||||
// require("ReactFeatureFlags").warnAboutDeprecatedLifecycles = false;
|
||||
|
||||
|
||||
// console.disableYellowBox = true
|
||||
|
||||
const { AppRegistry } = require('react-native');
|
||||
const { Root } = require('./root.js');
|
||||
|
||||
|
25
ReactNativeClient/package-lock.json
generated
25
ReactNativeClient/package-lock.json
generated
@@ -6539,6 +6539,31 @@
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"react-native-camera": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-1.3.0.tgz",
|
||||
"integrity": "sha512-f4Nev0dvJmWQPbXLYu4BF17agLWS6iQ+vanPlWkEaa4MAjbClD/YrQaR8w9vY+C472crSp3kRGHJXIQzSwgMpw==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.10",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
|
||||
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-datepicker": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-datepicker/-/react-native-datepicker-1.6.0.tgz",
|
||||
|
@@ -26,6 +26,7 @@
|
||||
"react": "^16.5.0",
|
||||
"react-native": "^0.57.1",
|
||||
"react-native-action-button": "^2.6.9",
|
||||
"react-native-camera": "^1.3.0",
|
||||
"react-native-datepicker": "^1.6.0",
|
||||
"react-native-dialogbox": "^0.6.6",
|
||||
"react-native-document-picker": "^2.1.0",
|
||||
|
@@ -542,16 +542,32 @@ class AppComponent extends React.Component {
|
||||
try {
|
||||
const { type, value } = await ShareExtension.data();
|
||||
|
||||
if (type != "" && this.props.selectedFolderId) {
|
||||
// reg.logger().info('Got share data:', type, value);
|
||||
|
||||
this.props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Note',
|
||||
noteId: null,
|
||||
sharedData: {type: type, value: value},
|
||||
folderId: this.props.selectedFolderId,
|
||||
itemType: 'note',
|
||||
if (type != "" && this.props.selectedFolderId) {
|
||||
const newNote = await Note.save({
|
||||
title: Note.defaultTitleFromBody(value),
|
||||
body: value,
|
||||
parent_id: this.props.selectedFolderId
|
||||
});
|
||||
|
||||
// This is a bit hacky, but the surest way to go to
|
||||
// the needed note. We go back one screen in case there's
|
||||
// already a note open - if we don't do this, the dispatch
|
||||
// below will do nothing (because routeName wouldn't change)
|
||||
// Then we wait a bit for the state to be set correctly, and
|
||||
// finally we go to the new note.
|
||||
this.props.dispatch({
|
||||
type: 'NAV_BACK',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Note',
|
||||
noteId: newNote.id,
|
||||
});
|
||||
}, 5);
|
||||
}
|
||||
|
||||
} catch(e) {
|
||||
|
0
ReactNativeClient/start_server.sh
Normal file → Executable file
0
ReactNativeClient/start_server.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
const fs = require('fs-extra');
|
||||
const { execCommand, githubRelease, githubOauthToken } = require('./tool-utils.js');
|
||||
const { execCommand, githubRelease, githubOauthToken, isWindows, fileExists } = require('./tool-utils.js');
|
||||
const path = require('path');
|
||||
const fetch = require('node-fetch');
|
||||
const uriTemplate = require('uri-template');
|
||||
@@ -60,9 +60,23 @@ async function main() {
|
||||
console.info('Running from: ' + process.cwd());
|
||||
|
||||
console.info('Building APK file...');
|
||||
const output = await execCommand('/mnt/c/Windows/System32/cmd.exe /c "cd ReactNativeClient\\android && gradlew.bat assembleRelease -PbuildDir=build --console plain"');
|
||||
|
||||
let restoreDir = null;
|
||||
let apkBuildCmd = 'assembleRelease -PbuildDir=build --console plain';
|
||||
if (await fileExists('/mnt/c/Windows/System32/cmd.exe')) {
|
||||
apkBuildCmd = '/mnt/c/Windows/System32/cmd.exe /c "cd ReactNativeClient\\android && gradlew.bat ' + apkBuildCmd + '"';
|
||||
} else {
|
||||
process.chdir(rnDir + '/android');
|
||||
apkBuildCmd = './gradlew ' + apkBuildCmd;
|
||||
restoreDir = rootDir;
|
||||
}
|
||||
|
||||
// const output = await execCommand('/mnt/c/Windows/System32/cmd.exe /c "cd ReactNativeClient\\android && gradlew.bat assembleRelease -PbuildDir=build --console plain"');
|
||||
const output = await execCommand(apkBuildCmd);
|
||||
console.info(output);
|
||||
|
||||
if (restoreDir) process.chdir(restoreDir);
|
||||
|
||||
await fs.mkdirp(releaseDir);
|
||||
|
||||
console.info('Copying APK to ' + apkFilePath);
|
||||
|
@@ -68,6 +68,8 @@ toolUtils.unlinkForce = async function(filePath) {
|
||||
}
|
||||
|
||||
toolUtils.fileExists = async function(filePath) {
|
||||
const fs = require('fs-extra');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(filePath, function(err, stat) {
|
||||
if (err == null) {
|
||||
@@ -115,4 +117,16 @@ toolUtils.githubRelease = async function(project, tagName, isDraft) {
|
||||
return responseJson;
|
||||
}
|
||||
|
||||
toolUtils.isLinux = () => {
|
||||
return process && process.platform === 'linux';
|
||||
}
|
||||
|
||||
toolUtils.isWindows = () => {
|
||||
return process && process.platform === 'win32';
|
||||
}
|
||||
|
||||
toolUtils.isMac = () => {
|
||||
return process && process.platform === 'darwin';
|
||||
}
|
||||
|
||||
module.exports = toolUtils;
|
@@ -251,6 +251,22 @@
|
||||
</ul>
|
||||
</div>
|
||||
<h1 id="joplin-changelog">Joplin changelog</h1>
|
||||
<h2 id="-v1-0-114-https-github-com-laurent22-joplin-releases-tag-v1-0-114-2018-10-24t20-14-10z"><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.114">v1.0.114</a> - 2018-10-24T20:14:10Z</h2>
|
||||
<ul>
|
||||
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/832">#832</a>: Enex import: Don't add extra line breaks at the beginning of list item when it contains a block element</li>
|
||||
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/798">#798</a>: Enable Select All shortcut in macOS</li>
|
||||
<li>API: Fixed handling of PUT method and log errors to file</li>
|
||||
<li>Api: Fixes <a href="https://github.com/laurent22/joplin/issues/843">#843</a>: Fixed regression that was preventing resource metadata from being downloaded</li>
|
||||
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/847">#847</a>: Prevent view from scrolling to top when clicking checkbox and editor not visible</li>
|
||||
<li>Resolves <a href="https://github.com/laurent22/joplin/issues/751">#751</a>: Allow switching between todo and note when multiple notes are selected</li>
|
||||
<li>Fixed potential crash that can happen if editor is not ready</li>
|
||||
<li>Prevent URLs added via A tag from being opened inside app</li>
|
||||
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/853">#853</a>: Replace characters to equivalent US-ASCII ones when exporting files</li>
|
||||
<li>Improved the way resources are loaded to prepare to allow making downloading resources optional, and to make sync faster</li>
|
||||
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/312">#312</a> (maybe): Removed power saving feature, which wasn\'t doing anything and added a possible fix to the UI freezing issue on Linux</li>
|
||||
<li>Improved: Handle internal anchors</li>
|
||||
<li>Improved Linux install script</li>
|
||||
</ul>
|
||||
<h2 id="-v1-0-111-https-github-com-laurent22-joplin-releases-tag-v1-0-111-2018-09-30t20-15-09z"><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.111">v1.0.111</a> - 2018-09-30T20:15:09Z</h2>
|
||||
<p>This is mainly a release to fix a bug related to the new IMG tag support.</p>
|
||||
<ul>
|
||||
@@ -496,12 +512,6 @@
|
||||
<li>Fixed: <a href="https://github.com/laurent22/joplin/issues/241">#241</a>: Ignore response for certain WebDAV calls to improve compatibility with some services.</li>
|
||||
<li>Updated: French and Español translation</li>
|
||||
</ul>
|
||||
<h2 id="-v1-0-66-https-github-com-laurent22-joplin-releases-tag-v1-0-66-2018-02-18t23-09-09z"><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.66">v1.0.66</a> - 2018-02-18T23:09:09Z</h2>
|
||||
<ul>
|
||||
<li>Fixed: Local items were no longer being deleted via sync.</li>
|
||||
<li>Improved: More debug information when WebDAV sync target does not work.</li>
|
||||
<li>Improved: Compatibility with some WebDAV services (Seafile in particular)</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
function stickyHeader() {
|
||||
|
@@ -279,17 +279,17 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Windows (32 and 64-bit)</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/Joplin-Setup-1.0.111.exe'><img alt='Get it on Windows' height="40px" src='https://joplin.cozic.net/images/BadgeWindows.png'/></a></td>
|
||||
<td>or Get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/JoplinPortable.exe'>Portable version</a><br>(to run from a USB key, etc.)</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/Joplin-Setup-1.0.114.exe'><img alt='Get it on Windows' height="40px" src='https://joplin.cozic.net/images/BadgeWindows.png'/></a></td>
|
||||
<td>or Get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/JoplinPortable.exe'>Portable version</a><br>(to run from a USB key, etc.)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>macOS</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/Joplin-1.0.111.dmg'><img alt='Get it on macOS' height="40px" src='https://joplin.cozic.net/images/BadgeMacOS.png'/></a></td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/Joplin-1.0.114.dmg'><img alt='Get it on macOS' height="40px" src='https://joplin.cozic.net/images/BadgeMacOS.png'/></a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.111/Joplin-1.0.111-x86_64.AppImage'><img alt='Get it on Linux' height="40px" src='https://joplin.cozic.net/images/BadgeLinux.png'/></a></td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.114/Joplin-1.0.114-x86_64.AppImage'><img alt='Get it on Linux' height="40px" src='https://joplin.cozic.net/images/BadgeLinux.png'/></a></td>
|
||||
<td>An Arch Linux package<br><a href="#terminal-application">is also available</a>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -311,7 +311,7 @@
|
||||
<tr>
|
||||
<td>Android</td>
|
||||
<td><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://joplin.cozic.net/images/BadgeAndroid.png'/></a></td>
|
||||
<td>or <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.0.142/joplin-v1.0.142.apk">Download APK File</a></td>
|
||||
<td>or <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.0.175/joplin-v1.0.175.apk">Download APK File</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>iOS</td>
|
||||
@@ -404,7 +404,7 @@
|
||||
:config sync.target 5
|
||||
</code></pre><p>If synchronisation does not work, please consult the logs in the app profile directory - it is often due to a misconfigured URL or password. The log should indicate what the exact issue is.</p>
|
||||
<h2 id="dropbox-synchronisation">Dropbox synchronisation</h2>
|
||||
<p>When syncing with Dropbox, Joplin creates a sub-directory in Dropbox, in /Apps/Joplin and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.</p>
|
||||
<p>When syncing with Dropbox, Joplin creates a sub-directory in Dropbox, in <code>/Apps/Joplin</code> and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.</p>
|
||||
<p>On the <strong>desktop application</strong> or <strong>mobile application</strong>, select "Dropbox" as the synchronisation target in the config screen (it is selected by default). Then, to initiate the synchronisation process, click on the "Synchronise" button in the sidebar and follow the instructions.</p>
|
||||
<p>On the <strong>terminal application</strong>, to initiate the synchronisation process, type <code>:sync</code>. You will be asked to follow a link to authorise the application. It is possible to also synchronise outside of the user interface by typing <code>joplin sync</code> from the terminal. This can be used to setup a cron script to synchronise at regular interval. For example, this would do it every 30 minutes:</p>
|
||||
<pre><code>*/30 * * * * /path/to/joplin sync
|
||||
@@ -417,6 +417,7 @@
|
||||
<li><a href="https://www.fastmail.com/">Fastmail</a></li>
|
||||
<li><a href="https://www.strato.fr/stockage-en-ligne/">HiDrive</a> from Strato. <a href="https://github.com/laurent22/joplin/issues/309">Setup help</a></li>
|
||||
<li><a href="https://nginx.org/en/docs/http/ngx_http_dav_module.html">Nginx WebDAV Module</a></li>
|
||||
<li><a href="https://nextcloud.com/">NextCloud</a></li>
|
||||
<li><a href="https://owncloud.org/">OwnCloud</a></li>
|
||||
<li><a href="https://www.seafile.com/">Seafile</a></li>
|
||||
<li><a href="https://www.transip.nl/stack/">Stack</a></li>
|
||||
@@ -459,7 +460,7 @@
|
||||
<pre><code>[Link to my note](:/0b0d62d15e60409dac34f354b6e9e839)
|
||||
</code></pre><p>Since getting the ID of a note is not straightforward, each app provides a way to create such link. In the <strong>desktop app</strong>, right click on a note an select "Copy Markdown link". In the <strong>mobile app</strong>, open a note and, in the top right menu, select "Copy Markdown link". You can then paste this link anywhere in another note.</p>
|
||||
<h2 id="math-notation">Math notation</h2>
|
||||
<p>Math expressions can be added using the <a href="https://khan.github.io/KaTeX/">Katex notation</a>. To add an inline equation, wrap the expression in <code>$EXPRESSION$</code>, eg. <code>$\sqrt{3x-1}+(1+x)^2$</code>. To create an expression block, wrap it as follow:</p>
|
||||
<p>Math expressions can be added using the <a href="https://khan.github.io/KaTeX/">KaTeX notation</a>. To add an inline equation, wrap the expression in <code>$EXPRESSION$</code>, eg. <code>$\sqrt{3x-1}+(1+x)^2$</code>. To create an expression block, wrap it as follow:</p>
|
||||
<pre><code>$$
|
||||
EXPRESSION
|
||||
$$
|
||||
|
@@ -261,23 +261,23 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Windows downloads</td>
|
||||
<td>60940</td>
|
||||
<td>72838</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total macOs downloads</td>
|
||||
<td>24311</td>
|
||||
<td>27452</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Linux downloads</td>
|
||||
<td>21700</td>
|
||||
<td>25291</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows %</td>
|
||||
<td>57%</td>
|
||||
<td>58%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>macOS %</td>
|
||||
<td>23%</td>
|
||||
<td>22%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux %</td>
|
||||
@@ -298,28 +298,36 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.114">v1.0.114</a></td>
|
||||
<td>2018-10-24T20:14:10Z</td>
|
||||
<td></td>
|
||||
<td>2</td>
|
||||
<td></td>
|
||||
<td>2 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.111">v1.0.111</a></td>
|
||||
<td>2018-09-30T20:15:09Z</td>
|
||||
<td>1</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>1 </td>
|
||||
<td>11714</td>
|
||||
<td>3080</td>
|
||||
<td>3627</td>
|
||||
<td>18421</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.110">v1.0.110</a></td>
|
||||
<td>2018-09-29T12:29:21Z</td>
|
||||
<td>782</td>
|
||||
<td>243</td>
|
||||
<td>95</td>
|
||||
<td>1120</td>
|
||||
<td>919</td>
|
||||
<td>368</td>
|
||||
<td>99</td>
|
||||
<td>1386</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.109">v1.0.109</a></td>
|
||||
<td>2018-09-27T18:01:41Z</td>
|
||||
<td>1939</td>
|
||||
<td>653</td>
|
||||
<td>304</td>
|
||||
<td>2896</td>
|
||||
<td>2063</td>
|
||||
<td>672</td>
|
||||
<td>307</td>
|
||||
<td>3042</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.108">v1.0.108</a></td>
|
||||
@@ -332,58 +340,58 @@
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.107">v1.0.107</a></td>
|
||||
<td>2018-09-16T19:51:07Z</td>
|
||||
<td>6888</td>
|
||||
<td>2103</td>
|
||||
<td>1688</td>
|
||||
<td>10679</td>
|
||||
<td>7098</td>
|
||||
<td>2108</td>
|
||||
<td>1694</td>
|
||||
<td>10900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.106">v1.0.106</a></td>
|
||||
<td>2018-09-08T15:23:40Z</td>
|
||||
<td>4499</td>
|
||||
<td>4501</td>
|
||||
<td>1435</td>
|
||||
<td>285</td>
|
||||
<td>6219</td>
|
||||
<td>288</td>
|
||||
<td>6224</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.105">v1.0.105</a></td>
|
||||
<td>2018-09-05T11:29:36Z</td>
|
||||
<td>4552</td>
|
||||
<td>1544</td>
|
||||
<td>1426</td>
|
||||
<td>7522</td>
|
||||
<td>4555</td>
|
||||
<td>1549</td>
|
||||
<td>1427</td>
|
||||
<td>7531</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.104">v1.0.104</a></td>
|
||||
<td>2018-06-28T20:25:36Z</td>
|
||||
<td>14943</td>
|
||||
<td>14947</td>
|
||||
<td>4649</td>
|
||||
<td>6882</td>
|
||||
<td>26474</td>
|
||||
<td>6893</td>
|
||||
<td>26489</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.103">v1.0.103</a></td>
|
||||
<td>2018-06-21T19:38:13Z</td>
|
||||
<td>2001</td>
|
||||
<td>852</td>
|
||||
<td>854</td>
|
||||
<td>664</td>
|
||||
<td>3517</td>
|
||||
<td>3519</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.101">v1.0.101</a></td>
|
||||
<td>2018-06-17T18:35:11Z</td>
|
||||
<td>1283</td>
|
||||
<td>1284</td>
|
||||
<td>577</td>
|
||||
<td>397</td>
|
||||
<td>2257</td>
|
||||
<td>2258</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.100">v1.0.100</a></td>
|
||||
<td>2018-06-14T17:41:43Z</td>
|
||||
<td>848</td>
|
||||
<td>405</td>
|
||||
<td>849</td>
|
||||
<td>406</td>
|
||||
<td>226</td>
|
||||
<td>1479</td>
|
||||
<td>1481</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.99">v1.0.99</a></td>
|
||||
@@ -396,18 +404,18 @@
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.97">v1.0.97</a></td>
|
||||
<td>2018-06-09T19:23:34Z</td>
|
||||
<td>290</td>
|
||||
<td>291</td>
|
||||
<td>131</td>
|
||||
<td>51</td>
|
||||
<td>472</td>
|
||||
<td>473</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.96">v1.0.96</a></td>
|
||||
<td>2018-05-26T16:36:39Z</td>
|
||||
<td>2671</td>
|
||||
<td>1194</td>
|
||||
<td>1152</td>
|
||||
<td>5017</td>
|
||||
<td>1159</td>
|
||||
<td>5024</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.95">v1.0.95</a></td>
|
||||
@@ -429,9 +437,9 @@
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.93">v1.0.93</a></td>
|
||||
<td>2018-05-14T11:36:01Z</td>
|
||||
<td>1766</td>
|
||||
<td>847</td>
|
||||
<td>853</td>
|
||||
<td>738</td>
|
||||
<td>3351</td>
|
||||
<td>3357</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.91">v1.0.91</a></td>
|
||||
@@ -460,18 +468,18 @@
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.83">v1.0.83</a></td>
|
||||
<td>2018-04-04T19:43:58Z</td>
|
||||
<td>4442</td>
|
||||
<td>2378</td>
|
||||
<td>4454</td>
|
||||
<td>2381</td>
|
||||
<td>2627</td>
|
||||
<td>9447</td>
|
||||
<td>9462</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.82">v1.0.82</a></td>
|
||||
<td>2018-03-31T19:16:31Z</td>
|
||||
<td>684</td>
|
||||
<td>383</td>
|
||||
<td>92</td>
|
||||
<td>1159</td>
|
||||
<td>93</td>
|
||||
<td>1160</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.81">v1.0.81</a></td>
|
||||
@@ -524,18 +532,10 @@
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.67">v1.0.67</a></td>
|
||||
<td>2018-02-19T22:51:08Z</td>
|
||||
<td>1802</td>
|
||||
<td>1805</td>
|
||||
<td>579</td>
|
||||
<td></td>
|
||||
<td>2381</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.66">v1.0.66</a></td>
|
||||
<td>2018-02-18T23:09:09Z</td>
|
||||
<td>313</td>
|
||||
<td>107</td>
|
||||
<td>72</td>
|
||||
<td>492</td>
|
||||
<td>2384</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -1,5 +1,21 @@
|
||||
# Joplin changelog
|
||||
|
||||
## [v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) - 2018-10-24T20:14:10Z
|
||||
|
||||
- Fixes [#832](https://github.com/laurent22/joplin/issues/832): Enex import: Don't add extra line breaks at the beginning of list item when it contains a block element
|
||||
- Fixes [#798](https://github.com/laurent22/joplin/issues/798): Enable Select All shortcut in macOS
|
||||
- API: Fixed handling of PUT method and log errors to file
|
||||
- Api: Fixes [#843](https://github.com/laurent22/joplin/issues/843): Fixed regression that was preventing resource metadata from being downloaded
|
||||
- Fixes [#847](https://github.com/laurent22/joplin/issues/847): Prevent view from scrolling to top when clicking checkbox and editor not visible
|
||||
- Resolves [#751](https://github.com/laurent22/joplin/issues/751): Allow switching between todo and note when multiple notes are selected
|
||||
- Fixed potential crash that can happen if editor is not ready
|
||||
- Prevent URLs added via A tag from being opened inside app
|
||||
- Fixes [#853](https://github.com/laurent22/joplin/issues/853): Replace characters to equivalent US-ASCII ones when exporting files
|
||||
- Improved the way resources are loaded to prepare to allow making downloading resources optional, and to make sync faster
|
||||
- Fixes [#312](https://github.com/laurent22/joplin/issues/312) (maybe): Removed power saving feature, which wasn\'t doing anything and added a possible fix to the UI freezing issue on Linux
|
||||
- Improved: Handle internal anchors
|
||||
- Improved Linux install script
|
||||
|
||||
## [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) - 2018-09-30T20:15:09Z
|
||||
|
||||
This is mainly a release to fix a bug related to the new IMG tag support.
|
||||
@@ -257,10 +273,4 @@ Note: This fixes an invalid database upgrade in the previous version.
|
||||
- Fixed: [#217](https://github.com/laurent22/joplin/issues/217): Display a message when the note has no content and only the note viewer is visible
|
||||
- Fixed: [#240](https://github.com/laurent22/joplin/issues/240): Tags should be handled in a case-insensitive way
|
||||
- Fixed: [#241](https://github.com/laurent22/joplin/issues/241): Ignore response for certain WebDAV calls to improve compatibility with some services.
|
||||
- Updated: French and Español translation
|
||||
|
||||
## [v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) - 2018-02-18T23:09:09Z
|
||||
|
||||
- Fixed: Local items were no longer being deleted via sync.
|
||||
- Improved: More debug information when WebDAV sync target does not work.
|
||||
- Improved: Compatibility with some WebDAV services (Seafile in particular)
|
||||
- Updated: French and Español translation
|
@@ -2,42 +2,42 @@
|
||||
|
||||
Name | Value
|
||||
--- | ---
|
||||
Total Windows downloads | 60940
|
||||
Total macOs downloads | 24311
|
||||
Total Linux downloads | 21700
|
||||
Windows % | 57%
|
||||
macOS % | 23%
|
||||
Total Windows downloads | 72838
|
||||
Total macOs downloads | 27452
|
||||
Total Linux downloads | 25291
|
||||
Windows % | 58%
|
||||
macOS % | 22%
|
||||
Linux % | 20%
|
||||
|
||||
Version | Date | Windows | macOS | Linux | Total
|
||||
--- | --- | --- | --- | --- | ---
|
||||
[v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 1 | | | 1
|
||||
[v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 782 | 243 | 95 | 1120
|
||||
[v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 1939 | 653 | 304 | 2896
|
||||
[v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | | 2 | | 2
|
||||
[v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 11714 | 3080 | 3627 | 18421
|
||||
[v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 919 | 368 | 99 | 1386
|
||||
[v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 2063 | 672 | 307 | 3042
|
||||
[v1.0.108](https://github.com/laurent22/joplin/releases/tag/v1.0.108) | 2018-09-29T18:49:29Z | 4 | | | 4
|
||||
[v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 6888 | 2103 | 1688 | 10679
|
||||
[v1.0.106](https://github.com/laurent22/joplin/releases/tag/v1.0.106) | 2018-09-08T15:23:40Z | 4499 | 1435 | 285 | 6219
|
||||
[v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4552 | 1544 | 1426 | 7522
|
||||
[v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 14943 | 4649 | 6882 | 26474
|
||||
[v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2001 | 852 | 664 | 3517
|
||||
[v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1283 | 577 | 397 | 2257
|
||||
[v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 848 | 405 | 226 | 1479
|
||||
[v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 7098 | 2108 | 1694 | 10900
|
||||
[v1.0.106](https://github.com/laurent22/joplin/releases/tag/v1.0.106) | 2018-09-08T15:23:40Z | 4501 | 1435 | 288 | 6224
|
||||
[v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4555 | 1549 | 1427 | 7531
|
||||
[v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 14947 | 4649 | 6893 | 26489
|
||||
[v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2001 | 854 | 664 | 3519
|
||||
[v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1284 | 577 | 397 | 2258
|
||||
[v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 849 | 406 | 226 | 1481
|
||||
[v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1228 | 575 | 370 | 2173
|
||||
[v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 290 | 131 | 51 | 472
|
||||
[v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2671 | 1194 | 1152 | 5017
|
||||
[v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 291 | 131 | 51 | 473
|
||||
[v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2671 | 1194 | 1159 | 5024
|
||||
[v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 381 | 186 | 81 | 648
|
||||
[v1.0.94](https://github.com/laurent22/joplin/releases/tag/v1.0.94) | 2018-05-21T20:52:59Z | 1094 | 553 | 354 | 2001
|
||||
[v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1766 | 847 | 738 | 3351
|
||||
[v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1766 | 853 | 738 | 3357
|
||||
[v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 812 | 531 | 286 | 1629
|
||||
[v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) | 2018-05-09T13:05:05Z | 469 | 206 | 90 | 765
|
||||
[v1.0.85](https://github.com/laurent22/joplin/releases/tag/v1.0.85) | 2018-05-01T21:08:24Z | 1638 | 929 | 607 | 3174
|
||||
[v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 4442 | 2378 | 2627 | 9447
|
||||
[v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 684 | 383 | 92 | 1159
|
||||
[v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 4454 | 2381 | 2627 | 9462
|
||||
[v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 684 | 383 | 93 | 1160
|
||||
[v1.0.81](https://github.com/laurent22/joplin/releases/tag/v1.0.81) | 2018-03-28T08:13:58Z | 984 | 565 | 742 | 2291
|
||||
[v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 919 | 509 | 353 | 1781
|
||||
[v1.0.78](https://github.com/laurent22/joplin/releases/tag/v1.0.78) | 2018-03-17T15:27:18Z | 1302 | 836 | 841 | 2979
|
||||
[v1.0.77](https://github.com/laurent22/joplin/releases/tag/v1.0.77) | 2018-03-16T15:12:35Z | 165 | 87 | 25 | 277
|
||||
[v1.0.72](https://github.com/laurent22/joplin/releases/tag/v1.0.72) | 2018-03-14T09:44:35Z | 396 | 232 | 32 | 660
|
||||
[v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 1844 | 1022 | 1220 | 4086
|
||||
[v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1802 | 579 | | 2381
|
||||
[v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) | 2018-02-18T23:09:09Z | 313 | 107 | 72 | 492
|
||||
[v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1805 | 579 | | 2384
|
Reference in New Issue
Block a user