diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml index 014d805..a86be1c 100644 --- a/qml/cover/CoverPage.qml +++ b/qml/cover/CoverPage.qml @@ -12,12 +12,12 @@ CoverBackground { CoverActionList { id: coverAction - enabled: appSettings.currentAccount >= 0 + enabled: appSettings.currentAccount.length > 0 CoverAction { iconSource: "image://theme/icon-cover-new" onTriggered: { - nextcloudAccounts.itemAt(appSettings.currentAccount).createNote({'content': ""}) + api.createNote({'content': ""}) appWindow.activate() } } diff --git a/qml/harbour-nextcloudnotes.qml b/qml/harbour-nextcloudnotes.qml index ba31e16..5fa1388 100644 --- a/qml/harbour-nextcloudnotes.qml +++ b/qml/harbour-nextcloudnotes.qml @@ -7,21 +7,90 @@ ApplicationWindow { id: appWindow + ConfigurationValue { + id: accounts + key: appSettings.path + "/accountIDs" + defaultValue: [ ] + } + ConfigurationGroup { id: appSettings path: "/apps/harbour-nextcloudnotes/settings" //synchronous: true - property int currentAccount: value("currentAccount", -1) + property string currentAccount: value("currentAccount", "") + property var accountIDs: value("accountIDs", [ ]) property int autoSyncInterval: value("autoSyncInterval", 0) property int previewLineCount: value("previewLineCount", 4) property string sortBy: value("sortBy", "date") property bool showSeparator: value("showSeparator", false) property bool useMonoFont: value("useMonoFont", false) property bool useCapitalX: value("useCapitalX", false) + + onCurrentAccountChanged: api.uuid = currentAccount + + function addAccount() { + var uuid = uuidv4() + var tmpIDs = accounts.value + tmpIDs.push(uuid) + accounts.value = tmpIDs + accounts.sync() + return uuid + } + function removeAccount(uuid) { + autoSyncTimer.stop() + var tmpAccouunt = currentAccount + currentAccount = uuid + api.clear() + currentAccount = tmpAccouunt + var newIds = [ ] + accountIDs.forEach(function(currentValue) { + if (currentValue !== uuid) { + newIds.push(currentValue) + } + }) + accounts.value = newIds + for (var i = accountIDs.length-1; i > 0; i--) { + if (accountIDs[i] !== uuid) { + api.uuid = accountIDs[i] + break + } + } + autoSyncTimer.start() + } + function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + } } - ConfigurationValue { + Timer { + id: autoSyncTimer + interval: appSettings.autoSyncInterval * 1000 + repeat: true + running: interval > 0 && appWindow.visible + triggeredOnStart: true + onTriggered: { + if (!api.busy) { + api.getNotes() + } + else { + triggeredOnStart = false + restart() + triggeredOnStart = true + } + } + onIntervalChanged: console.log("Auto-Sync every " + interval / 1000 + " seconds") + } + + NotesApi { + id: api + uuid: appSettings.currentAccount + } + + /*ConfigurationValue { id: nextcloudUUIDs key: "/apps/harbour-nextcloudnotes/settings/accountIDs" defaultValue: [] @@ -53,6 +122,8 @@ ApplicationWindow } }) nextcloudUUIDs.value = newIds + if (nextcloudUUIDs.value[appSettings.currentAccount] === uuid) + appSettings.currentAccount = nextcloudUUIDs.value.length-1 } function push(uuid) { var accountIDs = nextcloudUUIDs.value @@ -64,14 +135,7 @@ ApplicationWindow accountIDs.pop() nextcloudUUIDs.value = accountIDs } - } - - function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } + }*/ initialPage: Component { NotesPage { } } cover: Qt.resolvedUrl("cover/CoverPage.qml") diff --git a/qml/pages/EditPage.qml b/qml/pages/EditPage.qml index 5b6ebf3..cb50613 100644 --- a/qml/pages/EditPage.qml +++ b/qml/pages/EditPage.qml @@ -5,31 +5,29 @@ import Nemo.Notifications 1.0 Dialog { id: page - property var account property var note onAccepted: { - account.updateNote(note.id, { 'category': categoryField.text, 'content': contentArea.text, 'favorite': favoriteButton.selected } ) + api.updateNote(note.id, { 'category': categoryField.text, 'content': contentArea.text, 'favorite': favoriteButton.selected } ) } onStatusChanged: { if (status === PageStatus.Active) { - note = account.getNote(note.id, false) + //note = api.getNote(note.id, false) favoriteButton.selected = note.favorite - categoryRepeater.model = account.categories + categoryRepeater.model = api.categories } } SilicaFlickable { - id: flickable anchors.fill: parent - contentHeight: column.height + contentHeight: mainColumn.height PullDownMenu { MenuItem { text: qsTr("Reset") onClicked: { - note = account.getNote(note.id, false) + note = api.getNote(note.id, false) favoriteButton.selected = note.favorite } } @@ -40,47 +38,58 @@ Dialog { } Column { - id: column - width: parent.width// - 2*x + id: mainColumn + width: parent.width DialogHeader { - //title: account.model.get(noteIndex).title + title: note.title } - TextArea { - id: contentArea + Column { width: parent.width - focus: true - text: note.content - font.family: appSettings.useMonoFont ? "DejaVu Sans Mono" : Theme.fontFamily // "Courier" - property int preTextLength: 0 - property var listPrefixes: [/^( *)- /gm, /^( *)\* /gm, /^( *)\+ /gm, /^( *)- \[ \] /gm, /^( *)- \[[xX]\] /gm, /^( *)> /gm, /^( *)\d+. /gm] - onTextChanged: { - if (page.status === PageStatus.Active && - text.length > preTextLength && - text.charAt(cursorPosition-1) === "\n") { - var clipboard = "" - var preLine = text.substring(text.lastIndexOf("\n", cursorPosition-2), text.indexOf("\n", cursorPosition-1)) - listPrefixes.forEach(function(currentValue, index) { - var prefix = preLine.match(currentValue) - if (prefix !== null) { - if (index === listPrefixes.length-1) { - var newListNumber = parseInt(prefix[0].split(". ")[0]) + 1 - clipboard = prefix[0].replace(/\d/gm, newListNumber.toString()) - } - else { - clipboard = prefix[0] + spacing: Theme.paddingLarge + + Separator { + width: parent.width + color: Theme.primaryColor + horizontalAlignment: Qt.AlignHCenter + } + + TextArea { + id: contentArea + width: parent.width + focus: true + text: note.content + font.family: appSettings.useMonoFont ? "DejaVu Sans Mono" : Theme.fontFamily // "Courier" + property int preTextLength: 0 + property var listPrefixes: [/^( *)- /gm, /^( *)\* /gm, /^( *)\+ /gm, /^( *)- \[ \] /gm, /^( *)- \[[xX]\] /gm, /^( *)> /gm, /^( *)\d+. /gm] + onTextChanged: { + if (page.status === PageStatus.Active && + text.length > preTextLength && + text.charAt(cursorPosition-1) === "\n") { + var clipboard = "" + var preLine = text.substring(text.lastIndexOf("\n", cursorPosition-2), text.indexOf("\n", cursorPosition-1)) + listPrefixes.forEach(function(currentValue, index) { + var prefix = preLine.match(currentValue) + if (prefix !== null) { + if (index === listPrefixes.length-1) { + var newListNumber = parseInt(prefix[0].split(". ")[0]) + 1 + clipboard = prefix[0].replace(/\d/gm, newListNumber.toString()) + } + else { + clipboard = prefix[0] + } } + }) + if (clipboard !== "") { + var tmpClipboard = Clipboard.text + Clipboard.text = clipboard + contentArea.paste() + Clipboard.text = tmpClipboard } - }) - if (clipboard !== "") { - var tmpClipboard = Clipboard.text - Clipboard.text = clipboard - contentArea.paste() - Clipboard.text = tmpClipboard } + preTextLength = text.length } - preTextLength = text.length } } @@ -94,7 +103,7 @@ Dialog { Repeater { id: categoryRepeater - model: account.categories + model: api.categories BackgroundItem { id: categoryBackground width: categoryRectangle.width @@ -127,7 +136,9 @@ Dialog { width: Theme.iconSizeMedium icon.source: (selected ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") + (favoriteButton.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) - onClicked: selected = !selected + onClicked: { + api.updateNote(note.id, {'favorite': !note.favorite}) + } } TextField { id: categoryField @@ -135,8 +146,23 @@ Dialog { 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 && text !== note.category) { + api.updateNote(note.id, {'content': note.content, 'category': text}) // This does not seem to work without adding the content + } + } } } + + DetailItem { + id: modifiedDetail + label: qsTr("Modified") + value: new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat) + } } VerticalScrollDecorator {} diff --git a/qml/pages/LoginDialog.qml b/qml/pages/LoginDialog.qml index 135d8d5..be57513 100644 --- a/qml/pages/LoginDialog.qml +++ b/qml/pages/LoginDialog.qml @@ -5,16 +5,34 @@ import Nemo.Configuration 1.0 Dialog { id: loginDialog - property int account + property string accountId + + ConfigurationGroup { + id: account + path: "/apps/harbour-nextcloudnotes/accounts/" + accountId + Component.onCompleted: { + nameField.text = value("name", "", String) + serverField.text = value("server", "https://", String) + usernameField.text = value("username", "", String) + passwordField.text = value("password", "", String) + } + } canAccept: (nameField.text.length > 0 && serverField.acceptableInput && usernameField.text.length > 0 && passwordField.text.length > 0) + onDone: { + account.setValue("name", nameField.text) + account.setValue("server", serverField.text) + account.setValue("username", usernameField.text) + account.setValue("password", passwordField.text) + //account.setValue("unsecureConnection", unsecureConnectionTextSwitch.checked) + //account.setValue("unencryptedConnection", unencryptedConnectionTextSwitch.checked) + account.sync() + } onAccepted: { - nextcloudAccounts.itemAt(account).name = nameField.text - nextcloudAccounts.itemAt(account).server = serverField.text - nextcloudAccounts.itemAt(account).username = usernameField.text - nextcloudAccounts.itemAt(account).password = passwordField.text - //dnextcloudAccounts.itemAt(account).unsecureConnection = unsecureConnectionTextSwitch.checked - //dnextcloudAccounts.itemAt(account).unencryptedConnection = unencryptedConnectionTextSwitch.checked + api.uuid = accountId + } + onRejected: { + appSettings.removeAccount(accountId) } SilicaFlickable { @@ -41,7 +59,7 @@ Dialog { id: nameField focus: true width: parent.width - text: nextcloudAccounts.itemAt(account).name.length <= 0 ? qsTr("Unnamed account") : nextcloudAccounts.itemAt(account).name + text: account.value("name", "", String) placeholderText: qsTr("Account name") label: placeholderText errorHighlight: text.length === 0// && focus === true @@ -53,7 +71,7 @@ Dialog { TextField { id: serverField width: parent.width - text: nextcloudAccounts.itemAt(account).server.length <= 0 ? "https://" : nextcloudAccounts.itemAt(account).server + text: account.value("server", "https://", String) placeholderText: qsTr("Nextcloud server") label: placeholderText + " " + qsTr("(starting with \"https://\")") inputMethodHints: Qt.ImhUrlCharactersOnly @@ -68,7 +86,7 @@ Dialog { TextField { id: usernameField width: parent.width - text: nextcloudAccounts.itemAt(account).username + text: account.value("name", "", String) placeholderText: qsTr("Username") label: placeholderText inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase @@ -81,7 +99,8 @@ Dialog { PasswordField { id: passwordField width: parent.width - text: nextcloudAccounts.itemAt(account).password + text: account.value("password", "", String) + placeholderText: qsTr("Password") label: placeholderText errorHighlight: text.length === 0// && focus === true EnterKey.enabled: text.length > 0 diff --git a/qml/pages/NotePage.qml b/qml/pages/NotePage.qml index eabdcd9..b35a00b 100644 --- a/qml/pages/NotePage.qml +++ b/qml/pages/NotePage.qml @@ -5,7 +5,6 @@ import Sailfish.Silica 1.0 Dialog { id: noteDialog - property var account property var note property var showdown: ShowDown.showdown @@ -20,26 +19,29 @@ Dialog { emoji: true } ) acceptDestination: Qt.resolvedUrl("EditPage.qml") - acceptDestinationProperties: { account: account; note: note } + acceptDestinationProperties: { note: note } Component.onCompleted: { - acceptDestinationProperties = { account: account, note: note } - //showdown.setFlavor('original') - parseContent() + note = api.getNote(note.id) + reloadContent() } Connections { - target: account + target: api onBusyChanged: { - if (account.busy === false) { - note = account.getNote(note.id, false) - categoryRepeater.model = account.categories - acceptDestinationProperties = { account: account, note: note } - parseContent() + if (api.busy === false) { + note = api.getNote(note.id, false) + reloadContent() } } } + function reloadContent() { + acceptDestinationProperties = { note: note } + categoryRepeater.model = api.categories + parseContent() + } + function parseContent() { - note = account.getNote(note.id, false) + //note = api.getNote(note.id, false) var convertedText = converter.makeHtml(note.content) var occurence = -1 convertedText = convertedText.replace(/^
  • (

    )?\[ \] (.*)(<.*)$/gmi, @@ -75,31 +77,30 @@ Dialog { onTriggered: pageStack.pop() } PullDownMenu { - busy: account ? account.busy : false + busy: api.busy MenuItem { text: qsTr("Delete") - enabled: account ? true : false - onClicked: remorse.execute("Deleting", function() { account.deleteNote(notey.id) } ) + onClicked: remorse.execute("Deleting", function() { api.deleteNote(note.id) } ) } MenuItem { text: enabled ? qsTr("Reload") : qsTr("Updating...") - enabled: account ? !account.busy : false - onClicked: account.getNote(note.id) + enabled: !api.busy + onClicked: api.getNote(note.id) } MenuLabel { - visible: appSettings.currentAccount >= 0 - text: account ? ( - qsTr("Last update") + ": " + ( - new Date(account.update).valueOf() !== 0 ? - new Date(account.update).toLocaleString(Qt.locale(), Locale.ShortFormat) : - qsTr("never"))) : "" + visible: appSettings.currentAccount.length >= 0 + text: qsTr("Last update") + ": " + ( + new Date(api.update).valueOf() !== 0 ? + new Date(api.update).toLocaleString(Qt.locale(), Locale.ShortFormat) : + qsTr("never")) } } DialogHeader { id: dialogHeader dialog: noteDialog + title: note.title acceptText: qsTr("Edit") cancelText: qsTr("Notes") } @@ -108,6 +109,12 @@ Dialog { width: parent.width spacing: Theme.paddingLarge + Separator { + width: parent.width + color: Theme.primaryColor + horizontalAlignment: Qt.AlignHCenter + } + LinkedLabel { id: contentLabel x: Theme.horizontalPageMargin @@ -129,7 +136,7 @@ Dialog { } ) note.content = newContent parseContent() - account.updateNote(note.id, { 'content': note.content } ) + api.updateNote(note.id, { 'content': note.content } ) } else if (/^tasklist:uncheckbox_(\d+)$/m.test(link)) { newContent = newContent.replace(/- \[[xX]\] (.*)$/gm, @@ -141,7 +148,7 @@ Dialog { } ) note.content = newContent parseContent() - account.updateNote(note.id, { 'content': note.content } ) + api.updateNote(note.id, { 'content': note.content } ) } else { Qt.openUrlExternally(link) @@ -150,86 +157,83 @@ Dialog { } Separator { - id: separator width: parent.width color: Theme.primaryColor horizontalAlignment: Qt.AlignHCenter } - Column { - width: parent.width + Flow { + x: Theme.horizontalPageMargin + width: parent.width - 2*x + spacing: Theme.paddingMedium + visible: opacity > 0.0 + opacity: categoryField.focus ? 1.0 : 0.0 + Behavior on opacity { FadeAnimator { } } - Flow { - x: Theme.horizontalPageMargin - width: parent.width - 2*x - spacing: Theme.paddingMedium - visible: opacity > 0.0 - opacity: categoryField.focus ? 1.0 : 0.0 - Behavior on opacity { FadeAnimator { } } - - Repeater { - id: categoryRepeater - model: account.categories - BackgroundItem { - id: categoryBackground - width: categoryRectangle.width - height: categoryRectangle.height - Rectangle { - id: categoryRectangle - width: categoryLabel.width + Theme.paddingLarge - height: categoryLabel.height + Theme.paddingSmall - color: "transparent" - border.color: Theme.highlightColor - radius: height / 4 - Label { - id: categoryLabel - anchors.centerIn: parent - text: modelData - color: categoryBackground.highlighted ? Theme.highlightColor : Theme.primaryColor - font.pixelSize: Theme.fontSizeSmall - } - } - onClicked: categoryField.text = modelData - } - } - } - 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}) - } - } - 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 + Repeater { + id: categoryRepeater + model: api.categories + BackgroundItem { + id: categoryBackground + width: categoryRectangle.width + height: categoryRectangle.height + Rectangle { + id: categoryRectangle + width: categoryLabel.width + Theme.paddingLarge + height: categoryLabel.height + Theme.paddingSmall + color: "transparent" + border.color: Theme.highlightColor + radius: height / 4 + Label { + id: categoryLabel + anchors.centerIn: parent + text: modelData + color: categoryBackground.highlighted ? Theme.highlightColor : Theme.primaryColor + font.pixelSize: Theme.fontSizeSmall } } + onClicked: categoryField.text = modelData } } - DetailItem { - id: modifiedDetail - label: qsTr("Modified") - value: new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat) - } } } + + 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: { + api.updateNote(note.id, {'favorite': !note.favorite}) + } + } + 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 && text !== note.category) { + api.updateNote(note.id, {'content': note.content, 'category': text}) // This does not seem to work without adding the content + } + } + } + } + + DetailItem { + id: modifiedDetail + label: qsTr("Modified") + value: new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat) + } } VerticalScrollDecorator {} diff --git a/qml/pages/NotesApi.qml b/qml/pages/NotesApi.qml index c418f6b..b79f9d8 100644 --- a/qml/pages/NotesApi.qml +++ b/qml/pages/NotesApi.qml @@ -21,13 +21,28 @@ Item { property bool saveFile: false property bool busy: false property bool searchActive: false + property var apiReq: new XMLHttpRequest property int status: 204 property string statusText: "No Content" + Component.onCompleted: { + refreshConfig() + } + onStatusChanged: { console.log("Network status: " + statusText + " (" + status + ")") } + onUuidChanged: { + onUuidChanged: console.log("Account : " + uuid) + account.path = "/apps/harbour-nextcloudnotes/accounts/" + uuid + refreshConfig() + modelData = [] + model.clear() + appSettings.currentAccount = uuid + //getNotes() + } + Connections { target: appSettings onSortByChanged: _mapDataToModel() @@ -36,9 +51,14 @@ Item { ConfigurationGroup { id: account path: "/apps/harbour-nextcloudnotes/accounts/" + uuid + onValuesChanged: refreshConfig() } - Component.onCompleted: { + function refreshConfig() { + if (busy) { + apiReq.abort() + } + account.sync() name = account.value("name", "", String) server = account.value("server", "", String) url = server + "/index.php/apps/notes/api/" + version + "/notes" @@ -49,16 +69,18 @@ Item { unencryptedConnection = account.value("unencryptedConnection", false, Boolean) } - onUuidChanged: account.setValue("uuid", uuid) + /*onUuidChanged: account.setValue("uuid", uuid) onNameChanged: account.setValue("name", name) onServerChanged: account.setValue("server", server) onUsernameChanged: account.setValue("username", username) onPasswordChanged: account.setValue("password", password) onUpdateChanged: account.setValue("update", update) onUnsecureConnectionChanged: account.setValue("unsecureConnection", unsecureConnection) - onUnencryptedConnectionChanged: account.setValue("unencryptedConnection", unencryptedConnection) + onUnencryptedConnectionChanged: account.setValue("unencryptedConnection", unencryptedConnection)*/ function clear() { + apiReq.abort() + modelData = [] model.clear() account.clear() } @@ -73,7 +95,7 @@ Item { } } - var apiReq = new XMLHttpRequest + console.log("Calling " + endpoint) apiReq.open(method, endpoint, true) apiReq.setRequestHeader('User-Agent', 'SailfishOS/harbour-nextcloudnotes') apiReq.setRequestHeader('OCS-APIRequest', 'true') @@ -100,6 +122,9 @@ Item { case "POST": console.log("Created a note via API: " + endpoint) _addToModelData(json) + pageStack.push(Qt.resolvedUrl("NotePage.qml"), { note: json } ) + pageStack.completeAnimation() + pageStack.navigateForward() break; case "PUT": console.log("Updated a note via API: " + endpoint) @@ -241,7 +266,9 @@ Item { searchActive = true model.clear() for (var element in modelData) { - if (modelData[element].title.toLowerCase().indexOf(query) >= 0 | modelData[element].content.toLowerCase().indexOf(query) >= 0) { + if (modelData[element].title.toLowerCase().indexOf(query) >= 0 | + modelData[element].content.toLowerCase().indexOf(query) >= 0 | + modelData[element].category.toLowerCase().indexOf(query) >= 0) { model.append(modelData[element]) } } diff --git a/qml/pages/NotesPage.qml b/qml/pages/NotesPage.qml index f5f75c2..4027b85 100644 --- a/qml/pages/NotesPage.qml +++ b/qml/pages/NotesPage.qml @@ -6,31 +6,21 @@ Page { onStatusChanged: { if (status === PageStatus.Active) { - if (nextcloudAccounts.count > 0) { - autoSyncTimer.restart() - } - else { + if (appSettings.accountIDs.length <= 0) { addAccountHint.restart() } + else { + autoSyncTimer.restart() + } } } - Timer { - id: autoSyncTimer - interval: appSettings.autoSyncInterval * 1000 - repeat: true - running: interval > 0 && appWindow.visible - triggeredOnStart: true - onTriggered: nextcloudAccounts.itemAt(appSettings.currentAccount).getNotes() - onIntervalChanged: console.log("Auto-Sync every " + interval / 1000 + " seconds") - } - SilicaListView { id: notesList anchors.fill: parent PullDownMenu { - busy: nextcloudAccounts.itemAt(appSettings.currentAccount) ? nextcloudAccounts.itemAt(appSettings.currentAccount).busy : false + busy: api.busy MenuItem { text: qsTr("Settings") @@ -38,23 +28,20 @@ Page { } MenuItem { text: qsTr("Add note") - enabled: nextcloudAccounts.itemAt(appSettings.currentAccount) ? true : false - visible: appSettings.currentAccount >= 0 - onClicked: nextcloudAccounts.itemAt(appSettings.currentAccount).createNote({'content': ""}) + enabled: appSettings.currentAccount.length > 0 + onClicked: api.createNote({'content': ""}) } MenuItem { text: enabled ? qsTr("Reload") : qsTr("Updating...") - enabled: nextcloudAccounts.itemAt(appSettings.currentAccount) ? !nextcloudAccounts.itemAt(appSettings.currentAccount).busy : false - visible: appSettings.currentAccount >= 0 - onClicked: nextcloudAccounts.itemAt(appSettings.currentAccount).getNotes() + enabled: appSettings.currentAccount.length > 0 && !api.busy + onClicked: api.getNotes() } MenuLabel { - visible: appSettings.currentAccount >= 0 - text: nextcloudAccounts.itemAt(appSettings.currentAccount) ? ( - qsTr("Last update") + ": " + ( - new Date(nextcloudAccounts.itemAt(appSettings.currentAccount).update).valueOf() !== 0 ? - new Date(nextcloudAccounts.itemAt(appSettings.currentAccount).update).toLocaleString(Qt.locale(), Locale.ShortFormat) : - qsTr("never"))) : "" + visible: appSettings.currentAccount.length > 0 + text: qsTr("Last update") + ": " + ( + new Date(api.update).valueOf() !== 0 ? + new Date(api.update).toLocaleString(Qt.locale(), Locale.ShortFormat) : + qsTr("never")) } } @@ -63,10 +50,10 @@ Page { SearchField { id: searchField width: parent.width - placeholderText: nextcloudAccounts.itemAt(appSettings.currentAccount).name + placeholderText: api.name EnterKey.iconSource: "image://theme/icon-m-enter-close" EnterKey.onClicked: focus = false - onTextChanged: nextcloudAccounts.itemAt(appSettings.currentAccount).search(text.toLowerCase()) + onTextChanged: api.search(text.toLowerCase()) } Label { id: description @@ -76,23 +63,23 @@ Page { anchors.bottomMargin: Theme.paddingMedium color: Theme.secondaryHighlightColor font.pixelSize: Theme.fontSizeSmall - text: nextcloudAccounts.itemAt(appSettings.currentAccount).username + "@" + nextcloudAccounts.itemAt(appSettings.currentAccount).server + text: api.username + "@" + api.server } BusyIndicator { anchors.verticalCenter: searchField.verticalCenter anchors.right: parent.right anchors.rightMargin: Theme.horizontalPageMargin size: BusyIndicatorSize.Medium - running: nextcloudAccounts.itemAt(appSettings.currentAccount) ? nextcloudAccounts.itemAt(appSettings.currentAccount).busy && !busyIndicator.running : false + running: api.busy && !busyIndicator.running } } currentIndex: -1 - model: nextcloudAccounts.itemAt(appSettings.currentAccount)? nextcloudAccounts.itemAt(appSettings.currentAccount).model : 0 + model: api.model Connections { - target: appSettings - onCurrentAccountChanged: notesList.model = nextcloudAccounts.itemAt(appSettings.currentAccount)? nextcloudAccounts.itemAt(appSettings.currentAccount).model : 0 + target: api + onUuidChanged: notesList.model = api.model } delegate: BackgroundItem { @@ -125,7 +112,7 @@ Page { icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") + (note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) onClicked: { - nextcloudAccounts.itemAt(appSettings.currentAccount).updateNote(id, {'favorite': !favorite} ) + api.updateNote(id, {'favorite': !favorite} ) } } @@ -185,8 +172,7 @@ Page { } onClicked: pageStack.push(Qt.resolvedUrl("NotePage.qml"), - { account: nextcloudAccounts.itemAt(appSettings.currentAccount), - note: nextcloudAccounts.itemAt(appSettings.currentAccount).model.get(index)} ) + { note: api.model.get(index)} ) onPressAndHold: menu.open(note) ContextMenu { @@ -200,7 +186,7 @@ Page { text: qsTr("Delete") onClicked: { remorse.execute(note, qsTr("Deleting note"), function() { - nextcloudAccounts.itemAt(appSettings.currentAccount).deleteNote(id) + api.deleteNote(id) }) } } @@ -218,26 +204,26 @@ Page { id: busyIndicator anchors.centerIn: parent size: BusyIndicatorSize.Large - running: nextcloudAccounts.itemAt(appSettings.currentAccount) ? (notesList.count === 0 && nextcloudAccounts.itemAt(appSettings.currentAccount).busy) : false + running: notesList.count === 0 && api.busy } ViewPlaceholder { id: noLoginPlaceholder - enabled: nextcloudUUIDs.value.length <= 0 + enabled: appSettings.accountIDs.length <= 0 text: qsTr("No account yet") hintText: qsTr("Got to the settings to add an account") } ViewPlaceholder { id: noNotesPlaceholder - enabled: nextcloudAccounts.itemAt(appSettings.currentAccount) ? (nextcloudAccounts.itemAt(appSettings.currentAccount).status === 204 && !busyIndicator.running && !noLoginPlaceholder.enabled) : false + enabled: api.status === 204 && !busyIndicator.running && !noLoginPlaceholder.enabled text: qsTr("No notes yet") 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 + enabled: notesList.count === 0 && api.searchActive text: qsTr("No result") hintText: qsTr("Try another query") } @@ -246,7 +232,7 @@ Page { id: errorPlaceholder enabled: notesList.count === 0 && !busyIndicator.running && !noSearchPlaceholder.enabled && !noNotesPlaceholder.enabled && !noLoginPlaceholder.enabled text: qsTr("An error occurred") - hintText: nextcloudAccounts.itemAt(appSettings.currentAccount).statusText + hintText: api.statusText } TouchInteractionHint { diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml index b37b27d..72bb261 100644 --- a/qml/pages/SettingsPage.qml +++ b/qml/pages/SettingsPage.qml @@ -31,47 +31,53 @@ Page { } Label { id: noAccountsLabel - visible: nextcloudAccounts.count <= 0 + visible: appSettings.accountIDs.length <= 0 text: qsTr("No Nextcloud account yet") font.pixelSize: Theme.fontSizeLarge color: Theme.secondaryHighlightColor anchors.horizontalCenter: parent.horizontalCenter } Repeater { - model: nextcloudAccounts.count + id: accountRepeater + model: appSettings.accountIDs + delegate: ListItem { id: accountListItem contentHeight: accountTextSwitch.height highlighted: accountTextSwitch.down + ConfigurationGroup { + id: account + path: "/apps/harbour-nextcloudnotes/accounts/" + modelData + Component.onCompleted: { + accountTextSwitch.text = value("name", qsTr("Unnamed account"), String) + accountTextSwitch.description = account.value("username", qsTr("unknown"), String) + "@" + account.value("server", qsTr("unknown"), String) + } + } + TextSwitch { id: accountTextSwitch automaticCheck: false - checked: index === appSettings.currentAccount - text: nextcloudAccounts.itemAt(index).name.length <= 0 ? qsTr("Unnamed account") : nextcloudAccounts.itemAt(index).name - description: nextcloudAccounts.itemAt(index).username + "@" + nextcloudAccounts.itemAt(index).server// : qsTr("Press and hold to configure") - onClicked: appSettings.currentAccount = index + checked: modelData === api.uuid + onClicked: { + api.uuid = modelData + api.getNotes() + } onPressAndHold: openMenu() } menu: ContextMenu { MenuItem { text: qsTr("Edit") onClicked: { - var login = pageStack.push(Qt.resolvedUrl("LoginDialog.qml"), { account: index }) - login.accepted.connect(function() { - }) - login.rejected.connect(function() { - }) + var login = pageStack.replace(Qt.resolvedUrl("LoginDialog.qml"), { accountId: modelData }) } } MenuItem { text: qsTr("Delete") onClicked: { accountListItem.remorseAction(qsTr("Deleting account"), function() { - console.log("Deleting " + nextcloudAccounts.itemAt(index).uuid) - nextcloudAccounts.remove(nextcloudAccounts.itemAt(index).uuid) - //nextcloudAccounts.itemAt(index).clear() - //nextcloudAccounts.pop() + console.log("Deleting " + modelData) + appSettings.removeAccount(modelData) }) } } @@ -82,17 +88,8 @@ Page { text: qsTr("Add account") anchors.horizontalCenter: parent.horizontalCenter onClicked: { - nextcloudAccounts.add() - var login = pageStack.push(Qt.resolvedUrl("LoginDialog.qml"), { account:nextcloudAccounts.count-1 }) - login.accepted.connect(function() { - console.log("Adding account " + nextcloudAccounts.itemAt(login.account).name) - if (appSettings.currentAccount < 0) - appSettings.currentAccount = nextcloudUUIDs.value.length-1 - appWindow.update() - }) - login.rejected.connect(function() { - nextcloudAccounts.pop() - }) + var newAccountID = appSettings.addAccount() + var login = pageStack.replace(Qt.resolvedUrl("LoginDialog.qml"), { accountId: newAccountID }) } } diff --git a/rpm/harbour-nextcloudnotes.changes b/rpm/harbour-nextcloudnotes.changes index baad587..f1849eb 100644 --- a/rpm/harbour-nextcloudnotes.changes +++ b/rpm/harbour-nextcloudnotes.changes @@ -12,6 +12,10 @@ # * date Author's Name version-release # - Summary of changes +* Thu Dec 06 2018 Scharel Clemens 0.2-1 +- Improved account handling +- Directly go to edit page when creating a new note + * Thu Dec 06 2018 Scharel Clemens 0.1-8 - Fix for #19 "Strikethrough is not shown" - Added #20 "List of existing categories" diff --git a/rpm/harbour-nextcloudnotes.spec b/rpm/harbour-nextcloudnotes.spec index d66d81e..a26c0ea 100644 --- a/rpm/harbour-nextcloudnotes.spec +++ b/rpm/harbour-nextcloudnotes.spec @@ -13,8 +13,8 @@ Name: harbour-nextcloudnotes %{!?qtc_make:%define qtc_make make} %{?qtc_builddir:%define _builddir %qtc_builddir} Summary: Nextcloud Notes -Version: 0.1 -Release: 8 +Version: 0.2 +Release: 1 Group: Qt/Qt License: LICENSE URL: http://example.org/ diff --git a/rpm/harbour-nextcloudnotes.yaml b/rpm/harbour-nextcloudnotes.yaml index 0a88984..e338f96 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: 8 +Version: 0.2 +Release: 1 # 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 24d7b42..e4656a5 100644 --- a/translations/harbour-nextcloudnotes.ts +++ b/translations/harbour-nextcloudnotes.ts @@ -61,6 +61,10 @@ No category + + Modified + + GPLLicense @@ -100,11 +104,11 @@ - Unnamed account + <strong>CAUTION: Your password will be saved without any encryption on the device!</strong><br>Please consider creating a dedicated app password! Open your Nextcloud in a browser and go to <i>Settings</i> → <i>Security</i>. - <strong>CAUTION: Your password will be saved without any encryption on the device!</strong><br>Please consider creating a dedicated app password! Open your Nextcloud in a browser and go to <i>Settings</i> → <i>Security</i>. + Password @@ -179,10 +183,22 @@ Add note + + Reload + + + + Updating... + + Last update + + never + + Modified @@ -191,6 +207,18 @@ Delete + + Deleting note + + + + No account yet + + + + Got to the settings to add an account + + No notes yet @@ -200,27 +228,11 @@ - Reload + No result - never - - - - No account yet - - - - Open the settings to configure your Nextcloud accounts - - - - Deleting note - - - - Got to the settings to add an account + Try another query @@ -228,15 +240,7 @@ - Updating... - - - - No result - - - - Try another query + Open the settings to configure your Nextcloud accounts @@ -366,6 +370,10 @@ For interoperability with other apps such as Joplin + + unknown + + UnencryptedDialog