diff --git a/qml/pages/EditPage.qml b/qml/pages/EditPage.qml index 927fa03..d9bde19 100644 --- a/qml/pages/EditPage.qml +++ b/qml/pages/EditPage.qml @@ -28,7 +28,7 @@ Dialog { } MenuItem { text: qsTr("Markdown syntax") - onClicked: Qt.openUrlExternally("https://github.com/showdownjs/showdown/wiki/Showdown's-Markdown-syntax")//pageStack.push(Qt.resolvedUrl("MarkdownPage.qml")) + onClicked: Qt.openUrlExternally("https://github.com/showdownjs/showdown/wiki/Showdown's-Markdown-syntax") } } @@ -69,10 +69,9 @@ Dialog { id: categoryField width: parent.width - favoriteButton.width text: note.category - placeholderText: qsTr("Category") - label: placeholderText + placeholderText: qsTr("No category") + label: qsTr("Category") } - } } diff --git a/qml/pages/NotePage.qml b/qml/pages/NotePage.qml index db2964f..f63f9ba 100644 --- a/qml/pages/NotePage.qml +++ b/qml/pages/NotePage.qml @@ -13,30 +13,27 @@ Dialog { { noHeaderId: true, simplifiedAutoLink: true, tables: true, - tasklists: false, // this is handled by the function reloadContent() because LinkedLabel HTML support is to basic + tasklists: false, // this is handled by the function parseContent() because LinkedLabel HTML support is to basic simpleLineBreaks: true, emoji: true } ) - function reloadContent() { - var tmpNote = account.getNote(note.id) - if (tmpNote) { - note = tmpNote - } - modifiedDetail.value = new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat) - favoriteDetail.value = note.favorite ? qsTr("yes") : qsTr("no") - categoryDetail.value = note.category + function parseContent() { + note = account.getNote(note.id, false) + //modifiedDetail.value = new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat) + //favoriteDetail.value = note.favorite ? qsTr("yes") : qsTr("no") + //categoryDetail.value = note.category var convertedText = converter.makeHtml(note.content) var occurence = -1 - convertedText = convertedText.replace(/^
  • \[ \]\s(.*)<\/li>$/gm, + convertedText = convertedText.replace(/^
  • \[ \] (.*)<\/li>$/gm, function(match, p1, offset) { occurence++ - return '
  • ☐ ' + p1 + '
  • ' + return '
  • ☐ ' + p1 + '
  • ' } ) occurence = -1 - convertedText = convertedText.replace(/^
  • \[[xX]\]\s(.*)<\/li>$/gm, + convertedText = convertedText.replace(/^
  • \[[xX]\] (.*)<\/li>$/gm, function(match, p1, offset) { occurence++ - return '
  • ☑ ' + p1 + '
  • ' + return '
  • ☑ ' + p1 + '
  • ' } ) contentLabel.text = convertedText //console.log(contentLabel.text) @@ -44,18 +41,16 @@ Dialog { acceptDestination: Qt.resolvedUrl("EditPage.qml") acceptDestinationProperties: { account: account; note: note } - Component.onCompleted: acceptDestinationProperties = { account: account, note: note } - onStatusChanged: { - if (status === PageStatus.Active) { - //account.getNote(note.id) - reloadContent() - } + Component.onCompleted: { + parseContent() + acceptDestinationProperties = { account: account, note: note } } Connections { target: account onBusyChanged: { if (account.busy === false) { - reloadContent() + note = account.getNote(note.id, false) + parseContent() } } } @@ -118,30 +113,28 @@ Dialog { var occurence = -1 var newContent = note.content if (/^tasklist:checkbox_(\d+)$/m.test(link)) { - newContent = newContent.replace(/^- \[ \]\s(.*)$/gm, + newContent = newContent.replace(/^- \[ \] (.*)$/gm, function(match, p1, offset, string) { occurence++ if (occurence === parseInt(link.split('_')[1])) { - return '- [x] ' + p1 - } - else { - return match - } + return '- [x] ' + p1 } + else { return match } } ) - account.updateNote(note.id, { 'content': newContent } ) + note.content = newContent + parseContent() + account.updateNote(note.id, { 'content': note.content } ) } else if (/^tasklist:uncheckbox_(\d+)$/m.test(link)) { - newContent = newContent.replace(/^- \[x\]\s(.*)$/gm, + newContent = newContent.replace(/^- \[[xX]\] (.*)$/gm, function(match, p1, offset, string) { occurence++ if (occurence === parseInt(link.split('_')[1])) { - return '- [ ] ' + p1 - } - else { - return match - } + return '- [ ] ' + p1 } + else { return match } } ) - account.updateNote(note.id, { 'content': newContent } ) + note.content = newContent + parseContent() + account.updateNote(note.id, { 'content': note.content } ) } else { Qt.openUrlExternally(link) @@ -149,6 +142,12 @@ Dialog { } } + DetailItem { + id: modifiedDetail + label: qsTr("Modified") + value: new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat) + } + Separator { id: separator width: parent.width @@ -156,14 +155,37 @@ Dialog { horizontalAlignment: Qt.AlignHCenter } - Column { - width: parent.width - - DetailItem { - id: modifiedDetail - label: qsTr("Modified") + Row { + x: Theme.horizontalPageMargin + width: parent.width - x + IconButton { + id: favoriteButton + property bool selected: note.favorite + width: Theme.iconSizeMedium + icon.source: (selected ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") + + (favoriteButton.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) + onClicked: { + account.updateNote(note.id, {'favorite': !note.favorite}) + } } - DetailItem { + TextField { + id: categoryField + width: parent.width - favoriteButton.width + text: note.category + placeholderText: qsTr("No category") + label: qsTr("Category") + EnterKey.iconSource: "image://theme/icon-m-enter-accept" + EnterKey.onClicked: { + categoryField.focus = false + } + onFocusChanged: { + if (focus === false) { + account.updateNote(note.id, {'content': note.content, 'category': text}) // This does not seem to work without adding the content + } + } + } + } + /*DetailItem { id: favoriteDetail label: qsTr("Favorite") } @@ -171,8 +193,7 @@ Dialog { id: categoryDetail label: qsTr("Category") visible: value.length > 0 - } - } + }*/ } } diff --git a/qml/pages/NotesApi.qml b/qml/pages/NotesApi.qml index 3b3306c..1aee253 100644 --- a/qml/pages/NotesApi.qml +++ b/qml/pages/NotesApi.qml @@ -14,11 +14,12 @@ Item { property bool unsecureConnection property bool unencryptedConnection - property var modelData: [ ] // TODO use note id as key { note1.id: note1, note2.id: note2, ... } + property var modelData: [ ] property var model: ListModel { } property string file: StandardPaths.data + "/" + uuid + ".json" property bool saveFile: false property bool busy: false + property bool searchActive: false property int status: 204 property string statusText: "No Content" @@ -28,7 +29,7 @@ Item { Connections { target: appSettings - onSortByChanged: mapDataToModel() + onSortByChanged: _mapDataToModel() } ConfigurationGroup { @@ -61,7 +62,7 @@ Item { account.clear() } - function callApi(method, data) { + function _APIcall(method, data) { busy = true var endpoint = url @@ -87,21 +88,21 @@ Item { if (Array.isArray(json)) { console.log("Received all notes via API: " + endpoint) modelData = json - mapDataToModel() + _mapDataToModel() update = new Date() } else { console.log("Received a single note via API: " + endpoint) - addToModelData(json) + _addToModelData(json) } break; case "POST": console.log("Created a note via API: " + endpoint) - addToModelData(json) + _addToModelData(json) break; case "PUT": console.log("Updated a note via API: " + endpoint) - addToModelData(json) + _addToModelData(json) break; case "DELETE": console.log("Deleted a note via API: " + endpoint) @@ -141,36 +142,47 @@ Item { } } - function getNotes() { - callApi("GET") + function getNotes(refresh) { + if (typeof(refresh) === 'undefined') + refresh = true + if (refresh) + _APIcall("GET") + return modelData } - function getNote(id) { - if (id) - callApi("GET", { 'id': id } ) - modelData.forEach(function(currentValue) { - if (currentValue.id === id) - return currentValue - } ) + function getNote(id, refresh) { + if (typeof(refresh) === 'undefined') + refresh = true + if (id) { + if (refresh) + _APIcall("GET", { 'id': id } ) + var note + modelData.forEach(function(currentValue) { + if (currentValue.id === id) + note = currentValue + } ) + return note + } } function createNote(data) { - callApi("POST", data) + if (data) + _APIcall("POST", data) } function updateNote(id, data) { - if (id) { + if (id && data) { data.id = id - callApi("PUT", data) + _APIcall("PUT", data) } } function deleteNote(id) { if (id) - callApi("DELETE", { 'id': id } ) + _APIcall("DELETE", { 'id': id } ) } - function addToModelData(data) { + function _addToModelData(data) { var dataUpdated = false modelData.forEach(function(currentValue, index, array) { if (currentValue.id === data.id) { @@ -181,19 +193,19 @@ Item { if (!dataUpdated) { modelData.push(data) } - mapDataToModel() + _mapDataToModel() } - function removeFromModelData(id) { + function _removeFromModelData(id) { modelData.forEach(function(currentValue, index, array) { if (currentValue.id === id) { modelData.splice(i, 1) } } ) - mapDataToModel() + _mapDataToModel() } - function mapDataToModel() { + function _mapDataToModel() { modelData.forEach(function(value) { value.date = getPrettyDate(value.modified) } ) switch(appSettings.sortBy) { case "date": @@ -208,32 +220,30 @@ Item { modelData.sort(function(a, b) { return ((a.title > b.title) ? 1 : ((b.title > a.title) ? -1 : 0)) } ) break } - for (var element in modelData) { - model.set(element, modelData[element]) + if (!searchActive) { + for (var element in modelData) { + model.set(element, modelData[element]) + } + element++ + while (model.count > element) { + model.remove(element) + } } - element++ - while (model.count > element) { - model.remove(element) - } - } - - function refresh() { - search("") } function search(query) { - model.clear() - var elements = parseJson() - for (var element in elements) { - elements[element].section = "" - var match = false - for (var child in elements[element]) { - if (elements[element][child]) { - match = (elements[element][child].toString().toLowerCase().indexOf(query) >= 0) || match + if (query !== "") { + searchActive = true + model.clear() + for (var element in modelData) { + if (modelData[element].title.toLowerCase().indexOf(query) >= 0 | modelData[element].content.toLowerCase().indexOf(query) >= 0) { + model.append(modelData[element]) } } - if (query === "" || match) - model.append(elements[element]) + } + else { + searchActive = false + _mapDataToModel() } } diff --git a/qml/pages/NotesPage.qml b/qml/pages/NotesPage.qml index 4e01c8b..5359685 100644 --- a/qml/pages/NotesPage.qml +++ b/qml/pages/NotesPage.qml @@ -59,23 +59,19 @@ Page { } header: PageHeader { - title: nextcloudAccounts.itemAt(appSettings.currentAccount).name //qsTr("Nextclound Notes") - description: nextcloudAccounts.itemAt(appSettings.currentAccount).username + "@" + nextcloudAccounts.itemAt(appSettings.currentAccount).server + //title: nextcloudAccounts.itemAt(appSettings.currentAccount).name //qsTr("Nextclound Notes") + description: searchField.text === "" ? nextcloudAccounts.itemAt(appSettings.currentAccount).username + "@" + nextcloudAccounts.itemAt(appSettings.currentAccount).server : + searchField.placeholderText - BusyIndicator { - x: Theme.horizontalPageMargin - anchors.verticalCenter: parent.verticalCenter - running: nextcloudAccounts.itemAt(appSettings.currentAccount) ? nextcloudAccounts.itemAt(appSettings.currentAccount).busy && !busyIndicator.running : false + SearchField { + id: searchField + width: parent.width + //enabled: notesList.count > 0 + placeholderText: nextcloudAccounts.itemAt(appSettings.currentAccount).name + EnterKey.iconSource: "image://theme/icon-m-enter-close" + EnterKey.onClicked: focus = false + onTextChanged: nextcloudAccounts.itemAt(appSettings.currentAccount).search(text.toLowerCase()) } - - /*SearchField { - width: parent.width - placeholderText: qsTr("Nextcloud Notes") - onTextChanged: notes.search(text.toLowerCase()) - - EnterKey.iconSource: "image://theme/icon-m-enter-close" - EnterKey.onClicked: focus = false - enabled: notesList.count > 0*/ } currentIndex: -1 @@ -92,12 +88,12 @@ Page { height: contentHeight + menu.height width: parent.width highlighted: down || menu.active - ListView.onAdd: AddAnimation { + /*ListView.onAdd: AddAnimation { target: note } ListView.onRemove: RemoveAnimation { target: note - } + }*/ RemorseItem { id: remorse } @@ -116,7 +112,6 @@ Page { icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") + (note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) onClicked: { - console.log("Toggle favorite") nextcloudAccounts.itemAt(appSettings.currentAccount).updateNote(id, {'favorite': !favorite} ) } } @@ -227,9 +222,16 @@ Page { hintText: qsTr("Pull down to add a note") } + ViewPlaceholder { + id: noSearchPlaceholder + enabled: nextcloudAccounts.itemAt(appSettings.currentAccount) ? (notesList.count === 0 && nextcloudAccounts.itemAt(appSettings.currentAccount).modelData.length > 0) : false + text: qsTr("No result") + hintText: qsTr("Try another query") + } + ViewPlaceholder { id: errorPlaceholder - enabled: notesList.count === 0 && !busyIndicator.running && !noNotesPlaceholder.enabled && !noLoginPlaceholder.enabled + enabled: notesList.count === 0 && !busyIndicator.running && !noSearchPlaceholder.enabled && !noNotesPlaceholder.enabled && !noLoginPlaceholder.enabled text: qsTr("An error occurred") hintText: nextcloudAccounts.itemAt(appSettings.currentAccount).statusText } diff --git a/rpm/harbour-nextcloudnotes.changes b/rpm/harbour-nextcloudnotes.changes index 1d39fa1..5bdda7e 100644 --- a/rpm/harbour-nextcloudnotes.changes +++ b/rpm/harbour-nextcloudnotes.changes @@ -12,6 +12,12 @@ # * date Author's Name version-release # - Summary of changes +* Mon Dec 03 2018 Scharel Clemens 0.1-4 +- Implemented searching +- Larger checkboxes +- Better asynchronious behaviour +- Small bugfixes + * Wed Nov 28 2018 Scharel Clemens 0.1-3 - Implemented checkboxes - Link to external website containing the markdown syntax diff --git a/rpm/harbour-nextcloudnotes.spec b/rpm/harbour-nextcloudnotes.spec index 6ca4645..69fb423 100644 --- a/rpm/harbour-nextcloudnotes.spec +++ b/rpm/harbour-nextcloudnotes.spec @@ -14,7 +14,7 @@ Name: harbour-nextcloudnotes %{?qtc_builddir:%define _builddir %qtc_builddir} Summary: Nextcloud Notes Version: 0.1 -Release: 3 +Release: 4 Group: Qt/Qt License: LICENSE URL: http://example.org/ diff --git a/rpm/harbour-nextcloudnotes.yaml b/rpm/harbour-nextcloudnotes.yaml index 8eea5fd..ab01abe 100644 --- a/rpm/harbour-nextcloudnotes.yaml +++ b/rpm/harbour-nextcloudnotes.yaml @@ -1,7 +1,7 @@ Name: harbour-nextcloudnotes Summary: Nextcloud Notes Version: 0.1 -Release: 3 +Release: 4 # The contents of the Group field should be one of the groups listed here: # https://github.com/mer-tools/spectacle/blob/master/data/GROUPS Group: Qt/Qt diff --git a/translations/harbour-nextcloudnotes.ts b/translations/harbour-nextcloudnotes.ts index cadd8b5..9ce2536 100644 --- a/translations/harbour-nextcloudnotes.ts +++ b/translations/harbour-nextcloudnotes.ts @@ -57,6 +57,10 @@ Markdown syntax + + No category + + GPLLicense @@ -145,22 +149,14 @@ Modified - - Favorite - - - - yes - - - - no - - Category + + No category + + NotesApi @@ -235,6 +231,14 @@ Updating... + + No result + + + + Try another query + + SettingsPage