1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-02 20:46:21 +02:00

Compare commits

...

33 Commits

Author SHA1 Message Date
Laurent Cozic
85bf89fd97 Android release v1.0.279 2019-07-12 19:44:23 +01:00
Laurent Cozic
c2a80b12f0 Mobile: More rendering optimisations to make animations smoother and to allow typing fast on large notes 2019-07-12 19:36:12 +01:00
Laurent Cozic
981c97cca5 Mobile: Optimising screen rendering to make text input faster 2019-07-12 18:32:08 +01:00
Laurent Cozic
091cbc5355 Mobile: Added sync button animation; Added notebook header; Improved layout of Edit Notebook screen 2019-07-12 18:07:47 +01:00
Laurent Cozic
e5a8114887 Mobile: Added icons to left sidebar 2019-07-11 18:44:26 +01:00
Laurent Cozic
4779fc6f43 Mobile: Remove search and side menu button from config screen 2019-07-11 18:26:04 +01:00
Laurent Cozic
86e7daaec4 Mobile: Cleaned context menu and moved options and metadata to side menu bar 2019-07-11 18:23:29 +01:00
Laurent Cozic
cab73a26e7 Mobile: Adding note side menu 2019-07-11 17:43:55 +01:00
Laurent Cozic
554ddb3b51 Mobile: Grouped file attachment action under one menu 2019-07-11 17:41:13 +01:00
Laurent Cozic
3b22bdb8ae Doc: Fixed Linux install command line for website 2019-07-10 18:18:31 +01:00
Laurent Cozic
5fdd07679e All: Fix: Only log master key ID 2019-07-10 17:35:08 +01:00
Laurent Cozic
69f75a1520 Doc: Updated old links 2019-07-10 17:00:10 +01:00
Laurent Cozic
f9b7acb8b1 Merge branch 'master' of github.com:laurent22/joplin 2019-07-10 16:41:20 +01:00
Laurent Cozic
91f700ad54 Doc: Updated email addresses 2019-07-10 16:41:13 +01:00
Robert
966aca7753 Update nl_NL.po (#1709)
* Update nl_NL.po

* Added ampersands to main menu items 

for the nl-nl translation
2019-07-05 13:00:53 -04:00
Helmut K. C. Tessarek
4de8816ed5 Merge pull request #1710 from Marmo/Marmo-translation-20190705
Translation: minor fixes (de_DE)
2019-07-05 11:26:32 -04:00
Marmo
bea68a1056 Minor translation fixes (de_DE) 2019-07-05 13:54:11 +02:00
Laurent Cozic
6fea7116b6 Mobile: Removed now unneeded Welcome screen 2019-06-29 00:24:00 +01:00
Laurent Cozic
2955914ca5 Mobile: Fixes #1690 (maybe): Process less data simultaneously when building search index to prevent out of memory errors 2019-06-28 23:49:43 +01:00
Laurent Cozic
fd150b5b9d Update website 2019-06-28 16:08:50 +01:00
Laurent Cozic
334ffad196 Doc: Added link to Mastodon feed 2019-06-28 16:04:05 +01:00
Charles
a796a9d179 API: Support is_todo property to allow making a note a todo (#1688) 2019-06-28 13:46:55 +01:00
Helmut K. C. Tessarek
917dcea28a use a command to get the current branch that works with older git versions
closes #1695
2019-06-28 05:02:21 -04:00
Laurent Cozic
c901228dc5 Merge branch 'master' of github.com:laurent22/joplin 2019-06-28 00:51:14 +01:00
Laurent Cozic
da21580785 Mobile: Added 'All notes' screen; Cleaned up header bar buttons; Removed 'body' from note preview object to improve memory usage 2019-06-28 00:51:02 +01:00
Laurent Cozic
4d92187327 Mobile: Added button to fix search engine index 2019-06-28 00:48:52 +01:00
Helmut K. C. Tessarek
207d433fb3 Desktop: Improved: Show git branch and hash in About dialog (#1692)
* show git branch and hash in About dialog

This additional info will only be shown, if the code is not an official release.

An official release is calculated as follows:
- current commit has a tag
- the tag contains the version number of the package

However, the information will always be printed to the console.

* info will now always be shown in About dialog (if available)

ElectronClient/app/compile-package-info.js: added warning
ElectronClient/app/app.js: push info conditionally to the message array

* use sprintf syntax
2019-06-27 15:04:02 +01:00
Laurent Cozic
ffc311d7bd Mobile: Moved slider value to the left so that it is visible while dragging 2019-06-27 00:05:17 +01:00
Laurent Cozic
a1e8e71359 Mobile: Added auto-save 2019-06-26 23:26:26 +01:00
Laurent Cozic
7942e74dc6 Mobile: Fixed field focus logic 2019-06-26 23:21:12 +01:00
Laurent Cozic
c4e21c2b6a Mobile: Added placeholders for note title and body, and focus body by default for notes 2019-06-26 23:00:25 +01:00
Laurent Cozic
0a06aa6f9f Mobile: When inside a note, do not show side menu and search buttons 2019-06-26 22:54:09 +01:00
Laurent Cozic
f985cfa25c Mobile: Removed arrow icon as it is rendered weirdly on device 2019-06-26 18:51:12 +01:00
37 changed files with 905 additions and 553 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 986 B

BIN
Assets/AdresseSupport.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@@ -597,7 +597,7 @@ msgstr ""
#, javascript-format
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportiere „%s“ ins „%s“ Format. Bitte warten..."
msgstr "Exportiere „%s“ ins „%s“-Format. Bitte warten..."
msgid "Sidebar"
msgstr "Seitenleiste"
@@ -606,14 +606,14 @@ msgid "Note list"
msgstr "Notizen-Liste"
msgid "Note title"
msgstr "Notiz Titel"
msgstr "Notiz-Titel"
msgid "Note body"
msgstr "Notiz Text"
msgstr "Notiz-Text"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importiere „%s“ ins „%s“ Format. Bitte warten..."
msgstr "Importiere „%s“ als „%s“-Format. Bitte warten..."
msgid "PDF File"
msgstr "PDF-Datei"

View File

@@ -13,8 +13,10 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.1.1\n"
"X-Generator: Poedit 2.2.3\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 ""
@@ -127,13 +129,12 @@ msgstr "Markeert een taak als afgerond."
msgid "Note is not a to-do: \"%s\""
msgstr "Notitie is geen taak: \"%s\""
#, fuzzy
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status`, `decrypt-file` and `target-status`."
msgstr ""
"Beheert de E2EE-configuratie. Opdrachten zijn: `enable`, `disable`, "
"`decrypt`, `status` en `target-status`."
"`decrypt`, `status`, `decrypt-file` en `target-status`."
msgid "Enter master password:"
msgstr "Voer het hoofdwachtwoord in:"
@@ -260,13 +261,13 @@ msgid "To enter command line mode, press \":\""
msgstr "Druk op \":\" om de opdrachtregelmodus te starten."
msgid "To exit command line mode, press ESCAPE"
msgstr "Druk op Esc om de opdrachtregelmodus af te sluiten."
msgstr "Druk op Esc om de opdrachtregelmodus af te sluiten"
msgid ""
"For the list of keyboard shortcuts and config options, type `help keymap`"
msgstr ""
"Typ `help keymap` om de lijst met sneltoetsen en configuratie-opties te "
"bekijken."
"bekijken"
msgid "Imports data into Joplin."
msgstr "Importeert gegeven naar Joplin."
@@ -459,21 +460,20 @@ msgid "Starting synchronisation..."
msgstr "Bezig met starten van synchronisatie..."
msgid "Downloading resources..."
msgstr ""
msgstr "Resources downloaden…"
msgid "Cancelling... Please wait."
msgstr "Bezig met annuleren... Even geduld."
#, fuzzy
msgid ""
"<tag-command> can be \"add\", \"remove\" or \"list\" to assign or remove "
"[tag] from [note], or to list the notes associated with [tag]. The command "
"`tag list` can be used to list all the tags (use -l for long option)."
msgstr ""
"<tag-command> kan zijn \"add\", \"remove\" of \"list\" om [tag] toe te "
"<tag-command> kan \"add\", \"remove\" of \"list\" zijn om [tag] toe te "
"wijzen aan of te verwijderen uit [note] of om de met [tag] geassocieerde "
"notities op te sommen. De opdracht `tag list` kan worden gebruikt om alle "
"labels op te sommen."
"labels op te sommen (gebruik “-l” voor “long” optie)."
#, javascript-format
msgid "Invalid command: \"%s\""
@@ -587,18 +587,16 @@ msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Bezig met exporteren van \"%s\" in het formaat \"%s\". Even geduld..."
msgid "Sidebar"
msgstr ""
msgstr "Zijbalk"
msgid "Note list"
msgstr ""
msgstr "Notitielijst"
#, fuzzy
msgid "Note title"
msgstr "Titel van notitieboek:"
msgstr "Titel van notitie"
#, fuzzy
msgid "Note body"
msgstr "Notitieboeken"
msgstr "Inhoud van notitie"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
@@ -635,15 +633,14 @@ msgstr "Webclipper-opties"
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Bestand"
msgstr "&Bestand"
msgid "About Joplin"
msgstr "Over Joplin"
msgid "Preferences..."
msgstr ""
msgstr "Voorkeuren…"
msgid "Check for updates..."
msgstr "Controleren op updates..."
@@ -665,11 +662,10 @@ msgid "Quit"
msgstr "Afsluiten"
msgid "Close Window"
msgstr ""
msgstr "Venster afsluiten"
#, fuzzy
msgid "&Edit"
msgstr "Bewerken"
msgstr "Be&werken"
msgid "Copy"
msgstr "Kopiëren"
@@ -680,9 +676,8 @@ msgstr "Knippen"
msgid "Paste"
msgstr "Plakken"
#, fuzzy
msgid "Select all"
msgstr "Datum kiezen"
msgstr "Alles selecteren"
msgid "Bold"
msgstr "Vetgedrukt"
@@ -691,7 +686,7 @@ msgid "Italic"
msgstr "Cursief"
msgid "Link"
msgstr ""
msgstr "Koppeling"
msgid "Code"
msgstr "Code"
@@ -708,13 +703,11 @@ msgstr "Labels"
msgid "Search in all the notes"
msgstr "Alle notities doorzoeken"
#, fuzzy
msgid "Search in current note"
msgstr "Alle notities doorzoeken"
msgstr "Huidige notitie doorzoeken"
#, fuzzy
msgid "&View"
msgstr "Beeld"
msgstr "Beel&d"
msgid "Toggle sidebar"
msgstr "Zijbalk tonen/verbergen"
@@ -722,17 +715,14 @@ msgstr "Zijbalk tonen/verbergen"
msgid "Toggle editor layout"
msgstr "Bewerkindeling tonen/verbergen"
#, fuzzy
msgid "Focus"
msgstr "Inhoud focussen"
msgstr "Focus"
#, fuzzy
msgid "&Tools"
msgstr "Hulpmiddelen"
msgstr "E&xtra"
#, fuzzy
msgid "&Help"
msgstr "Hulp"
msgstr "&Help"
msgid "Website and documentation"
msgstr "Website en documentatie"
@@ -741,7 +731,7 @@ msgid "Make a donation"
msgstr "Doneren"
msgid "Toggle development tools"
msgstr ""
msgstr "Wissel ontwikkelhulpmiddelen"
#, javascript-format
msgid "Open %s"
@@ -761,18 +751,18 @@ msgstr "De huidige versie is up-to-date."
#, javascript-format
msgid "%s (pre-release)"
msgstr ""
msgstr "%s (pre-release)"
msgid "An update is available, do you want to download it now?"
msgstr "Er is een update beschikbaar. Wil je deze nu downloaden?"
#, javascript-format
msgid "Your version: %s"
msgstr ""
msgstr "Jouw versie: %s"
#, javascript-format
msgid "New version: %s"
msgstr ""
msgstr "Nieuwe versie: %s"
msgid "Yes"
msgstr "Ja"
@@ -781,7 +771,7 @@ msgid "No"
msgstr "Nee"
msgid "Token has been copied to the clipboard!"
msgstr ""
msgstr "Token is naar het klembord gekopieerd!"
msgid "The web clipper service is enabled and set to auto-start."
msgstr "De webclipper-dienst is ingeschakeld en wordt automatisch opgestart."
@@ -832,20 +822,21 @@ msgstr "Stap 2: Installeer de extensie"
msgid "Download and install the relevant extension for your browser:"
msgstr "Download en installeer de bijbehorende extensie in je browser:"
#, fuzzy
msgid "Advanced options"
msgstr "Geavanceerde opties tonen"
msgstr "Geavanceerde opties"
msgid "Authorisation token:"
msgstr ""
msgstr "Autorisatie-token:"
msgid "Copy token"
msgstr ""
msgstr "Kopieer token"
msgid ""
"This authorisation token is only needed to allow third-party applications to "
"access Joplin."
msgstr ""
"Dit autorisatie-token is alleen nodig om applicaties van derden toegang te "
"geven tot Joplin."
#, javascript-format
msgid "Notes and settings are stored in: %s"
@@ -855,7 +846,7 @@ msgid "Check synchronisation configuration"
msgstr "Synchronisatieconfiguratie controleren"
msgid "Browse..."
msgstr ""
msgstr "Bladeren…"
msgid "Apply"
msgstr "Toepassen"
@@ -951,9 +942,8 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Gebruikte versleuteling:"
#, fuzzy
msgid "Usage"
msgstr "Gebruik: %s"
msgstr "Gebruik"
msgid "Back"
msgstr "Terug"
@@ -998,9 +988,8 @@ msgstr "Sommige items kunnen niet worden gesynchroniseerd."
msgid "View them now"
msgstr "Items tonen"
#, fuzzy
msgid "One or more master keys need a password."
msgstr "Voer het hoofdwachtwoord in:"
msgstr "Een of meer hoofdsleutels vereist een wachtwoord."
msgid "Set the password"
msgstr "Wachtwoord instellen"
@@ -1017,37 +1006,38 @@ msgstr ""
"\"Nieuw notitieboek\"."
msgid "Location"
msgstr ""
msgstr "Locatie"
msgid "URL"
msgstr ""
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Notitieboeken"
msgstr "Notitiegeschiedenis"
msgid "Previous versions of this note"
msgstr ""
msgstr "Vorige versies van deze notitie"
msgid "Note properties"
msgstr ""
msgstr "Eigenschappen van notitie"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
msgstr "De notitie “%s” is succesvol hersteld naar notitieboek “%s”."
#, fuzzy
msgid "This note has no history"
msgstr "Deze notitie is bewerkt:"
msgstr "Deze notitie heeft geen geschiedenis"
msgid "Restore"
msgstr ""
msgstr "Herstel"
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
"Klik “%s” om de notitie te herstellen. Het wordt gekopieerd naar het "
"notitieboek genaamd “%s”. De huidige versie van de notitie wordt niet "
"vervangen of aangepast."
msgid "Open..."
msgstr "Openen..."
@@ -1066,7 +1056,7 @@ msgid "Copy Link Address"
msgstr "Linkadres kopiëren"
msgid "This attachment is not downloaded or not decrypted yet."
msgstr ""
msgstr "Deze bijlage is niet gedownload of nog niet ontsleuteld."
#, javascript-format
msgid "Unsupported link or message: %s"
@@ -1082,6 +1072,8 @@ msgstr ""
msgid "Only one note can be printed or exported to PDF at a time."
msgstr ""
"Slechts één notitie kan gelijktijdig worden afgedrukt of geëxporteerd naar "
"PDF."
msgid "strong text"
msgstr "vetgedrukte tekst"
@@ -1163,21 +1155,23 @@ msgstr "Versleutelopties"
msgid "Clipper Options"
msgstr "Webclipperopties"
#, fuzzy, javascript-format
#, javascript-format
msgid ""
"Delete notebook \"%s\"?\n"
"\n"
"All notes and sub-notebooks within this notebook will also be deleted."
msgstr ""
"Notitieboek verwijderen? Alle notities en sub-notitieboeken worden eveneens "
"Notitieboek “%s” verwijderen?\n"
"\n"
"Alle notities en sub-notitieboeken in dit notitieboek worden eveneens "
"verwijderd."
#, fuzzy, javascript-format
#, javascript-format
msgid "Remove tag \"%s\" from all notes?"
msgstr "Wil je dit label verwijderen van alle notities?"
msgstr "Label “%s” verwijderen van alle notities?"
msgid "Remove this search from the sidebar?"
msgstr "Wil je deze zoekopdracht verwijderen uit de zijbalk?"
msgstr "Deze zoekopdracht verwijderen uit de zijbalk?"
msgid "Delete"
msgstr "Verwijderen"
@@ -1192,15 +1186,15 @@ msgstr "Notitieboeken"
msgid "Decrypting items: %d/%d"
msgstr "Bezig met ontsleutelen van items: %d/%d"
#, fuzzy, javascript-format
#, javascript-format
msgid "Fetching resources: %d/%d"
msgstr "Bronnen: %d/%d"
msgstr "Bronnen ophalen: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Kies waar de synchronisatiestatus naar moet worden geëxporteerd"
msgid "Retry"
msgstr ""
msgstr "Opnieuw proberen"
msgid "Add or remove tags"
msgstr "Labels toevoegen of verwijderen"
@@ -1215,32 +1209,32 @@ msgstr "%s - kopiëren"
msgid "Switch between note and to-do type"
msgstr "Schakelen tussen notitie en taak"
#, fuzzy
msgid "Switch to note type"
msgstr "Schakelen tussen notitie en taak"
msgstr "Overschakelen naar notitie-type"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Schakelen tussen notitie en taak"
msgstr "Overschakelen naar todo-type"
msgid "Copy Markdown link"
msgstr "Markdownlink kopiëren"
#, fuzzy, javascript-format
#, javascript-format
msgid "Delete note \"%s\"?"
msgstr "Notities verwijderen?"
msgstr "Notitie “%s” verwijderen?"
#, fuzzy, javascript-format
#, javascript-format
msgid "Delete these %d notes?"
msgstr "Deze notities verwijderen?"
msgstr "Deze %d notities verwijderen?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
"Typ de titel van een notitie om er naartoe te springen. Of typ # gevolgd "
"door de naam van een label, of @ gevolgd door de naam van een notitieboek."
msgid "Goto Anything..."
msgstr ""
msgstr "Ga naar alles…"
#, javascript-format
msgid "Usage: %s"
@@ -1357,6 +1351,7 @@ msgstr "De synchronisatie loopt al. Status: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
"Onbekend type item gedownload - graag Joplin upgraden naar de laatste versie"
msgid "Encrypted"
msgstr "Versleuteld"
@@ -1400,6 +1395,9 @@ msgid ""
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Let op: Als je deze locatie wijzigt, zorg dan dat je eerst alle inhoud hier "
"naartoe kopieert voor synchronisatie. Anders worden alle bestanden "
"verwijderd! Zie de FAQ voor meer details: %s"
msgid "Synchronisation target"
msgstr "Synchronisatiedoel"
@@ -1434,25 +1432,29 @@ msgid "WebDAV password"
msgstr "WebDAV-wachtwoord"
msgid "Attachment download behaviour"
msgstr ""
msgstr "Gedrag bijlagen downloaden"
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
"In de mode “Handmatig” worden bijlagen alleen gedownload als je hen "
"aanklikt. In “Auto” worden ze gedownload zodra je de notitie opent. In "
"“Altijd” worden bijlagen altijd gedownload, of je de notitie nu opent of "
"niet."
msgid "Always"
msgstr ""
msgstr "Altijd"
msgid "Manual"
msgstr ""
msgstr "Handmatig"
msgid "Auto"
msgstr ""
msgstr "Auto"
msgid "Max concurrent connections"
msgstr ""
msgstr "Max gelijktijdige verbindingen"
msgid "Language"
msgstr "Taal"
@@ -1484,9 +1486,8 @@ msgstr "Notities sorteren op"
msgid "Reverse sort order"
msgstr "Sorteervolgorde omdraaien"
#, fuzzy
msgid "Sort notebooks by"
msgstr "Notities sorteren op"
msgstr "Notitieboeken sorteren op"
msgid "Save geo-location with notes"
msgstr "Locatie opslaan in notities"
@@ -1504,41 +1505,40 @@ msgid "When creating a new note:"
msgstr "Bij het creëren van een nieuwe notitie:"
msgid "Enable soft breaks"
msgstr ""
msgstr "Inschakelen zacht afbreken"
#, fuzzy
msgid "Enable math expressions"
msgstr "Versleuteling inschakelen"
msgstr "Inschakelen wiskundige expressies"
msgid "Enable ==mark== syntax"
msgstr ""
msgstr "Inschakelen ==mark== syntaxis"
msgid "Enable footnotes"
msgstr ""
msgstr "Inschakelen voetnoten"
msgid "Enable table of contents extension"
msgstr ""
msgstr "Inschakelen inhoudsopgave"
msgid "Enable ~sub~ syntax"
msgstr ""
msgstr "Inschakelen ~sub~ syntaxis"
msgid "Enable ^sup^ syntax"
msgstr ""
msgstr "Inschakelen ^sup^ syntaxis"
msgid "Enable deflist syntax"
msgstr ""
msgstr "Inschakelen deflist syntaxis"
msgid "Enable abbreviation syntax"
msgstr ""
msgstr "Inschakelen afkortingen syntaxis"
msgid "Enable markdown emoji"
msgstr ""
msgstr "Inschakelen markdown emoji"
msgid "Enable ++insert++ syntax"
msgstr ""
msgstr "Inschakelen ++insert++ syntaxis"
msgid "Enable multimarkdown table extension"
msgstr ""
msgstr "Inschakelen multimarkdown tabel extensie"
msgid "Show tray icon"
msgstr "Systeemvakpictogram tonen"
@@ -1551,16 +1551,18 @@ msgid ""
"this setting so that your notes are constantly being synchronised, thus "
"reducing the number of conflicts."
msgstr ""
"Dit zal Joplin toestaan in de achtergrond te werken. Het is aanbevolen deze "
"instelling in te schakelen, zodat je notities constant worden "
"gesynchroniseerd, waardoor het aantal conflicten wordt beperkt."
msgid "Start application minimised in the tray icon"
msgstr ""
msgstr "Start applicatie geminimaliseerd in het systeemvak"
msgid "Global zoom percentage"
msgstr "Globaal zoompercentage"
#, fuzzy
msgid "Editor font size"
msgstr "Lettertype van bewerker"
msgstr "Lettergrootte van bewerker"
msgid "Editor font family"
msgstr "Lettertype van bewerker"
@@ -1577,11 +1579,11 @@ msgid "Automatically update the application"
msgstr "Applicatie automatisch bijwerken"
msgid "Get pre-releases when checking for updates"
msgstr ""
msgstr "Verkrijg pre-releases bij controleren op updates"
#, javascript-format
msgid "See the pre-release page for more details: %s"
msgstr ""
msgstr "Zie de pre-release pagina voor meer details: %s"
msgid "Synchronisation interval"
msgstr "Synchronisatietussenpoos"
@@ -1630,49 +1632,44 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "TLS-certificaatfouten negeren"
#, fuzzy
msgid "Enable note history"
msgstr "Versleuteling inschakelen"
msgstr "Inschakelen geschiedenis van notities"
msgid "days"
msgstr ""
msgstr "dagen"
#, javascript-format
msgid "%d days"
msgstr ""
msgstr "%d dagen"
msgid "Keep note history for"
msgstr ""
msgstr "Bewaar geschiedenis van notities voor"
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ongeldige optie: \"%s\". Geldige waarden zijn: %s."
#, fuzzy
msgid "General"
msgstr "Algemene opties"
msgstr "Algemeen"
#, fuzzy
msgid "Synchronisation"
msgstr "Synchronisatiestatus"
msgstr "Synchronisatie"
msgid "Appearance"
msgstr ""
msgstr "Verschijningsvorm"
#, fuzzy
msgid "Note"
msgstr "Notitieboeken"
msgstr "Notitie"
msgid "Plugins"
msgstr ""
msgstr "Plugins"
#, fuzzy
msgid "Application"
msgstr "Sluit de applicatie af."
msgstr "Applicatie"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
msgstr "Het label “%s” bestaat al. Kies een andere naam."
msgid "Joplin Export File"
msgstr "Joplin-exportbestand"
@@ -1686,9 +1683,8 @@ msgstr "Joplin-exportmap"
msgid "Evernote Export File"
msgstr "Evernote-exportbestand"
#, fuzzy
msgid "Json Export Directory"
msgstr "Joplin-exportmap"
msgstr "JSON-exportmap"
msgid "File"
msgstr "Bestand"
@@ -1720,7 +1716,7 @@ msgstr ""
"Geef het notitieboek op waar de notities naar moeten worden geïmporteerd."
msgid "Restored Notes"
msgstr ""
msgstr "Herstelde notities"
msgid "Items that cannot be synchronised"
msgstr "Items die niet kunnen worden gesynchroniseerd"
@@ -1734,23 +1730,25 @@ msgstr ""
"synchronisatiedoel. Als je deze items wilt vinden, moet je zoeken naar de "
"titel of ID ervan (welke hierboven tussen haakjes wordt getoond)."
#, fuzzy, javascript-format
#, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Dit bestand kan niet worden geopend: %s"
msgstr "%s (%s) kon niet worden geupload: %s"
#, fuzzy, javascript-format
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Dit bestand kan niet worden geopend: %s"
msgstr "Item “%s” kan niet worden gedownload: %s"
#, fuzzy
msgid "Items that cannot be decrypted"
msgstr "Items die niet kunnen worden gesynchroniseerd"
msgstr "Items die niet kunnen worden ontsleuteld"
msgid ""
"Joplin failed to decrypt these items multiple times, possibly because they "
"are corrupted or too large. These items will remain on the device but Joplin "
"will no longer attempt to decrypt them."
msgstr ""
"Joplin kon deze items meermaals niet ontsleutelen, mogelijk omdat ze "
"beschadigd of te groot zijn. Deze items blijven op het apparaat, maar Joplin "
"zal niet langer proberen ze te ontsleutelen."
msgid "Sync status (synced items / total items)"
msgstr ""
@@ -1787,10 +1785,10 @@ msgid "On %s: %s"
msgstr "Op %s: %s"
msgid "Permission to use camera"
msgstr ""
msgstr "Toestemming om de camera te gebruiken"
msgid "Your permission to use your camera is required."
msgstr ""
msgstr "Je toestemming om de camera te gebruiken is vereist."
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr ""
@@ -1822,12 +1820,11 @@ msgstr "%d notities verplaatsen naar notitieboek \"%s\"?"
msgid "Press to set the decryption password."
msgstr "Druk om het ontsleutelwachtwoord in te stellen."
#, fuzzy
msgid "Clear alarm"
msgstr "Alarm instellen"
msgstr "Alarm wissen"
msgid "Save alarm"
msgstr "Alarm opslaam"
msgstr "Alarm opslaan"
msgid "Select date"
msgstr "Datum kiezen"
@@ -1838,22 +1835,21 @@ msgstr "Bevestigen"
msgid "Cancel synchronisation"
msgstr "Synchronisatie annuleren"
#, fuzzy
msgid "Checking... Please wait."
msgstr "Bezig met annuleren... Even geduld."
msgstr "Controleren Even geduld."
#, fuzzy
msgid "Success! Synchronisation configuration appears to be correct."
msgstr "Synchronisatieconfiguratie controleren"
msgstr "Succes! Configuratie van synchronisatie lijkt correct te zijn."
msgid ""
"Error. Please check that URL, username, password, etc. are correct and that "
"the sync target is accessible. The reported error was:"
msgstr ""
"Fout. Controleer of de URL, gebruikersnaam, wachtwoord, etc. kloppen en dat "
"het synchronisatiedoel toegankelijk is. De gemelde fout :"
#, fuzzy
msgid "The application has been authorised!"
msgstr "De applicatie is geautoriseerd."
msgstr "De applicatie is geautoriseerd!"
#, javascript-format
msgid ""
@@ -1863,10 +1859,15 @@ msgid ""
"\n"
"Please try again."
msgstr ""
"Kon applicatie niet autoriseren:\n"
"\n"
"%s\n"
"\n"
"Probeer opnieuw."
#, fuzzy, javascript-format
#, javascript-format
msgid "Decrypted items: %s / %s"
msgstr "Bezig met ontsleutelen van items: %d/%d"
msgstr "Ontsleutelde items: %s / %s"
msgid "New tags:"
msgstr "Nieuwe labels:"
@@ -1874,9 +1875,8 @@ msgstr "Nieuwe labels:"
msgid "Type new tags or select from list"
msgstr "Typ nieuwe labels of kies ze uit de lijst"
#, fuzzy
msgid "More information"
msgstr "Configuratie"
msgstr "Meer informatie"
msgid ""
"To work correctly, the app needs the following permissions. Please enable "
@@ -1904,17 +1904,17 @@ msgstr "Joplin-website"
#, javascript-format
msgid "Database v%s"
msgstr ""
msgstr "Database v%s"
#, fuzzy, javascript-format
#, javascript-format
msgid "FTS enabled: %d"
msgstr "Te verwijderen: %d"
msgstr "FTS ingeschakeld: %d"
msgid "Login with Dropbox"
msgstr "Inloggen met Dropbox"
msgid "Enter code here"
msgstr ""
msgstr "Code hier invoeren"
#, javascript-format
msgid "Master Key %s"
@@ -1965,15 +1965,14 @@ msgstr "De mobiele Joplin-app ondersteunt momenteel niet dit soort links: %s"
#, javascript-format
msgid "Links with protocol \"%s\" are not supported"
msgstr ""
msgstr "Links met protocol “%s” worden niet ondersteund"
#, javascript-format
msgid "Unsupported image type: %s"
msgstr "Niet-ondersteunde afbeeldingssoort: %s"
#, fuzzy
msgid "Take photo"
msgstr "Foto bijvoegen"
msgstr "Foto maken"
msgid "Attach photo"
msgstr "Foto bijvoegen"
@@ -2000,7 +1999,7 @@ msgid "View on map"
msgstr "Tonen op kaart"
msgid "Go to source URL"
msgstr ""
msgstr "Ga naar bron-URL"
msgid "Edit"
msgstr "Bewerken"

View File

@@ -189,6 +189,39 @@ describe('services_rest_Api', function() {
done();
});
it('should create todos', async (done) => {
let response = null;
const f = await Folder.save({ title: "stuff to do" });
response = await api.route('POST', 'notes', null, JSON.stringify({
title: 'testing',
parent_id: f.id,
is_todo: 1
}));
expect(response.is_todo).toBe(1);
response = await api.route('POST', 'notes', null, JSON.stringify({
title: 'testing 2',
parent_id: f.id,
is_todo: 0
}));
expect(response.is_todo).toBe(0);
response = await api.route('POST', 'notes', null, JSON.stringify({
title: 'testing 3',
parent_id: f.id,
}));
expect(response.is_todo).toBeUndefined();
response = await api.route('POST', 'notes', null, JSON.stringify({
title: 'testing 4',
parent_id: f.id,
is_todo: '1'
}));
expect(response.is_todo).toBe(1);
done();
});
it('should create folders with supplied ID', async (done) => {
const response = await api.route('POST', 'folders', null, JSON.stringify({
id: '12345678123456781234567812345678',
@@ -316,4 +349,4 @@ describe('services_rest_Api', function() {
done();
});
});
});

View File

@@ -512,12 +512,20 @@ class Application extends BaseApplication {
function _showAbout() {
const p = packageInfo;
let gitInfo = '';
if ("git" in p) {
gitInfo = _('Revision: %s (%s)', p.git.hash, p.git.branch);
}
let message = [
p.description,
'',
'Copyright © 2016-2019 Laurent Cozic',
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
];
if (!!gitInfo) {
message.push("\n" + gitInfo);
console.info(gitInfo);
}
bridge().showInfoMessageBox(message.join('\n'), {
icon: bridge().electronApp().buildDir() + '/icons/32x32.png',
});

View File

@@ -1,4 +1,5 @@
const fs = require('fs-extra');
const execSync = require('child_process').execSync;
// Electron Builder strip off certain important keys from package.json, which we need, in particular build.appId
// so this script is used to preserve the keys that we need.
@@ -16,6 +17,19 @@ const appId = packageInfo.build.appId;
delete packageInfo.build;
packageInfo.build = { appId: appId };
let branch;
let hash;
try {
branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
hash = execSync('git log --pretty="%h" -1').toString().trim();
}
catch(err) {
console.warn("Could not get git info", err);
}
if (typeof branch !== 'undefined' && typeof hash !== 'undefined') {
packageInfo.git = { branch: branch, hash: hash };
}
let fileContent = "// Auto-generated by compile-package-info.js\n// Do not change directly\nconst packageInfo = " + JSON.stringify(packageInfo, null, 4) + ';';
fileContent += "\n";
fileContent += "module.exports = packageInfo;";

View File

@@ -62,8 +62,6 @@ class NoteTextComponent extends React.Component {
this.state = {
note: null,
noteMetadata: '',
showNoteMetadata: false,
folder: null,
lastSavedNote: null,
isLoading: true,
@@ -644,10 +642,6 @@ class NoteTextComponent extends React.Component {
return false;
}
refreshNoteMetadata(force = null) {
return shared.refreshNoteMetadata(this, force);
}
async noteRevisionViewer_onBack() {
this.setState({ showRevisions: false });
@@ -666,10 +660,6 @@ class NoteTextComponent extends React.Component {
this.scheduleSave();
}
showMetadata_onPress() {
shared.showMetadata_onPress(this);
}
async webview_ipcMessage(event) {
const msg = event.channel ? event.channel : '';
const args = event.args;

View File

@@ -28,7 +28,7 @@ Linux | <a href='https://github.com/laurent22/joplin/releases/download/
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://joplinapp.org/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.277/joplin-v1.0.277.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://joplinapp.org/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.279/joplin-v1.0.279.apk)
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://joplinapp.org/images/BadgeIOS.png'/></a> | -
## Terminal application
@@ -346,7 +346,7 @@ Please see the [donation page](https://joplinapp.org/donate/) for information on
- Also see here for information about [the latest releases and general news](https://discourse.joplinapp.org/c/news).
- For bug reports and feature requests, go to the [GitHub Issue Tracker](https://github.com/laurent22/joplin/issues).
- The latest news are posted [on the Patreon page](https://www.patreon.com/joplin).
- You can also follow us on [the Twitter feed](https://twitter.com/joplinapp).
- You can also follow us on <a rel="me" href="https://mastodon.social/@joplinapp">the Mastodon feed</a> or [the Twitter feed](https://twitter.com/joplinapp).
# Contributing
@@ -359,7 +359,7 @@ Joplin is currently available in the languages below. If you would like to contr
- [Download Poedit](https://poedit.net/), the translation editor, and install it.
- [Download the file to be translated](https://raw.githubusercontent.com/laurent22/joplin/master/CliClient/locales/joplin.pot).
- In Poedit, open this .pot file, go into the Catalog menu and click Configuration. Change "Country" and "Language" to your own country and language.
- From then you can translate the file. Once it is done, please either [open a pull request](https://github.com/laurent22/joplin/pulls) or send the file to [this address](https://raw.githubusercontent.com/laurent22/joplin/master/Assets/Adresse.png).
- From then you can translate the file. Once it is done, please either [open a pull request](https://github.com/laurent22/joplin/pulls) or send the file to [this address](https://raw.githubusercontent.com/laurent22/joplin/master/Assets/AdresseTranslation.png).
This translation will apply to the three applications - desktop, mobile and terminal.

View File

@@ -94,8 +94,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097513
versionName "1.0.277"
versionCode 2097515
versionName "1.0.279"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}

View File

@@ -26,7 +26,7 @@ const DialogBox = require('react-native-dialogbox').default;
// default height.
const PADDING_V = 10;
class ScreenHeaderComponent extends Component {
class ScreenHeaderComponent extends React.PureComponent {
constructor() {
super();
@@ -124,7 +124,7 @@ class ScreenHeaderComponent extends Component {
titleText: {
flex: 1,
textAlignVertical: 'center',
marginLeft: 0,
marginLeft: 10,
color: theme.raisedHighlightedColor,
fontWeight: 'bold',
fontSize: theme.fontSize,
@@ -158,7 +158,11 @@ class ScreenHeaderComponent extends Component {
}
async backButton_press() {
await BackButtonService.back();
if (this.props.noteSelectionEnabled) {
this.props.dispatch({ type: 'NOTE_SELECTION_END' });
} else {
await BackButtonService.back();
}
}
searchButton_press() {
@@ -311,9 +315,10 @@ class ScreenHeaderComponent extends Component {
}
const titlePickerItems = (mustSelect) => {
const folders = this.props.folders.filter(f => f.id !== Folder.conflictFolderId());
let output = [];
if (mustSelect) output.push({ label: _('Move to notebook...'), value: null });
const folderTree = Folder.buildTree(this.props.folders);
const folderTree = Folder.buildTree(folders);
output = addFolderChildren(folderTree, output, 0);
return output;
}
@@ -373,21 +378,30 @@ class ScreenHeaderComponent extends Component {
</TouchableOpacity>
) : null;
const showSideMenuButton = this.props.showSideMenuButton !== false && !this.props.noteSelectionEnabled;
const showSearchButton = this.props.showSearchButton !== false && !this.props.noteSelectionEnabled;
const showSideMenuButton = !!this.props.showSideMenuButton && !this.props.noteSelectionEnabled;
const showSearchButton = !!this.props.showSearchButton && !this.props.noteSelectionEnabled;
const showContextMenuButton = this.props.showContextMenuButton !== false;
const showBackButton = !!this.props.noteSelectionEnabled || this.props.showBackButton !== false;
let backButtonDisabled = !this.props.historyCanGoBack;
if (!!this.props.noteSelectionEnabled) backButtonDisabled = false;
const titleComp = createTitleComponent();
const sideMenuComp = !showSideMenuButton ? null : sideMenuButton(this.styles(), () => this.sideMenuButton_press());
const backButtonComp = backButton(this.styles(), () => this.backButton_press(), !this.props.historyCanGoBack);
const backButtonComp = !showBackButton ? null : backButton(this.styles(), () => this.backButton_press(), backButtonDisabled);
const searchButtonComp = !showSearchButton ? null : searchButton(this.styles(), () => this.searchButton_press());
const deleteButtonComp = this.props.noteSelectionEnabled ? deleteButton(this.styles(), () => this.deleteButton_press()) : null;
const sortButtonComp = this.props.sortButton_press ? sortButton(this.styles(), () => this.props.sortButton_press()) : null;
const sortButtonComp = !this.props.noteSelectionEnabled && this.props.sortButton_press ? sortButton(this.styles(), () => this.props.sortButton_press()) : null;
const windowHeight = Dimensions.get('window').height - 50;
const contextMenuStyle = { paddingTop: PADDING_V, paddingBottom: PADDING_V };
// HACK: if this button is removed during selection mode, the header layout is broken, so for now just make it 1 pixel large (normally it should be hidden)
if (!!this.props.noteSelectionEnabled) contextMenuStyle.width = 1;
const menuComp = !menuOptionComponents.length || !showContextMenuButton ? null : (
<Menu onSelect={(value) => this.menu_select(value)} style={this.styles().contextMenu}>
<MenuTrigger style={{ paddingTop: PADDING_V, paddingBottom: PADDING_V }}>
<MenuTrigger style={contextMenuStyle}>
<Icon name='md-more' style={this.styles().contextMenuTrigger} />
</MenuTrigger>
<MenuOptions>

View File

@@ -1,5 +1,5 @@
const React = require('react'); const Component = React.Component;
const { Platform, TouchableOpacity, Linking, View, Switch, StyleSheet, Text, Button, ScrollView, TextInput } = require('react-native');
const { Platform, TouchableOpacity, Linking, View, Switch, StyleSheet, Text, Button, ScrollView, TextInput, Alert } = require('react-native');
const { connect } = require('react-redux');
const { ScreenHeader } = require('lib/components/screen-header.js');
const { _, setLocale } = require('lib/locale.js');
@@ -14,6 +14,7 @@ const NavService = require('lib/services/NavService.js');
const VersionInfo = require('react-native-version-info').default;
const { ReportService } = require('lib/services/report.js');
const { time } = require('lib/time-utils');
const SearchEngine = require('lib/services/SearchEngine');
const RNFS = require('react-native-fs');
import Slider from '@react-native-community/slider';
@@ -78,6 +79,12 @@ class ConfigScreenComponent extends BaseScreenComponent {
this.setState({ creatingReport: false });
}
this.fixSearchEngineIndexButtonPress_ = async () => {
this.setState({ fixingSearchIndex: true });
await SearchEngine.instance().rebuildIndex();
this.setState({ fixingSearchIndex: false });
}
this.logButtonPress_ = () => {
NavService.go('Log');
}
@@ -125,6 +132,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
sliderUnits: {
color: theme.color,
fontSize: theme.fontSize,
marginRight: 10,
},
settingDescriptionText: {
color: theme.color,
@@ -190,6 +198,15 @@ class ConfigScreenComponent extends BaseScreenComponent {
renderButton(key, title, clickHandler, options = null) {
if (!options) options = {};
let descriptionComp = null;
if (options.description) {
descriptionComp = (
<View style={{flex:1, marginTop: 10}}>
<Text style={this.styles().descriptionText}>{options.description}</Text>
</View>
);
}
return (
<View key={key} style={this.styles().settingContainer}>
<View style={{flex:1, flexDirection: 'column'}}>
@@ -197,6 +214,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
<Button title={title} onPress={clickHandler} disabled={!!options.disabled}/>
</View>
{ options.statusComp }
{ descriptionComp }
</View>
</View>
);
@@ -229,7 +247,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
}
if (section.name === 'sync') {
settingComps.push(this.renderButton('e2ee_config_button', _('Encryption Config') + ' ▶', this.e2eeConfig_));
settingComps.push(this.renderButton('e2ee_config_button', _('Encryption Config'), this.e2eeConfig_));
}
const headerWrapperStyle = this.styles().headerWrapperStyle;
@@ -307,9 +325,9 @@ class ConfigScreenComponent extends BaseScreenComponent {
return (
<View key={key} style={this.styles().settingContainer}>
<Text key="label" style={this.styles().settingText}>{md.label()}</Text>
<View style={{display:'flex', flexDirection: 'column', alignItems: 'center', flex:1}}>
<Slider key="control" minimumTrackTintColor={theme.color} maximumTrackTintColor={theme.color} style={{width:'100%'}} step={md.step} minimumValue={md.minimum} maximumValue={md.maximum} value={value} onValueChange={(value) => updateSettingValue(key, value)} />
<View style={{display:'flex', flexDirection: 'row', alignItems: 'center', flex:1}}>
<Text style={this.styles().sliderUnits}>{unitLabel}</Text>
<Slider key="control" minimumTrackTintColor={theme.color} maximumTrackTintColor={theme.color} style={{flex:1}} step={md.step} minimumValue={md.minimum} maximumValue={md.maximum} value={value} onValueChange={(value) => updateSettingValue(key, value)} />
</View>
</View>
);
@@ -332,11 +350,12 @@ class ConfigScreenComponent extends BaseScreenComponent {
const settingComps = shared.settingsToComponents2(this, 'mobile', settings);
settingComps.push(this.renderHeader('moreInfo', _('Tools')));
settingComps.push(this.renderHeader('tools', _('Tools')));
settingComps.push(this.renderButton('status_button', _('Sync Status') + ' ▶', this.syncStatusButtonPress_));
settingComps.push(this.renderButton('log_button', _('Log') + ' ▶', this.logButtonPress_));
settingComps.push(this.renderButton('status_button', _('Sync Status'), this.syncStatusButtonPress_));
settingComps.push(this.renderButton('log_button', _('Log'), this.logButtonPress_));
settingComps.push(this.renderButton('export_report_button', this.state.creatingReport ? _('Creating report...') : _('Export Debug Report'), this.exportDebugButtonPress_, { disabled: this.state.creatingReport }));
settingComps.push(this.renderButton('fix_search_engine_index', this.state.fixingSearchIndex ? _('Fixing search index...') : _('Fix search index'), this.fixSearchEngineIndexButtonPress_, { disabled: this.state.fixingSearchIndex, description: _('Use this to rebuild the search index if there is a problem with search. It may take some times depending on the number of notes.') }));
settingComps.push(this.renderHeader('moreInfo', _('More information')));
@@ -403,6 +422,8 @@ class ConfigScreenComponent extends BaseScreenComponent {
<ScreenHeader
title={_('Configuration')}
showSaveButton={true}
showSearchButton={false}
showSideMenuButton={false}
saveButtonDisabled={!this.state.changedSettingKeys.length}
onSaveButtonPress={this.saveButton_press}
/>

View File

@@ -35,7 +35,8 @@ class FolderScreenComponent extends BaseScreenComponent {
let styles = {
textInput: {
color: theme.color,
paddingLeft: 10,
paddingLeft: theme.marginLeft,
marginTop: theme.marginTop,
},
};
@@ -112,8 +113,10 @@ class FolderScreenComponent extends BaseScreenComponent {
showSaveButton={true}
saveButtonDisabled={saveButtonDisabled}
onSaveButtonPress={() => this.saveFolderButton_press()}
showSideMenuButton={false}
showSearchButton={false}
/>
<TextInput underlineColorAndroid={theme.strongDividerColor} selectionColor={theme.textSelectionColor} style={this.styles().textInput} autoFocus={true} value={this.state.folder.title} onChangeText={(text) => this.title_changeText(text)} />
<TextInput placeholder={_('Enter notebook title')} underlineColorAndroid={theme.strongDividerColor} selectionColor={theme.textSelectionColor} style={this.styles().textInput} autoFocus={true} value={this.state.folder.title} onChangeText={(text) => this.title_changeText(text)} />
<dialogs.DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
</View>
);

View File

@@ -4,10 +4,12 @@ const { connect } = require('react-redux');
const { uuid } = require('lib/uuid.js');
const RNFS = require('react-native-fs');
const Note = require('lib/models/Note.js');
const ObjectUtils = require('lib/ObjectUtils.js');
const BaseItem = require('lib/models/BaseItem.js');
const Setting = require('lib/models/Setting.js');
const Resource = require('lib/models/Resource.js');
const Folder = require('lib/models/Folder.js');
const md5 = require('md5');
const { BackButtonService } = require('lib/services/back-button.js');
const NavService = require('lib/services/NavService.js');
const BaseModel = require('lib/BaseModel.js');
@@ -52,8 +54,6 @@ class NoteScreenComponent extends BaseScreenComponent {
this.state = {
note: Note.new(),
mode: 'view',
noteMetadata: '',
showNoteMetadata: false,
folder: null,
lastSavedNote: null,
isLoading: true,
@@ -75,6 +75,8 @@ class NoteScreenComponent extends BaseScreenComponent {
HACK_webviewLoadingState: 0,
};
this.doFocusUpdate_ = false;
// iOS doesn't support multiline text fields properly so disable it
this.enableMultilineTitle_ = Platform.OS !== 'ios';
@@ -183,14 +185,25 @@ class NoteScreenComponent extends BaseScreenComponent {
this.takePhoto_onPress = this.takePhoto_onPress.bind(this);
this.cameraView_onPhoto = this.cameraView_onPhoto.bind(this);
this.cameraView_onCancel = this.cameraView_onCancel.bind(this);
this.properties_onPress = this.properties_onPress.bind(this);
this.onMarkForDownload = this.onMarkForDownload.bind(this);
this.sideMenuOptions = this.sideMenuOptions.bind(this);
this.folderPickerOptions_valueChanged = this.folderPickerOptions_valueChanged.bind(this);
this.saveNoteButton_press = this.saveNoteButton_press.bind(this);
this.onAlarmDialogAccept = this.onAlarmDialogAccept.bind(this);
this.onAlarmDialogReject = this.onAlarmDialogReject.bind(this);
this.todoCheckbox_change = this.todoCheckbox_change.bind(this);
this.titleTextInput_contentSizeChange = this.titleTextInput_contentSizeChange.bind(this);
this.title_changeText = this.title_changeText.bind(this);
}
styles() {
const themeId = this.props.theme;
const theme = themeStyle(themeId);
if (this.styles_[themeId]) return this.styles_[themeId];
const cacheKey = [themeId, this.state.titleTextInputHeight, this.state.HACK_webviewLoadingState].join('_');
if (this.styles_[cacheKey]) return this.styles_[cacheKey];
this.styles_ = {};
let styles = {
@@ -210,10 +223,12 @@ class NoteScreenComponent extends BaseScreenComponent {
paddingTop: theme.marginTop,
paddingBottom: theme.marginBottom,
},
metadata: {
paddingLeft: globalStyle.marginLeft,
paddingRight: globalStyle.marginRight,
checkbox: {
color: theme.color,
paddingRight: 10,
paddingLeft: theme.marginLeft,
paddingTop: 10, // Added for iOS (Not needed for Android??)
paddingBottom: 10, // Added for iOS (Not needed for Android??)
},
};
@@ -229,8 +244,23 @@ class NoteScreenComponent extends BaseScreenComponent {
styles.titleContainerTodo = Object.assign({}, styles.titleContainer);
styles.titleContainerTodo.paddingLeft = 0;
this.styles_[themeId] = StyleSheet.create(styles);
return this.styles_[themeId];
styles.titleTextInput = {
flex: 1,
marginTop: 0,
paddingLeft: 0,
color: theme.color,
backgroundColor: theme.backgroundColor,
fontWeight: 'bold',
fontSize: theme.fontSize,
paddingTop: 10, // Added for iOS (Not needed for Android??)
paddingBottom: 10, // Added for iOS (Not needed for Android??)
};
if (this.enableMultilineTitle_) styles.titleTextInput.height = this.state.titleTextInputHeight;
if (this.state.HACK_webviewLoadingState === 1) styles.titleTextInput.marginTop = 1;
this.styles_[cacheKey] = StyleSheet.create(styles);
return this.styles_[cacheKey];
}
isModified() {
@@ -251,15 +281,18 @@ class NoteScreenComponent extends BaseScreenComponent {
await ResourceFetcher.instance().markForDownload(resourceIds);
}
this.refreshNoteMetadata();
this.focusUpdate();
}
onMarkForDownload(event) {
ResourceFetcher.instance().markForDownload(event.resourceId);
}
refreshNoteMetadata(force = null) {
return shared.refreshNoteMetadata(this, force);
componentDidUpdate() {
if (this.doFocusUpdate_) {
this.doFocusUpdate_ = false;
this.focusUpdate();
}
}
componentWillUnmount() {
@@ -276,10 +309,23 @@ class NoteScreenComponent extends BaseScreenComponent {
title_changeText(text) {
shared.noteComponent_change(this, 'title', text);
this.setState({ newAndNoTitleChangeNoteId: null });
this.scheduleSave();
}
body_changeText(text) {
shared.noteComponent_change(this, 'body', text);
this.scheduleSave();
}
scheduleSave() {
if (this.scheduleSaveIID_) {
clearTimeout(this.scheduleSaveIID_);
this.scheduleSaveIID_ = null;
}
this.scheduleSaveIID_ = setTimeout(async () => {
await shared.saveNoteButton_press(this);
}, 1000);
}
async saveNoteButton_press(folderId = null) {
@@ -455,6 +501,8 @@ class NoteScreenComponent extends BaseScreenComponent {
this.setState({ note: newNote });
this.refreshResource(resource);
this.scheduleSave();
}
async attachPhoto_onPress() {
@@ -503,6 +551,15 @@ class NoteScreenComponent extends BaseScreenComponent {
});
}
properties_onPress() {
this.props.dispatch({
type: 'NOTE_SIDE_MENU_OPTIONS_SET',
options: this.sideMenuOptions(),
});
this.props.dispatch({ type: 'SIDE_MENU_OPEN' });
}
setAlarm_onPress() {
this.setState({ alarmDialogShown: true });
}
@@ -520,10 +577,6 @@ class NoteScreenComponent extends BaseScreenComponent {
this.setState({ alarmDialogShown: false });
}
showMetadata_onPress() {
shared.showMetadata_onPress(this);
}
async showOnMap_onPress() {
if (!this.state.note.id) return;
@@ -552,11 +605,34 @@ class NoteScreenComponent extends BaseScreenComponent {
Clipboard.setString(Note.markdownTag(note));
}
sideMenuOptions() {
const note = this.state.note;
if (!note) return [];
const output = [];
const createdDateString = time.unixMsToLocalDateTime(note.user_created_time);
const updatedDateString = time.unixMsToLocalDateTime(note.user_updated_time);
output.push({ title: _('Created: %s', createdDateString) });
output.push({ title: _('Updated: %s', updatedDateString) });
output.push({ isDivider: true });
output.push({ title: _('View on map'), onPress: () => { this.showOnMap_onPress(); } });
if (!!note.source_url) output.push({ title: _('Go to source URL'), onPress: () => { this.showSource_onPress(); } });
return output;
}
menuOptions() {
const note = this.state.note;
const isTodo = note && !!note.is_todo;
const isSaved = note && note.id;
const hasSource = note && note.source_url;
const cacheKey = md5([isTodo, isSaved].join('_'));
if (!this.menuOptionsCache_) this.menuOptionsCache_ = {};
if (this.menuOptionsCache_[cacheKey]) return this.menuOptionsCache_[cacheKey];
let output = [];
@@ -565,10 +641,17 @@ class NoteScreenComponent extends BaseScreenComponent {
let canAttachPicture = true;
if (Platform.OS === 'android' && Platform.Version < 21) canAttachPicture = false;
if (canAttachPicture) {
output.push({ title: _('Take photo'), onPress: () => { this.takePhoto_onPress(); } });
output.push({ title: _('Attach photo'), onPress: () => { this.attachPhoto_onPress(); } });
output.push({ title: _('Attach any file'), onPress: () => { this.attachFile_onPress(); } });
output.push({ isDivider: true });
output.push({ title: _('Attach...'), onPress: async () => {
const buttonId = await dialogs.pop(this, _('Choose an option'), [
{ text: _('Take photo'), id: 'takePhoto' },
{ text: _('Attach photo'), id: 'attachPhoto' },
{ text: _('Attach any file'), id: 'attachFile' },
]);
if (buttonId === 'takePhoto') this.takePhoto_onPress();
if (buttonId === 'attachPhoto') this.attachPhoto_onPress();
if (buttonId === 'attachFile') this.attachFile_onPress();
}});
}
if (isTodo) {
@@ -579,13 +662,12 @@ class NoteScreenComponent extends BaseScreenComponent {
if (isSaved) output.push({ title: _('Tags'), onPress: () => { this.tags_onPress(); } });
output.push({ title: isTodo ? _('Convert to note') : _('Convert to todo'), onPress: () => { this.toggleIsTodo_onPress(); } });
if (isSaved) output.push({ title: _('Copy Markdown link'), onPress: () => { this.copyMarkdownLink_onPress(); } });
output.push({ isDivider: true });
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: _('Properties'), onPress: () => { this.properties_onPress(); } });
output.push({ title: _('Delete'), onPress: () => { this.deleteNote_onPress(); } });
this.menuOptionsCache_ = {};
this.menuOptionsCache_[cacheKey] = output;
return output;
}
@@ -600,6 +682,49 @@ class NoteScreenComponent extends BaseScreenComponent {
this.setState({ titleTextInputHeight: height });
}
focusUpdate() {
this.scheduleFocusUpdateIID_ = null;
if (!this.state.note) return;
let fieldToFocus = !!this.state.note.is_todo ? 'title' : 'body';
if (this.state.mode === 'view') fieldToFocus = '';
if (fieldToFocus === 'title') this.refs.titleTextField.focus();
if (fieldToFocus === 'body') this.refs.noteBodyTextField.focus();
}
async folderPickerOptions_valueChanged(itemValue, itemIndex) {
const note = this.state.note;
if (!note.id) {
await this.saveNoteButton_press(itemValue);
} else {
await Note.moveToFolder(note.id, itemValue);
}
note.parent_id = itemValue;
const folder = await Folder.load(note.parent_id);
this.setState({
lastSavedNote: Object.assign({}, note),
note: note,
folder: folder,
});
}
folderPickerOptions() {
const options = {
enabled: true,
selectedFolderId: this.state.folder ? this.state.folder.id : null,
onValueChange: this.folderPickerOptions_valueChanged,
};
if (this.folderPickerOptions_ && options.selectedFolderId === this.folderPickerOptions_.selectedFolderId) return this.folderPickerOptions_;
this.folderPickerOptions_ = options;
return this.folderPickerOptions_;
}
render() {
if (this.state.isLoading) {
return (
@@ -655,20 +780,21 @@ class NoteScreenComponent extends BaseScreenComponent {
}}
/>
} else {
const focusBody = !isNew && !!note.title;
// autoFocus={fieldToFocus === 'body'}
// Note: blurOnSubmit is necessary to get multiline to work.
// See https://github.com/facebook/react-native/issues/12717#issuecomment-327001997
bodyComponent = (
<TextInput
autoCapitalize="sentences"
autoFocus={focusBody}
autoCapitalize="sentences"
style={this.styles().bodyTextInput}
ref="noteBodyTextField"
multiline={true}
value={note.body}
onChangeText={(text) => this.body_changeText(text)}
blurOnSubmit={false}
selectionColor={theme.textSelectionColor}
placeholder={_('Add body')}
/>
);
}
@@ -681,10 +807,12 @@ class NoteScreenComponent extends BaseScreenComponent {
icon: 'md-create',
onPress: () => {
this.setState({ mode: 'edit' });
this.doFocusUpdate_ = true;
},
});
if (this.state.mode == 'edit') return null;//<ActionButton style={{display:'none'}}/>;
if (this.state.mode == 'edit') return null;
return <ActionButton multiStates={true} buttons={buttons} buttonIndex={0} />
}
@@ -698,47 +826,22 @@ class NoteScreenComponent extends BaseScreenComponent {
const titleContainerStyle = isTodo ? this.styles().titleContainerTodo : this.styles().titleContainer;
let titleTextInputStyle = {
flex: 1,
marginTop: 0,
paddingLeft: 0,
color: theme.color,
backgroundColor: theme.backgroundColor,
fontWeight: 'bold',
fontSize: theme.fontSize,
paddingTop: 10, // Added for iOS (Not needed for Android??)
paddingBottom: 10, // Added for iOS (Not needed for Android??)
};
if (this.enableMultilineTitle_) titleTextInputStyle.height = this.state.titleTextInputHeight;
let checkboxStyle = {
color: theme.color,
paddingRight: 10,
paddingLeft: theme.marginLeft,
paddingTop: 10, // Added for iOS (Not needed for Android??)
paddingBottom: 10, // Added for iOS (Not needed for Android??)
}
if (this.state.HACK_webviewLoadingState === 1) {
titleTextInputStyle.marginTop = 1;
}
const dueDate = isTodo && note.todo_due ? new Date(note.todo_due) : null;
const dueDate = Note.dueDateObject(note);
const titleComp = (
<View style={titleContainerStyle}>
{ isTodo && <Checkbox style={checkboxStyle} checked={!!Number(note.todo_completed)} onChange={(checked) => { this.todoCheckbox_change(checked) }} /> }
{ isTodo && <Checkbox style={this.styles().checkbox} checked={!!Number(note.todo_completed)} onChange={this.todoCheckbox_change} /> }
<TextInput
onContentSizeChange={(event) => this.titleTextInput_contentSizeChange(event)}
autoFocus={isNew}
onContentSizeChange={this.titleTextInput_contentSizeChange}
multiline={this.enableMultilineTitle_}
ref="titleTextField"
underlineColorAndroid="#ffffff00"
autoCapitalize="sentences"
style={titleTextInputStyle}
style={this.styles().titleTextInput}
value={note.title}
onChangeText={(text) => this.title_changeText(text)}
onChangeText={this.title_changeText}
selectionColor={theme.textSelectionColor}
placeholder={_('Add title')}
/>
</View>
);
@@ -748,42 +851,23 @@ class NoteScreenComponent extends BaseScreenComponent {
return (
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader
folderPickerOptions={{
enabled: true,
selectedFolderId: folder ? folder.id : null,
onValueChange: async (itemValue, itemIndex) => {
if (!note.id) {
await this.saveNoteButton_press(itemValue);
} else {
await Note.moveToFolder(note.id, itemValue);
}
note.parent_id = itemValue;
const folder = await Folder.load(note.parent_id);
this.setState({
lastSavedNote: Object.assign({}, note),
note: note,
folder: folder,
});
},
}}
folderPickerOptions={this.folderPickerOptions()}
menuOptions={this.menuOptions()}
showSaveButton={showSaveButton}
saveButtonDisabled={saveButtonDisabled}
onSaveButtonPress={() => this.saveNoteButton_press()}
onSaveButtonPress={this.saveNoteButton_press}
showSideMenuButton={false}
showSearchButton={false}
/>
{ titleComp }
{ bodyComponent }
{ actionButtonComp }
{ this.state.showNoteMetadata && <Text style={this.styles().metadata}>{this.state.noteMetadata}</Text> }
<SelectDateTimeDialog
shown={this.state.alarmDialogShown}
date={dueDate}
onAccept={(date) => this.onAlarmDialogAccept(date) }
onReject={() => this.onAlarmDialogReject() }
onAccept={this.onAlarmDialogAccept}
onReject={this.onAlarmDialogReject}
/>
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>

View File

@@ -1,5 +1,5 @@
const React = require('react'); const Component = React.Component;
const { AppState, View, Button, Text } = require('react-native');
const { AppState, View, Button, Text, StyleSheet } = require('react-native');
const { stateUtils } = require('lib/reducer.js');
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
@@ -72,6 +72,25 @@ class NotesScreenComponent extends BaseScreenComponent {
}
}
styles() {
if (!this.styles_) this.styles_ = {};
const themeId = this.props.theme;
const theme = themeStyle(themeId);
const cacheKey = themeId;
if (this.styles_[cacheKey]) return this.styles_[cacheKey];
this.styles_ = {};
let styles = {
noteList: {
flex: 1,
},
};
this.styles_[cacheKey] = StyleSheet.create(styles);
return this.styles_[cacheKey];
}
async componentDidMount() {
await this.refreshNotes();
AppState.addEventListener('change', this.onAppStateChange_);
@@ -85,6 +104,7 @@ class NotesScreenComponent extends BaseScreenComponent {
if (newProps.notesOrder !== this.props.notesOrder ||
newProps.selectedFolderId != this.props.selectedFolderId ||
newProps.selectedTagId != this.props.selectedTagId ||
newProps.selectedSmartFilterId != this.props.selectedSmartFilterId ||
newProps.notesParentType != this.props.notesParentType) {
await this.refreshNotes(newProps);
}
@@ -111,10 +131,12 @@ class NotesScreenComponent extends BaseScreenComponent {
if (source == props.notesSource) return;
let notes = [];
if (props.notesParentType == 'Folder') {
if (props.notesParentType === 'Folder') {
notes = await Note.previews(props.selectedFolderId, options);
} else {
} else if (props.notesParentType === 'Tag') {
notes = await Tag.notes(props.selectedTagId, options);
} else if (props.notesParentType === 'SmartFilter') {
notes = await Note.previews(null, options);
}
this.props.dispatch({
@@ -131,7 +153,8 @@ class NotesScreenComponent extends BaseScreenComponent {
Folder.delete(folderId).then(() => {
this.props.dispatch({
type: 'NAV_GO',
routeName: 'Welcome',
routeName: 'Notes',
smartFilterId: 'c3176726992c11e9ac940492261af972',
});
}).catch((error) => {
alert(error.message);
@@ -147,23 +170,6 @@ class NotesScreenComponent extends BaseScreenComponent {
});
}
menuOptions() {
if (this.props.notesParentType == 'Folder') {
if (this.props.selectedFolderId == Folder.conflictFolderId()) return [];
const folder = this.parentItem();
if (!folder) return [];
let output = [];
// if (!folder.encryption_applied) output.push({ title: _('Edit notebook'), onPress: () => { this.editFolder_onPress(this.props.selectedFolderId); } });
// output.push({ title: _('Delete notebook'), onPress: () => { this.deleteFolder_onPress(this.props.selectedFolderId); } });
return output;
} else {
return []; // For tags - TODO
}
}
parentItem(props = null) {
if (!props) props = this.props;
@@ -172,6 +178,8 @@ class NotesScreenComponent extends BaseScreenComponent {
output = Folder.byId(props.folders, props.selectedFolderId);
} else if (props.notesParentType == 'Tag') {
output = Tag.byId(props.tags, props.selectedTagId);
} else if (props.notesParentType == 'SmartFilter') {
output = { id: this.props.selectedSmartFilterId, title: _('All notes') };
} else {
return null;
throw new Error('Invalid parent type: ' + props.notesParentType);
@@ -179,6 +187,18 @@ class NotesScreenComponent extends BaseScreenComponent {
return output;
}
folderPickerOptions() {
const options = {
enabled: this.props.noteSelectionEnabled,
mustSelect: true,
};
if (this.folderPickerOptions_ && options.enabled === this.folderPickerOptions_.enabled) return this.folderPickerOptions_;
this.folderPickerOptions_ = options;
return this.folderPickerOptions_;
}
render() {
const parent = this.parentItem();
const theme = themeStyle(this.props.theme);
@@ -195,7 +215,7 @@ class NotesScreenComponent extends BaseScreenComponent {
if (!parent) {
return (
<View style={rootStyle}>
<ScreenHeader title={title} menuOptions={this.menuOptions()} />
<ScreenHeader title={title} />
</View>
)
}
@@ -209,15 +229,14 @@ class NotesScreenComponent extends BaseScreenComponent {
<View style={rootStyle}>
<ScreenHeader
title={title}
menuOptions={this.menuOptions()}
showBackButton={false}
parentComponent={thisComp}
sortButton_press={this.sortButton_press}
folderPickerOptions={{
enabled: this.props.noteSelectionEnabled,
mustSelect: true,
}}
folderPickerOptions={this.folderPickerOptions()}
showSearchButton={true}
showSideMenuButton={true}
/>
<NoteList style={{flex: 1}}/>
<NoteList style={this.styles().noteList}/>
{ actionButtonComp }
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
</View>
@@ -233,6 +252,7 @@ const NotesScreen = connect(
selectedFolderId: state.selectedFolderId,
selectedNoteIds: state.selectedNoteIds,
selectedTagId: state.selectedTagId,
selectedSmartFilterId: state.selectedSmartFilterId,
notesParentType: state.notesParentType,
notes: state.notes,
notesSource: state.notesSource,

View File

@@ -166,6 +166,8 @@ class SearchScreenComponent extends BaseScreenComponent {
enabled: this.props.noteSelectionEnabled,
mustSelect: true,
}}
showSideMenuButton={false}
showSearchButton={false}
/>
<View style={this.styles().body}>
<View style={this.styles().searchContainer}>

View File

@@ -1,64 +0,0 @@
const React = require('react'); const Component = React.Component;
const { View, Text, StyleSheet } = require('react-native');
const { connect } = require('react-redux');
const { ScreenHeader } = require('lib/components/screen-header.js');
const { ActionButton } = require('lib/components/action-button.js');
const { BaseScreenComponent } = require('lib/components/base-screen.js');
const { _ } = require('lib/locale.js');
const { themeStyle } = require('lib/components/global-style.js');
class WelcomeScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
constructor() {
super();
this.styles_ = {};
}
styles() {
const themeId = this.props.theme;
const theme = themeStyle(themeId);
if (this.styles_[themeId]) return this.styles_[themeId];
this.styles_ = {};
let styles = {
message: {
margin: theme.margin,
fontSize: theme.fontSize,
color: theme.color,
},
};
this.styles_[themeId] = StyleSheet.create(styles);
return this.styles_[themeId];
}
render() {
let message = this.props.folders.length ? _('Click on the (+) button to create a new note or notebook. Click on the side menu to access your existing notebooks.') : _('You currently have no notebook. Create one by clicking on (+) button.');
return (
<View style={this.rootStyle(this.props.theme).root} >
<ScreenHeader title={_('Welcome')}/>
<Text style={this.styles().message}>{message}</Text>
<ActionButton addFolderNoteButtons={true} parentFolderId={this.props.selectedFolderId}/>
</View>
);
}
}
const WelcomeScreen = connect(
(state) => {
return {
folders: state.folders,
theme: state.settings.theme,
selectedFolderId: state.selectedFolderId,
};
}
)(WelcomeScreenComponent)
module.exports = { WelcomeScreen };

View File

@@ -5,13 +5,15 @@ import DatePicker from 'react-native-datepicker'
import moment from 'moment';
import { _ } from 'lib/locale.js';
class SelectDateTimeDialog extends Component {
class SelectDateTimeDialog extends React.PureComponent {
constructor() {
super();
this.dialog_ = null;
this.shown_ = false;
this.state = { date: null };
this.onReject = this.onReject.bind(this);
}
UNSAFE_componentWillReceiveProps(newProps) {
@@ -72,6 +74,7 @@ class SelectDateTimeDialog extends Component {
ref={(dialog) => { this.dialog_ = dialog; }}
dialogTitle={<DialogTitle title={_('Set alarm')} />}
actions={popupActions}
dismissOnTouchOutside={false}
width={0.9}
height={350}
>

View File

@@ -109,12 +109,9 @@ shared.saveNoteButton_press = async function(comp, folderId = null, options = nu
const modLastSavedNote = Object.assign({}, comp.state.lastSavedNote, geoInfo);
comp.setState({ note: modNote, lastSavedNote: modLastSavedNote });
comp.refreshNoteMetadata();
});
}
comp.refreshNoteMetadata();
if (isNew) {
// Clear the newNote item now that the note has been saved, and
// make sure that the note we're editing is selected.
@@ -195,13 +192,6 @@ shared.attachedResources = async function(noteBody) {
return output;
}
shared.refreshNoteMetadata = async function(comp, force = null) {
if (force !== true && !comp.state.showNoteMetadata) return;
let noteMetadata = await Note.serializeAllProps(comp.state.note);
comp.setState({ noteMetadata: noteMetadata });
}
shared.isModified = function(comp) {
if (!comp.state.note || !comp.state.lastSavedNote) return false;
let diff = BaseModel.diffObjects(comp.state.lastSavedNote, comp.state.note);
@@ -238,11 +228,6 @@ shared.initState = async function(comp) {
comp.lastLoadedNoteId_ = note ? note.id : null;
}
shared.showMetadata_onPress = function(comp) {
comp.setState({ showNoteMetadata: !comp.state.showNoteMetadata });
comp.refreshNoteMetadata(true);
}
shared.toggleIsTodo_onPress = function(comp) {
let newNote = Note.toggleIsTodo(comp.state.note);
let newState = { note: newNote };

View File

@@ -0,0 +1,126 @@
const React = require('react'); const Component = React.Component;
const { TouchableOpacity , Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const { connect } = require('react-redux');
const Icon = require('react-native-vector-icons/Ionicons').default;
const Tag = require('lib/models/Tag.js');
const Note = require('lib/models/Note.js');
const Folder = require('lib/models/Folder.js');
const Setting = require('lib/models/Setting.js');
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
const { Synchronizer } = require('lib/synchronizer.js');
const NavService = require('lib/services/NavService.js');
const { reg } = require('lib/registry.js');
const { _ } = require('lib/locale.js');
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
const shared = require('lib/components/shared/side-menu-shared.js');
const { ActionButton } = require('lib/components/action-button.js');
class SideMenuContentNoteComponent extends Component {
constructor() {
super();
this.styles_ = {};
}
styles() {
const theme = themeStyle(this.props.theme);
if (this.styles_[this.props.theme]) return this.styles_[this.props.theme];
this.styles_ = {};
let styles = {
menu: {
flex: 1,
backgroundColor: theme.backgroundColor
},
button: {
flex: 1,
flexDirection: 'row',
height: 36,
alignItems: 'center',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
},
sidebarIcon: {
fontSize: 22,
color: theme.color,
},
};
styles.sideButton = Object.assign({}, styles.button, { flex: 0 });
styles.sideButtonDisabled = Object.assign({}, styles.sideButton, { opacity: 0.6 });
styles.sideButtonText = Object.assign({}, styles.buttonText);
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
renderDivider(key) {
return <View style={{ marginTop: 15, marginBottom: 15, flex: -1, borderBottomWidth: 1, borderBottomColor: globalStyle.dividerColor }} key={key}></View>
}
renderSideBarButton(key, title, iconName, onPressHandler) {
const theme = themeStyle(this.props.theme);
const content = (
<View key={key} style={onPressHandler ? this.styles().sideButton : this.styles().sideButtonDisabled}>
{ !iconName ? null : <Icon name={iconName} style={this.styles().sidebarIcon} /> }
<Text style={this.styles().sideButtonText}>{title}</Text>
</View>
);
if (!onPressHandler) return content;
return (
<TouchableOpacity key={key} onPress={onPressHandler}>
{content}
</TouchableOpacity>
);
}
render() {
const theme = themeStyle(this.props.theme);
let items = [];
const options = this.props.options ? this.props.options : [];
let dividerIndex = 0;
for (const option of options) {
if (option.isDivider) {
items.push(this.renderDivider('divider_' + dividerIndex++));
} else {
items.push(this.renderSideBarButton(option.title, option.title, null, option.onPress));
}
}
let style = {
flex:1,
borderRightWidth: 1,
borderRightColor: globalStyle.dividerColor,
backgroundColor: theme.backgroundColor,
paddingTop: 10,
};
return (
<View style={style}>
<View style={{flex:1, opacity: this.props.opacity}}>
<ScrollView scrollsToTop={false} style={this.styles().menu}>
{ items }
</ScrollView>
</View>
</View>
);
}
};
const SideMenuContentNote = connect(
(state) => {
return {
theme: state.settings.theme,
};
}
)(SideMenuContentNoteComponent)
module.exports = { SideMenuContentNote };

View File

@@ -1,5 +1,5 @@
const React = require('react'); const Component = React.Component;
const { TouchableOpacity , Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const { Easing, Animated, TouchableOpacity , Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const { connect } = require('react-redux');
const Icon = require('react-native-vector-icons/Ionicons').default;
const Tag = require('lib/models/Tag.js');
@@ -28,7 +28,14 @@ class SideMenuContentComponent extends Component {
this.newFolderButton_press = this.newFolderButton_press.bind(this);
this.synchronize_press = this.synchronize_press.bind(this);
this.configButton_press = this.configButton_press.bind(this);
this.allNotesButton_press = this.allNotesButton_press.bind(this);
this.renderFolderItem = this.renderFolderItem.bind(this);
this.syncIconRotationValue = new Animated.Value(0);
this.syncIconRotation = this.syncIconRotationValue.interpolate({
inputRange: [0, 1],
outputRange: ['360deg', '0deg'],
});
}
styles() {
@@ -79,12 +86,30 @@ class SideMenuContentComponent extends Component {
styles.folderIcon.paddingTop = 3;
styles.sideButton = Object.assign({}, styles.button, { flex: 0 });
styles.sideButtonSelected = Object.assign({}, styles.sideButton, { backgroundColor: theme.selectedColor });
styles.sideButtonText = Object.assign({}, styles.buttonText);
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
componentDidUpdate(prevProps) {
if (this.props.syncStarted !== prevProps.syncStarted) {
if (this.props.syncStarted) {
this.syncIconAnimation = Animated.loop(Animated.timing(this.syncIconRotationValue, {
toValue: 1,
duration: 3000,
easing: Easing.linear,
}));
this.syncIconAnimation.start();
} else {
if (this.syncIconAnimation) this.syncIconAnimation.stop();
this.syncIconAnimation = null;
}
}
}
folder_press(folder) {
this.props.dispatch({ type: 'SIDE_MENU_CLOSE' });
@@ -96,6 +121,8 @@ class SideMenuContentComponent extends Component {
}
async folder_longPress(folder) {
if (folder === 'all') return;
const buttons = [];
Alert.alert(
@@ -169,6 +196,16 @@ class SideMenuContentComponent extends Component {
NavService.go('Config');
}
allNotesButton_press() {
this.props.dispatch({ type: 'SIDE_MENU_CLOSE' });
this.props.dispatch({
type: 'NAV_GO',
routeName: 'Notes',
smartFilterId: 'c3176726992c11e9ac940492261af972',
});
}
newFolderButton_press() {
this.props.dispatch({ type: 'SIDE_MENU_CLOSE' });
@@ -192,19 +229,20 @@ class SideMenuContentComponent extends Component {
flexDirection: 'row',
height: 36,
alignItems: 'center',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
};
if (selected) folderButtonStyle.backgroundColor = theme.selectedColor;
folderButtonStyle.paddingLeft = depth * 10;
folderButtonStyle.paddingLeft = depth * 10 + theme.marginLeft;
const iconWrapperStyle = { paddingLeft: 10, paddingRight: 10 };
if (selected) iconWrapperStyle.backgroundColor = theme.selectedColor;
let iconWrapper = null;
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'md-arrow-dropdown' : 'md-arrow-dropup';
const iconComp = <Icon name={iconName} style={this.styles().folderIcon} />
const iconWrapper = !hasChildren ? null : (
iconWrapper = !hasChildren ? null : (
<TouchableOpacity style={iconWrapperStyle} folderid={folder.id} onPress={() => { if (hasChildren) this.folder_togglePress(folder) }}>
{ iconComp }
</TouchableOpacity>
@@ -222,15 +260,31 @@ class SideMenuContentComponent extends Component {
);
}
renderSideBarButton(key, title, iconName, onPressHandler) {
renderSideBarButton(key, title, iconName, onPressHandler = null, selected = false) {
const theme = themeStyle(this.props.theme);
let icon = <Icon name={iconName} style={this.styles().sidebarIcon} />
if (key === 'synchronize_button') {
icon = (
<Animated.View style={{transform: [{rotate: this.syncIconRotation}]}}>
{icon}
</Animated.View>
);
}
const content = (
<View key={key} style={selected ? this.styles().sideButtonSelected : this.styles().sideButton}>
{icon}
<Text style={this.styles().sideButtonText}>{title}</Text>
</View>
);
if (!onPressHandler) return content;
return (
<TouchableOpacity key={key} onPress={onPressHandler}>
<View style={this.styles().sideButton}>
<Icon name={iconName} style={this.styles().sidebarIcon} />
<Text style={this.styles().sideButtonText}>{title}</Text>
</View>
{content}
</TouchableOpacity>
);
}
@@ -274,8 +328,8 @@ class SideMenuContentComponent extends Component {
items.push(this.renderSideBarButton(
'synchronize_button',
!this.props.syncStarted ? _('Synchronise') : _('Cancel synchronisation'),
!this.props.syncStarted ? 'md-sync' : 'md-close',
!this.props.syncStarted ? _('Synchronise') : _('Cancel'),
'md-sync',
this.synchronize_press
));
@@ -297,6 +351,12 @@ class SideMenuContentComponent extends Component {
// using padding. So instead creating blank elements for padding bottom and top.
items.push(<View style={{ height: globalStyle.marginTop }} key='bottom_top_hack'/>);
items.push(this.renderSideBarButton('all_notes', _('All notes'), 'md-document', this.allNotesButton_press, this.props.notesParentType === 'SmartFilter'));
items.push(this.makeDivider('divider_all'));
items.push(this.renderSideBarButton('folder_header', _('Notebooks'), 'md-folder'));
if (this.props.folders.length) {
const result = shared.renderFolders(this.props, this.renderFolderItem);
const folderItems = result.items;

View File

@@ -194,6 +194,10 @@ class JoplinDatabase extends Database {
queries.push('DELETE FROM settings WHERE key="sync.5.context"');
queries.push('DELETE FROM settings WHERE key="sync.6.context"');
queries.push('DELETE FROM settings WHERE key="sync.7.context"');
queries.push('DELETE FROM settings WHERE key="revisionService.lastProcessedChangeId"');
queries.push('DELETE FROM settings WHERE key="resourceService.lastProcessedChangeId"');
queries.push('DELETE FROM settings WHERE key="searchEngine.lastProcessedChangeId"');
await this.transactionExecBatch(queries);
}

View File

@@ -250,7 +250,8 @@ class Note extends BaseItem {
}
static previewFields() {
return ['id', 'title', 'body', 'is_todo', 'todo_completed', 'parent_id', 'updated_time', 'user_updated_time', 'user_created_time', 'encryption_applied'];
// return ['id', 'title', 'body', 'is_todo', 'todo_completed', 'parent_id', 'updated_time', 'user_updated_time', 'user_created_time', 'encryption_applied'];
return ['id', 'title', 'is_todo', 'todo_completed', 'parent_id', 'updated_time', 'user_updated_time', 'user_created_time', 'encryption_applied'];
}
static previewFieldsSql(fields = null) {
@@ -602,6 +603,17 @@ class Note extends BaseItem {
return note.is_todo && !note.todo_completed && note.todo_due >= time.unixMs() && !note.is_conflict;
}
static dueDateObject(note) {
if (!!note.is_todo && note.todo_due) {
if (!this.dueDateObjects_) this.dueDateObjects_ = {};
if (this.dueDateObjects_[note.todo_due]) return this.dueDateObjects_[note.todo_due];
this.dueDateObjects_[note.todo_due] = new Date(note.todo_due);
return this.dueDateObjects_[note.todo_due];
}
return null;
}
// Tells whether the conflict between the local and remote note can be ignored.
static mustHandleConflict(localNote, remoteNote) {
// That shouldn't happen so throw an exception

View File

@@ -26,7 +26,7 @@ class ResourceService extends BaseService {
WHERE item_type = ?
AND id > ?
ORDER BY id ASC
LIMIT 100
LIMIT 10
`, [BaseModel.TYPE_NOTE, Setting.value('resourceService.lastProcessedChangeId')]);
if (!changes.length) break;

View File

@@ -7,6 +7,7 @@ const BaseModel = require('lib/BaseModel.js');
const ItemChangeUtils = require('lib/services/ItemChangeUtils');
const { pregQuote, scriptType } = require('lib/string-utils.js');
const removeDiacritics = require('diacritics').remove;
const { sprintf } = require('sprintf-js');
class SearchEngine {
@@ -91,6 +92,12 @@ class SearchEngine {
}, 10000);
}
async rebuildIndex() {
Setting.setValue('searchEngine.lastProcessedChangeId', 0)
Setting.setValue('searchEngine.initialIndexingDone', false);
return this.syncTables();
}
async syncTables() {
if (this.isIndexing_) return;
@@ -109,6 +116,11 @@ class SearchEngine {
const startTime = Date.now();
const report = {
inserted: 0,
deleted: 0,
};
let lastChangeId = Setting.value('searchEngine.lastProcessedChangeId');
try {
@@ -119,9 +131,11 @@ class SearchEngine {
WHERE item_type = ?
AND id > ?
ORDER BY id ASC
LIMIT 100
LIMIT 10
`, [BaseModel.TYPE_NOTE, lastChangeId]);
const maxRow = await ItemChange.db().selectOne('SELECT max(id) FROM item_changes');
if (!changes.length) break;
const noteIds = changes.map(a => a.item_id);
@@ -137,9 +151,11 @@ class SearchEngine {
if (note) {
const n = this.normalizeNote_(note);
queries.push({ sql: 'INSERT INTO notes_normalized(id, title, body) VALUES (?, ?, ?)', params: [change.item_id, n.title, n.body] });
report.inserted++;
}
} else if (change.type === ItemChange.TYPE_DELETE) {
queries.push({ sql: 'DELETE FROM notes_normalized WHERE id = ?', params: [change.item_id] });
report.deleted++;
} else {
throw new Error('Invalid change type: ' + change.type);
}
@@ -157,7 +173,7 @@ class SearchEngine {
await ItemChangeUtils.deleteProcessedChanges();
this.logger().info('SearchEngine: Updated FTS table in ' + (Date.now() - startTime) + 'ms');
this.logger().info(sprintf('SearchEngine: Updated FTS table in %dms. Inserted: %d. Deleted: %d', Date.now() - startTime, report.inserted, report.deleted));
this.isIndexing_ = false;
}

View File

@@ -456,6 +456,7 @@ class Api {
if ('author' in requestNote) output.author = requestNote.author;
if ('user_updated_time' in requestNote) output.user_updated_time = Database.formatValue(Database.TYPE_INT, requestNote.user_updated_time);
if ('user_created_time' in requestNote) output.user_created_time = Database.formatValue(Database.TYPE_INT, requestNote.user_created_time);
if ('is_todo' in requestNote) output.is_todo = Database.formatValue(Database.TYPE_INT, requestNote.is_todo);
return output;
}
@@ -590,4 +591,4 @@ class Api {
}
module.exports = Api;
module.exports = Api;

View File

@@ -619,12 +619,10 @@ class Synchronizer {
if (!hasAutoEnabledEncryption && content.type_ === BaseModel.TYPE_MASTER_KEY && !masterKeysBefore) {
hasAutoEnabledEncryption = true;
this.logger().info("One master key was downloaded and none was previously available: automatically enabling encryption");
this.logger().info("Using master key: ", content);
this.logger().info("Using master key: ", content.id);
await this.encryptionService().enableEncryption(content);
await this.encryptionService().loadMasterKeysFromSettings();
this.logger().info(
"Encryption has been enabled with downloaded master key as active key. However, note that no password was initially supplied. It will need to be provided by user."
);
this.logger().info("Encryption has been enabled with downloaded master key as active key. However, note that no password was initially supplied. It will need to be provided by user.");
}
if (!!content.encryption_applied) this.dispatch({ type: "SYNC_GOT_ENCRYPTED_ITEM" });

View File

@@ -37,7 +37,6 @@ const { ConfigScreen } = require('lib/components/screens/config.js');
const { FolderScreen } = require('lib/components/screens/folder.js');
const { LogScreen } = require('lib/components/screens/log.js');
const { StatusScreen } = require('lib/components/screens/status.js');
const { WelcomeScreen } = require('lib/components/screens/welcome.js');
const { SearchScreen } = require('lib/components/screens/search.js');
const { OneDriveLoginScreen } = require('lib/components/screens/onedrive-login.js');
const { EncryptionConfigScreen } = require('lib/components/screens/encryption-config.js');
@@ -46,6 +45,7 @@ const Setting = require('lib/models/Setting.js');
const { MenuContext } = require('react-native-popup-menu');
const { SideMenu } = require('lib/components/side-menu.js');
const { SideMenuContent } = require('lib/components/side-menu-content.js');
const { SideMenuContentNote } = require('lib/components/side-menu-content-note.js');
const { DatabaseDriverReactNative } = require('lib/database-driver-react-native');
const { reg } = require('lib/registry.js');
const { _, setLocale, closestSupportedLocale, defaultLocale } = require('lib/locale.js');
@@ -167,14 +167,17 @@ function historyCanGoBackTo(route, nextRoute) {
return true;
}
const DEFAULT_ROUTE = {
type: 'NAV_GO',
routeName: 'Notes',
smartFilterId: 'c3176726992c11e9ac940492261af972',
};
const appDefaultState = Object.assign({}, defaultState, {
sideMenuOpenPercent: 0,
route: {
type: 'NAV_GO',
routeName: 'Welcome',
params: {},
},
route: DEFAULT_ROUTE,
noteSelectionEnabled: false,
noteSideMenuOptions: null,
});
const appReducer = (state = appDefaultState, action) => {
@@ -229,8 +232,6 @@ const appReducer = (state = appDefaultState, action) => {
}
}
if (action.routeName == 'Welcome') navHistory = [];
//reg.logger().info('Route: ' + currentRouteName + ' => ' + action.routeName);
newState = Object.assign({}, state);
@@ -249,6 +250,11 @@ const appReducer = (state = appDefaultState, action) => {
newState.notesParentType = 'Tag';
}
if ('smartFilterId' in action) {
newState.smartFilterId = action.smartFilterId;
newState.notesParentType = 'SmartFilter';
}
if ('itemType' in action) {
newState.selectedItemType = action.itemType;
}
@@ -321,6 +327,11 @@ const appReducer = (state = appDefaultState, action) => {
newState.selectedNoteIds = [];
break;
case 'NOTE_SIDE_MENU_OPTIONS_SET':
newState = Object.assign({}, state);
newState.noteSideMenuOptions = action.options;
break;
}
} catch (error) {
@@ -495,10 +506,7 @@ async function initialize(dispatch) {
});
if (!folder) {
dispatch({
type: 'NAV_GO',
routeName: 'Welcome',
});
dispatch(DEFAULT_ROUTE);
} else {
dispatch({
type: 'NAV_GO',
@@ -684,10 +692,17 @@ class AppComponent extends React.Component {
if (this.props.appState != 'ready') return null;
const theme = themeStyle(this.props.theme);
const sideMenuContent = <SafeAreaView style={{flex:1, backgroundColor: theme.backgroundColor}}><SideMenuContent/></SafeAreaView>;
let sideMenuContent = null;
let menuPosition = 'left';
if (this.props.routeName === 'Note') {
sideMenuContent = <SafeAreaView style={{flex:1, backgroundColor: theme.backgroundColor}}><SideMenuContentNote options={this.props.noteSideMenuOptions}/></SafeAreaView>;
menuPosition = 'right';
} else {
sideMenuContent = <SafeAreaView style={{flex:1, backgroundColor: theme.backgroundColor}}><SideMenuContent/></SafeAreaView>;
}
const appNavInit = {
Welcome: { screen: WelcomeScreen },
Notes: { screen: NotesScreen },
Note: { screen: NoteScreen },
Tags: { screen: TagsScreen },
@@ -704,6 +719,7 @@ class AppComponent extends React.Component {
return (
<SideMenu
menu={sideMenuContent}
menuPosition={menuPosition}
onChange={(isOpen) => this.sideMenu_change(isOpen)}
onSliding={(percent) => {
this.props.dispatch({
@@ -733,7 +749,9 @@ const mapStateToProps = (state) => {
appState: state.appState,
noteSelectionEnabled: state.noteSelectionEnabled,
selectedFolderId: state.selectedFolderId,
theme: state.settings.theme
routeName: state.route.routeName,
theme: state.settings.theme,
noteSideMenuOptions: state.noteSideMenuOptions,
};
};

View File

@@ -478,6 +478,11 @@ function renderFileToHtml(sourcePath, targetPath, params) {
function makeHomePageMd() {
let md = fs.readFileSync(rootDir + '/README.md', 'utf8');
md = md.replace(tocRegex_, '');
// HACK: GitHub needs the \| or the inline code won't be displayed correctly inside the table,
// while MarkdownIt doesn't and will in fact display the \. So we remove it here.
md = md.replace(/\\\| bash/g, '| bash');
return md;
}

View File

@@ -550,7 +550,7 @@
<h2><a name="v1-0-119-https-github-com-laurent22-joplin-releases-tag-v1-0-119-2018-12-18t12-40-22z" href="#v1-0-119-https-github-com-laurent22-joplin-releases-tag-v1-0-119-2018-12-18t12-40-22z" class="heading-anchor">🔗</a><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.119">v1.0.119</a> - 2018-12-18T12:40:22Z</h2>
<p>Important: This release might be slow on startup due to the need to index all the notes, especially if you have many of them with lots of content. The best is simply to wait for it even if it takes several minutes. This is just a one off and afterwards startup time will be the same as before.</p>
<ul>
<li>New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See <a href="https://joplin.cozic.net/#searching">https://joplin.cozic.net/#searching</a> for more info.</li>
<li>New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See <a href="https://joplinapp.org/#searching">https://joplinapp.org/#searching</a> for more info.</li>
<li>New: Search within current note (Ctrl+F).</li>
<li>New: Add separate editor font size option (<a href="https://github.com/laurent22/joplin/issues/1027">#1027</a>)</li>
<li>Changed: Changed global search shortcut to F6.</li>
@@ -563,7 +563,7 @@
<h2><a name="v1-0-118-https-github-com-laurent22-joplin-releases-tag-v1-0-118-2019-01-11t08-34-13z" href="#v1-0-118-https-github-com-laurent22-joplin-releases-tag-v1-0-118-2019-01-11t08-34-13z" class="heading-anchor">🔗</a><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.118">v1.0.118</a> - 2019-01-11T08:34:13Z</h2>
<p>Important: This release might be slow on startup due to the need to index all the notes, especially if you have many of them with lots of content. The best is simply to wait for it even if it takes several minutes. This is just a one off and afterwards startup time will be the same as before.</p>
<ul>
<li>New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See <a href="https://joplin.cozic.net/#searching">https://joplin.cozic.net/#searching</a> for more info.</li>
<li>New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See <a href="https://joplinapp.org/#searching">https://joplinapp.org/#searching</a> for more info.</li>
<li>New: Search within current note (Ctrl+F).</li>
<li>New: Add separate editor font size option (<a href="https://github.com/laurent22/joplin/issues/1027">#1027</a>)</li>
<li>Changed: Changed global search shortcut to F6.</li>
@@ -764,7 +764,7 @@
</ul>
<h2><a name="v1-0-93-https-github-com-laurent22-joplin-releases-tag-v1-0-93-2018-05-14t11-36-01z" href="#v1-0-93-https-github-com-laurent22-joplin-releases-tag-v1-0-93-2018-05-14t11-36-01z" class="heading-anchor">🔗</a><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.93">v1.0.93</a> - 2018-05-14T11:36:01Z</h2>
<ul>
<li>New: A portable version is now available. To install it simply copy the file &quot;JoplinPortable.exe&quot; to your USB device. See the documentation for more information - <a href="https://joplin.cozic.net/#desktop-applications">https://joplin.cozic.net/#desktop-applications</a></li>
<li>New: A portable version is now available. To install it simply copy the file &quot;JoplinPortable.exe&quot; to your USB device. See the documentation for more information - <a href="https://joplinapp.org/#desktop-applications">https://joplinapp.org/#desktop-applications</a></li>
<li>Improved: Made import of ENEX files more robust and accurate</li>
<li>Improved: Auto-update process should be more reliable.</li>
<li>Fixed: Made sync-after-save interval longer to made synchronisations less frequent.</li>
@@ -781,7 +781,7 @@
</ul>
<h2><a name="v1-0-89-https-github-com-laurent22-joplin-releases-tag-v1-0-89-2018-05-09t13-05-05z" href="#v1-0-89-https-github-com-laurent22-joplin-releases-tag-v1-0-89-2018-05-09t13-05-05z" class="heading-anchor">🔗</a><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.89">v1.0.89</a> - 2018-05-09T13:05:05Z</h2>
<ul>
<li>New: Resolves <a href="https://github.com/laurent22/joplin/issues/122">#122</a>: Added support for sub-notebooks. Please see doc for more info: <a href="https://joplin.cozic.net/#sub-notebooks">https://joplin.cozic.net/#sub-notebooks</a></li>
<li>New: Resolves <a href="https://github.com/laurent22/joplin/issues/122">#122</a>: Added support for sub-notebooks. Please see doc for more info: <a href="https://joplinapp.org/#sub-notebooks">https://joplinapp.org/#sub-notebooks</a></li>
<li>Improved: Export/Import links to notes</li>
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/480">#480</a>: Ignore invalid flag automatically passed by macOS</li>
<li>Fixes <a href="https://github.com/laurent22/joplin/issues/61">#61</a>: Handle path that ends with slash for file system sync</li>

View File

@@ -300,7 +300,7 @@
<h1><a name="creating-a-low-level-bug-report-on-ios" href="#creating-a-low-level-bug-report-on-ios" class="heading-anchor">🔗</a>Creating a low-level bug report on iOS</h1>
<p>Some crashes cannot be investigated using Joplin's own tools. In that case, it can be very helpful to provide a native iOS crash report.</p>
<p>For this, please follow these instructions:</p>
<p>You can send it to this address <a href="https://raw.githubusercontent.com/laurent22/joplin/master/Assets/Adresse.png">https://raw.githubusercontent.com/laurent22/joplin/master/Assets/Adresse.png</a></p>
<p>You can send it to this address <a href="https://raw.githubusercontent.com/laurent22/joplin/master/Assets/AdresseSupport.png">https://raw.githubusercontent.com/laurent22/joplin/master/Assets/AdresseSupport.png</a></p>
<p><a href="https://developer.apple.com/library/content/qa/qa1747/_index.html">https://developer.apple.com/library/content/qa/qa1747/_index.html</a></p>
<p>Getting Crash Logs Directly From a Device Without Xcode</p>
<p>Your users can retrieve crash reports from their device and send them to you via email by following these instructions.</p>

View File

@@ -300,7 +300,7 @@
<tr>
<td>Linux</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.160/Joplin-1.0.160-x86_64.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
<td>An Arch Linux package <a href="#terminal-application">is also available</a>.<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, Gnome and Mint), the recommended way is to use this script as it will handle the desktop icon too:<br><br> <code>wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_install_and_update.sh \| bash</code></td>
<td>An Arch Linux package <a href="#terminal-application">is also available</a>.<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, Gnome and Mint), the recommended way is to use this script as it will handle the desktop icon too:<br><br> <code>wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_install_and_update.sh | bash</code></td>
</tr>
</tbody>
</table>
@@ -641,7 +641,7 @@ $$
<li>Also see here for information about <a href="https://discourse.joplinapp.org/c/news">the latest releases and general news</a>.</li>
<li>For bug reports and feature requests, go to the <a href="https://github.com/laurent22/joplin/issues">GitHub Issue Tracker</a>.</li>
<li>The latest news are posted <a href="https://www.patreon.com/joplin">on the Patreon page</a>.</li>
<li>You can also follow us on <a href="https://twitter.com/joplinapp">the Twitter feed</a>.</li>
<li>You can also follow us on <a rel="me" href="https://mastodon.social/@joplinapp">the Mastodon feed</a> or <a href="https://twitter.com/joplinapp">the Twitter feed</a>.</li>
</ul>
<h1><a name="contributing" href="#contributing" class="heading-anchor">🔗</a>Contributing</h1>
<p>Please see the guide for information on how to contribute to the development of Joplin: <a href="https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md">https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md</a></p>
@@ -651,7 +651,7 @@ $$
<li><a href="https://poedit.net/">Download Poedit</a>, the translation editor, and install it.</li>
<li><a href="https://raw.githubusercontent.com/laurent22/joplin/master/CliClient/locales/joplin.pot">Download the file to be translated</a>.</li>
<li>In Poedit, open this .pot file, go into the Catalog menu and click Configuration. Change &quot;Country&quot; and &quot;Language&quot; to your own country and language.</li>
<li>From then you can translate the file. Once it is done, please either <a href="https://github.com/laurent22/joplin/pulls">open a pull request</a> or send the file to <a href="https://raw.githubusercontent.com/laurent22/joplin/master/Assets/Adresse.png">this address</a>.</li>
<li>From then you can translate the file. Once it is done, please either <a href="https://github.com/laurent22/joplin/pulls">open a pull request</a> or send the file to <a href="https://raw.githubusercontent.com/laurent22/joplin/master/Assets/AdresseTranslation.png">this address</a>.</li>
</ul>
<p>This translation will apply to the three applications - desktop, mobile and terminal.</p>
<p>To <strong>update a translation</strong>, follow the same steps as above but instead of getting the .pot file, get the .po file for your language from the table below.</p>

View File

@@ -280,15 +280,15 @@
<tbody>
<tr>
<td>Total Windows downloads</td>
<td>279,497</td>
<td>291,223</td>
</tr>
<tr>
<td>Total macOs downloads</td>
<td>119,042</td>
<td>122,809</td>
</tr>
<tr>
<td>Total Linux downloads</td>
<td>93,494</td>
<td>96,536</td>
</tr>
<tr>
<td>Windows %</td>
@@ -319,34 +319,34 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.160">v1.0.160</a></td>
<td>2019-06-15T00:21:40Z</td>
<td>381</td>
<td>117</td>
<td>57</td>
<td>555</td>
<td>11,629</td>
<td>3,795</td>
<td>2,992</td>
<td>18,416</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.159">v1.0.159</a></td>
<td>2019-06-08T00:00:19Z</td>
<td>5,046</td>
<td>2,092</td>
<td>1,055</td>
<td>8,193</td>
<td>5,122</td>
<td>2,137</td>
<td>1,071</td>
<td>8,330</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.158">v1.0.158</a></td>
<td>2019-05-27T19:01:18Z</td>
<td>9,541</td>
<td>3,478</td>
<td>9,741</td>
<td>3,484</td>
<td>1,915</td>
<td>14,934</td>
<td>15,140</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.157">v1.0.157</a></td>
<td>2019-05-26T17:55:53Z</td>
<td>2,127</td>
<td>2,133</td>
<td>808</td>
<td>272</td>
<td>3,207</td>
<td>3,213</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.153">v1.0.153</a></td>
@@ -359,10 +359,10 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.152">v1.0.152</a></td>
<td>2019-05-13T09:08:07Z</td>
<td>13,722</td>
<td>4,373</td>
<td>13,750</td>
<td>4,380</td>
<td>4,045</td>
<td>22,140</td>
<td>22,175</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.151">v1.0.151</a></td>
@@ -385,40 +385,40 @@
<td>2019-05-08T19:12:24Z</td>
<td>111</td>
<td>36</td>
<td>77</td>
<td>224</td>
<td>78</td>
<td>225</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.145">v1.0.145</a></td>
<td>2019-05-03T09:16:53Z</td>
<td>6,868</td>
<td>6,877</td>
<td>2,830</td>
<td>1,425</td>
<td>11,123</td>
<td>11,132</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.143">v1.0.143</a></td>
<td>2019-04-22T10:51:38Z</td>
<td>11,861</td>
<td>3,512</td>
<td>11,862</td>
<td>3,513</td>
<td>2,765</td>
<td>18,138</td>
<td>18,140</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.142">v1.0.142</a></td>
<td>2019-04-02T16:44:51Z</td>
<td>14,494</td>
<td>14,503</td>
<td>4,511</td>
<td>4,708</td>
<td>23,713</td>
<td>4,710</td>
<td>23,724</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.140">v1.0.140</a></td>
<td>2019-03-10T20:59:58Z</td>
<td>13,535</td>
<td>4,120</td>
<td>2,995</td>
<td>20,650</td>
<td>13,557</td>
<td>4,122</td>
<td>2,999</td>
<td>20,678</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.139">v1.0.139</a></td>
@@ -447,10 +447,10 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.135">v1.0.135</a></td>
<td>2019-02-27T23:36:57Z</td>
<td>12,192</td>
<td>12,214</td>
<td>3,915</td>
<td>4,045</td>
<td>20,152</td>
<td>20,174</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.134">v1.0.134</a></td>
@@ -471,10 +471,10 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.127">v1.0.127</a></td>
<td>2019-02-14T23:12:48Z</td>
<td>9,429</td>
<td>9,452</td>
<td>3,127</td>
<td>2,905</td>
<td>15,461</td>
<td>15,484</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.126">v1.0.126</a></td>
@@ -495,34 +495,34 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.120">v1.0.120</a></td>
<td>2019-01-10T21:42:53Z</td>
<td>15,557</td>
<td>15,571</td>
<td>5,164</td>
<td>6,489</td>
<td>27,210</td>
<td>27,224</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.119">v1.0.119</a></td>
<td>2018-12-18T12:40:22Z</td>
<td>8,857</td>
<td>3,203</td>
<td>8,861</td>
<td>3,205</td>
<td>1,994</td>
<td>14,054</td>
<td>14,060</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.118">v1.0.118</a></td>
<td>2019-01-11T08:34:13Z</td>
<td>678</td>
<td>682</td>
<td>215</td>
<td>75</td>
<td>968</td>
<td>972</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.117">v1.0.117</a></td>
<td>2018-11-24T12:05:24Z</td>
<td>16,210</td>
<td>16,214</td>
<td>4,849</td>
<td>6,359</td>
<td>27,418</td>
<td>27,422</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.116">v1.0.116</a></td>
@@ -535,26 +535,26 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.115">v1.0.115</a></td>
<td>2018-11-16T16:52:02Z</td>
<td>3,630</td>
<td>3,632</td>
<td>1,280</td>
<td>784</td>
<td>5,694</td>
<td>5,696</td>
</tr>
<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>11,369</td>
<td>11,371</td>
<td>3,475</td>
<td>3,822</td>
<td>18,666</td>
<td>18,668</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>11,892</td>
<td>3,135</td>
<td>11,905</td>
<td>3,139</td>
<td>3,653</td>
<td>18,680</td>
<td>18,697</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.110">v1.0.110</a></td>
@@ -583,42 +583,42 @@
<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>7,129</td>
<td>7,133</td>
<td>2,117</td>
<td>1,699</td>
<td>10,945</td>
<td>10,949</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>4,531</td>
<td>4,535</td>
<td>1,440</td>
<td>309</td>
<td>6,280</td>
<td>6,284</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>4,595</td>
<td>4,599</td>
<td>1,554</td>
<td>1,441</td>
<td>7,590</td>
<td>7,594</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>14,992</td>
<td>14,995</td>
<td>4,656</td>
<td>7,105</td>
<td>26,753</td>
<td>7,128</td>
<td>26,779</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>2,016</td>
<td>2,022</td>
<td>859</td>
<td>668</td>
<td>3,543</td>
<td>3,549</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.101">v1.0.101</a></td>
@@ -657,8 +657,8 @@
<td>2018-05-26T16:36:39Z</td>
<td>2,688</td>
<td>1,200</td>
<td>1,277</td>
<td>5,165</td>
<td>1,288</td>
<td>5,176</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.95">v1.0.95</a></td>
@@ -680,9 +680,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>1,770</td>
<td>928</td>
<td>933</td>
<td>743</td>
<td>3,441</td>
<td>3,446</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.91">v1.0.91</a></td>
@@ -711,10 +711,10 @@
<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>4,575</td>
<td>2,444</td>
<td>4,582</td>
<td>2,448</td>
<td>2,640</td>
<td>9,659</td>
<td>9,670</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.82">v1.0.82</a></td>
@@ -736,9 +736,9 @@
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.79">v1.0.79</a></td>
<td>2018-03-23T18:00:11Z</td>
<td>920</td>
<td>516</td>
<td>518</td>
<td>361</td>
<td>1,797</td>
<td>1,799</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.78">v1.0.78</a></td>
@@ -769,8 +769,8 @@
<td>2018-02-28T20:04:30Z</td>
<td>1,845</td>
<td>1,031</td>
<td>1,233</td>
<td>4,109</td>
<td>1,235</td>
<td>4,111</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.67">v1.0.67</a></td>
@@ -793,8 +793,8 @@
<td>2018-02-17T20:02:25Z</td>
<td>186</td>
<td>110</td>
<td>120</td>
<td>416</td>
<td>122</td>
<td>418</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.64">v1.0.64</a></td>
@@ -817,16 +817,16 @@
<td>2018-02-12T20:19:58Z</td>
<td>550</td>
<td>281</td>
<td>358</td>
<td>1,189</td>
<td>359</td>
<td>1,190</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v0.10.61">v0.10.61</a></td>
<td>2018-02-08T18:27:39Z</td>
<td>964</td>
<td>609</td>
<td>611</td>
<td>947</td>
<td>2,520</td>
<td>2,522</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v0.10.60">v0.10.60</a></td>
@@ -903,10 +903,10 @@
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v0.10.39">v0.10.39</a></td>
<td>2017-12-11T21:19:44Z</td>
<td>5,546</td>
<td>4,034</td>
<td>2,943</td>
<td>12,523</td>
<td>5,557</td>
<td>4,043</td>
<td>2,953</td>
<td>12,553</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v0.10.38">v0.10.38</a></td>
@@ -993,8 +993,8 @@
<td>2017-11-24T14:27:49Z</td>
<td>139</td>
<td>679</td>
<td>5,555</td>
<td>6,373</td>
<td>5,590</td>
<td>6,408</td>
</tr>
<tr>
<td><a href="https://github.com/laurent22/joplin/releases/tag/v0.10.23">v0.10.23</a></td>

View File

@@ -295,7 +295,7 @@ This big release aims at improving the overall usability of the application and
Important: This release might be slow on startup due to the need to index all the notes, especially if you have many of them with lots of content. The best is simply to wait for it even if it takes several minutes. This is just a one off and afterwards startup time will be the same as before.
- New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See https://joplin.cozic.net/#searching for more info.
- New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See https://joplinapp.org/#searching for more info.
- New: Search within current note (Ctrl+F).
- New: Add separate editor font size option ([#1027](https://github.com/laurent22/joplin/issues/1027))
- Changed: Changed global search shortcut to F6.
@@ -309,7 +309,7 @@ Important: This release might be slow on startup due to the need to index all th
Important: This release might be slow on startup due to the need to index all the notes, especially if you have many of them with lots of content. The best is simply to wait for it even if it takes several minutes. This is just a one off and afterwards startup time will be the same as before.
- New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See https://joplin.cozic.net/#searching for more info.
- New: Fast full text search engine. Works with multiple terms, support for prefixes, can restrict search to either note title or body. See https://joplinapp.org/#searching for more info.
- New: Search within current note (Ctrl+F).
- New: Add separate editor font size option ([#1027](https://github.com/laurent22/joplin/issues/1027))
- Changed: Changed global search shortcut to F6.
@@ -523,7 +523,7 @@ This release is mainly to fix various issues with the recently released Web Clip
## [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) - 2018-05-14T11:36:01Z
- New: A portable version is now available. To install it simply copy the file "JoplinPortable.exe" to your USB device. See the documentation for more information - https://joplin.cozic.net/#desktop-applications
- New: A portable version is now available. To install it simply copy the file "JoplinPortable.exe" to your USB device. See the documentation for more information - https://joplinapp.org/#desktop-applications
- Improved: Made import of ENEX files more robust and accurate
- Improved: Auto-update process should be more reliable.
- Fixed: Made sync-after-save interval longer to made synchronisations less frequent.
@@ -541,7 +541,7 @@ Same as v1.0.90 but with a fix for [#510](https://github.com/laurent22/joplin/is
## [v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) - 2018-05-09T13:05:05Z
- New: Resolves [#122](https://github.com/laurent22/joplin/issues/122): Added support for sub-notebooks. Please see doc for more info: https://joplin.cozic.net/#sub-notebooks
- New: Resolves [#122](https://github.com/laurent22/joplin/issues/122): Added support for sub-notebooks. Please see doc for more info: https://joplinapp.org/#sub-notebooks
- Improved: Export/Import links to notes
- Fixes [#480](https://github.com/laurent22/joplin/issues/480): Ignore invalid flag automatically passed by macOS
- Fixes [#61](https://github.com/laurent22/joplin/issues/61): Handle path that ends with slash for file system sync

View File

@@ -37,7 +37,7 @@ Some crashes cannot be investigated using Joplin's own tools. In that case, it c
For this, please follow these instructions:
You can send it to this address https://raw.githubusercontent.com/laurent22/joplin/master/Assets/Adresse.png
You can send it to this address https://raw.githubusercontent.com/laurent22/joplin/master/Assets/AdresseSupport.png
https://developer.apple.com/library/content/qa/qa1747/_index.html

View File

@@ -2,79 +2,79 @@
Name | Value
--- | ---
Total Windows downloads | 279,497
Total macOs downloads | 119,042
Total Linux downloads | 93,494
Total Windows downloads | 291,223
Total macOs downloads | 122,809
Total Linux downloads | 96,536
Windows % | 57%
macOS % | 24%
Linux % | 19%
Version | Date | Windows | macOS | Linux | Total
--- | --- | --- | --- | --- | ---
[v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 381 | 117 | 57 | 555
[v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,046 | 2,092 | 1,055 | 8,193
[v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,541 | 3,478 | 1,915 | 14,934
[v1.0.157](https://github.com/laurent22/joplin/releases/tag/v1.0.157) | 2019-05-26T17:55:53Z | 2,127 | 808 | 272 | 3,207
[v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 11,629 | 3,795 | 2,992 | 18,416
[v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,122 | 2,137 | 1,071 | 8,330
[v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,741 | 3,484 | 1,915 | 15,140
[v1.0.157](https://github.com/laurent22/joplin/releases/tag/v1.0.157) | 2019-05-26T17:55:53Z | 2,133 | 808 | 272 | 3,213
[v1.0.153](https://github.com/laurent22/joplin/releases/tag/v1.0.153) | 2019-05-15T06:27:29Z | 822 | 73 | 94 | 989
[v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,722 | 4,373 | 4,045 | 22,140
[v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,750 | 4,380 | 4,045 | 22,175
[v1.0.151](https://github.com/laurent22/joplin/releases/tag/v1.0.151) | 2019-05-12T15:14:32Z | 1,927 | 511 | 947 | 3,385
[v1.0.150](https://github.com/laurent22/joplin/releases/tag/v1.0.150) | 2019-05-12T11:27:48Z | 395 | 109 | 56 | 560
[v1.0.148](https://github.com/laurent22/joplin/releases/tag/v1.0.148) | 2019-05-08T19:12:24Z | 111 | 36 | 77 | 224
[v1.0.145](https://github.com/laurent22/joplin/releases/tag/v1.0.145) | 2019-05-03T09:16:53Z | 6,868 | 2,830 | 1,425 | 11,123
[v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,861 | 3,512 | 2,765 | 18,138
[v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,494 | 4,511 | 4,708 | 23,713
[v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,535 | 4,120 | 2,995 | 20,650
[v1.0.148](https://github.com/laurent22/joplin/releases/tag/v1.0.148) | 2019-05-08T19:12:24Z | 111 | 36 | 78 | 225
[v1.0.145](https://github.com/laurent22/joplin/releases/tag/v1.0.145) | 2019-05-03T09:16:53Z | 6,877 | 2,830 | 1,425 | 11,132
[v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,862 | 3,513 | 2,765 | 18,140
[v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,503 | 4,511 | 4,710 | 23,724
[v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,557 | 4,122 | 2,999 | 20,678
[v1.0.139](https://github.com/laurent22/joplin/releases/tag/v1.0.139) | 2019-03-09T10:06:48Z | 83 | 20 | 25 | 128
[v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) | 2019-03-03T17:23:00Z | 113 | 42 | 68 | 223
[v1.0.137](https://github.com/laurent22/joplin/releases/tag/v1.0.137) | 2019-03-03T01:12:51Z | 547 | 26 | 68 | 641
[v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,192 | 3,915 | 4,045 | 20,152
[v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,214 | 3,915 | 4,045 | 20,174
[v1.0.134](https://github.com/laurent22/joplin/releases/tag/v1.0.134) | 2019-02-27T10:21:44Z | 1,431 | 532 | 201 | 2,164
[v1.0.132](https://github.com/laurent22/joplin/releases/tag/v1.0.132) | 2019-02-26T23:02:05Z | 1,046 | 411 | 79 | 1,536
[v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 9,429 | 3,127 | 2,905 | 15,461
[v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 9,452 | 3,127 | 2,905 | 15,484
[v1.0.126](https://github.com/laurent22/joplin/releases/tag/v1.0.126) | 2019-02-09T19:46:16Z | 914 | 53 | 109 | 1,076
[v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,230 | 3,522 | 1,693 | 15,445
[v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,557 | 5,164 | 6,489 | 27,210
[v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 8,857 | 3,203 | 1,994 | 14,054
[v1.0.118](https://github.com/laurent22/joplin/releases/tag/v1.0.118) | 2019-01-11T08:34:13Z | 678 | 215 | 75 | 968
[v1.0.117](https://github.com/laurent22/joplin/releases/tag/v1.0.117) | 2018-11-24T12:05:24Z | 16,210 | 4,849 | 6,359 | 27,418
[v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,571 | 5,164 | 6,489 | 27,224
[v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 8,861 | 3,205 | 1,994 | 14,060
[v1.0.118](https://github.com/laurent22/joplin/releases/tag/v1.0.118) | 2019-01-11T08:34:13Z | 682 | 215 | 75 | 972
[v1.0.117](https://github.com/laurent22/joplin/releases/tag/v1.0.117) | 2018-11-24T12:05:24Z | 16,214 | 4,849 | 6,359 | 27,422
[v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 3,458 | 1,087 | 704 | 5,249
[v1.0.115](https://github.com/laurent22/joplin/releases/tag/v1.0.115) | 2018-11-16T16:52:02Z | 3,630 | 1,280 | 784 | 5,694
[v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | 11,369 | 3,475 | 3,822 | 18,666
[v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 11,892 | 3,135 | 3,653 | 18,680
[v1.0.115](https://github.com/laurent22/joplin/releases/tag/v1.0.115) | 2018-11-16T16:52:02Z | 3,632 | 1,280 | 784 | 5,696
[v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | 11,371 | 3,475 | 3,822 | 18,668
[v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 11,905 | 3,139 | 3,653 | 18,697
[v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 926 | 376 | 103 | 1,405
[v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 2,074 | 681 | 314 | 3,069
[v1.0.108](https://github.com/laurent22/joplin/releases/tag/v1.0.108) | 2018-09-29T18:49:29Z | 13 | 6 | 6 | 25
[v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 7,129 | 2,117 | 1,699 | 10,945
[v1.0.106](https://github.com/laurent22/joplin/releases/tag/v1.0.106) | 2018-09-08T15:23:40Z | 4,531 | 1,440 | 309 | 6,280
[v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4,595 | 1,554 | 1,441 | 7,590
[v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 14,992 | 4,656 | 7,105 | 26,753
[v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2,016 | 859 | 668 | 3,543
[v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 7,133 | 2,117 | 1,699 | 10,949
[v1.0.106](https://github.com/laurent22/joplin/releases/tag/v1.0.106) | 2018-09-08T15:23:40Z | 4,535 | 1,440 | 309 | 6,284
[v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4,599 | 1,554 | 1,441 | 7,594
[v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 14,995 | 4,656 | 7,128 | 26,779
[v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2,022 | 859 | 668 | 3,549
[v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1,290 | 581 | 401 | 2,272
[v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 857 | 410 | 228 | 1,495
[v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,238 | 581 | 372 | 2,191
[v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 297 | 138 | 54 | 489
[v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,688 | 1,200 | 1,277 | 5,165
[v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,688 | 1,200 | 1,288 | 5,176
[v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 387 | 190 | 87 | 664
[v1.0.94](https://github.com/laurent22/joplin/releases/tag/v1.0.94) | 2018-05-21T20:52:59Z | 1,099 | 557 | 362 | 2,018
[v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,770 | 928 | 743 | 3,441
[v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,770 | 933 | 743 | 3,446
[v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 816 | 536 | 290 | 1,642
[v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) | 2018-05-09T13:05:05Z | 476 | 212 | 97 | 785
[v1.0.85](https://github.com/laurent22/joplin/releases/tag/v1.0.85) | 2018-05-01T21:08:24Z | 1,641 | 934 | 617 | 3,192
[v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 4,575 | 2,444 | 2,640 | 9,659
[v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 4,582 | 2,448 | 2,640 | 9,670
[v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 686 | 388 | 106 | 1,180
[v1.0.81](https://github.com/laurent22/joplin/releases/tag/v1.0.81) | 2018-03-28T08:13:58Z | 986 | 572 | 754 | 2,312
[v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 920 | 516 | 361 | 1,797
[v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 920 | 518 | 361 | 1,799
[v1.0.78](https://github.com/laurent22/joplin/releases/tag/v1.0.78) | 2018-03-17T15:27:18Z | 1,303 | 845 | 853 | 3,001
[v1.0.77](https://github.com/laurent22/joplin/releases/tag/v1.0.77) | 2018-03-16T15:12:35Z | 166 | 89 | 29 | 284
[v1.0.72](https://github.com/laurent22/joplin/releases/tag/v1.0.72) | 2018-03-14T09:44:35Z | 397 | 238 | 41 | 676
[v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 1,845 | 1,031 | 1,233 | 4,109
[v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 1,845 | 1,031 | 1,235 | 4,111
[v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,806 | 585 | 0 | 2,391
[v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) | 2018-02-18T23:09:09Z | 315 | 109 | 74 | 498
[v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 186 | 110 | 120 | 416
[v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 186 | 110 | 122 | 418
[v1.0.64](https://github.com/laurent22/joplin/releases/tag/v1.0.64) | 2018-02-16T00:58:20Z | 1,076 | 531 | 1,117 | 2,724
[v1.0.63](https://github.com/laurent22/joplin/releases/tag/v1.0.63) | 2018-02-14T19:40:36Z | 292 | 145 | 84 | 521
[v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 550 | 281 | 358 | 1,189
[v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 964 | 609 | 947 | 2,520
[v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 550 | 281 | 359 | 1,190
[v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 964 | 611 | 947 | 2,522
[v0.10.60](https://github.com/laurent22/joplin/releases/tag/v0.10.60) | 2018-02-06T13:09:56Z | 713 | 503 | 545 | 1,761
[v0.10.54](https://github.com/laurent22/joplin/releases/tag/v0.10.54) | 2018-01-31T20:21:30Z | 1,813 | 1,444 | 311 | 3,568
[v0.10.52](https://github.com/laurent22/joplin/releases/tag/v0.10.52) | 2018-01-31T19:25:18Z | 38 | 618 | 7 | 663
@@ -84,7 +84,7 @@ Version | Date | Windows | macOS | Linux | Total
[v0.10.43](https://github.com/laurent22/joplin/releases/tag/v0.10.43) | 2018-01-08T10:12:10Z | 3,428 | 2,332 | 1,200 | 6,960
[v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,030 | 1,534 | 231 | 2,795
[v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,587 | 1,756 | 329 | 3,672
[v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,546 | 4,034 | 2,943 | 12,523
[v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,557 | 4,043 | 2,953 | 12,553
[v0.10.38](https://github.com/laurent22/joplin/releases/tag/v0.10.38) | 2017-12-08T10:12:06Z | 1,041 | 1,213 | 299 | 2,553
[v0.10.37](https://github.com/laurent22/joplin/releases/tag/v0.10.37) | 2017-12-07T19:38:05Z | 256 | 829 | 74 | 1,159
[v0.10.36](https://github.com/laurent22/joplin/releases/tag/v0.10.36) | 2017-12-05T09:34:40Z | 1,008 | 1,340 | 431 | 2,779
@@ -95,7 +95,7 @@ Version | Date | Windows | macOS | Linux | Total
[v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 711 | 1,352 | 410 | 2,473
[v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,282 | 1,683 | 864 | 3,829
[v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 180 | 685 | 255 | 1,120
[v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 139 | 679 | 5,555 | 6,373
[v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 139 | 679 | 5,590 | 6,408
[v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 125 | 630 | 21 | 776
[v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 77 | 629 | 13 | 719
[v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 45 | 622 | 5 | 672