API Implemented in javascript. Currently just readonly functionality. No possibility to set user credentials

This commit is contained in:
Scharel Clemens 2018-10-16 23:52:28 +02:00
parent 4b9a83cfb8
commit 53b94e99e2
17 changed files with 195 additions and 93 deletions

View file

@ -0,0 +1,13 @@
[Desktop Entry]
Type=Application
X-Nemo-Application-Type=silica-qt5
Icon=harbour-nextcloudnotes
Exec=harbour-nextcloudnotes
Name=harbour-nextcloudnotes
# translation example:
# your app name in German locale (de)
#
# Remember to comment out the following line, if you do not want to use
# a different app name in German locale (de).
Name[de]=harbour-nextcloudnotes
Name[de_DE]=harbour-nextcloudnotes.desktop

View file

@ -0,0 +1,43 @@
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = harbour-nextcloudnotes
CONFIG += sailfishapp
SOURCES += src/harbour-nextcloudnotes.cpp
DISTFILES += qml/harbour-nextcloudnotes.qml \
qml/cover/CoverPage.qml \
qml/pages/FirstPage.qml \
qml/pages/NotesApi.qml \
rpm/harbour-nextcloudnotes.changes.in \
rpm/harbour-nextcloudnotes.changes.run.in \
rpm/harbour-nextcloudnotes.spec \
rpm/harbour-nextcloudnotes.yaml \
translations/*.ts \
harbour-nextcloudnotes.desktop \
qml/pages/NotePage.qml
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the
# following CONFIG line
CONFIG += sailfishapp_i18n
# German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the
# following TRANSLATIONS line. And also do not forget to
# modify the localized app name in the the .desktop file.
TRANSLATIONS += translations/harbour-nextcloudnotes-de.ts
HEADERS +=

View file

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -9,21 +9,20 @@ ApplicationWindow
ConfigurationGroup { ConfigurationGroup {
id: appSettings id: appSettings
path: "/apps/harbour-nextcloud-notes/settings" path: "/apps/harbour-nextcloudnotes/settings"
property string lastUpdate: qsTr("never") property string lastUpdate: qsTr("never")
property url nextcloudServer: "https://cloud.scharel.name" property url server: "https://cloud.scharel.name" + "/index.php/apps/notes/api/v0.2/notes"
property string username: "scharel" property string username: "test"
property string password: "" property string password // TODO provide password before testing
} }
property var notesModel: JSONListModel { property var notes: NotesApi {
url: appSettings.nextcloudServer + "/index.php/apps/notes/api/v0.2/notes"
name: "notes" name: "notes"
saveFile: false saveFile: false
} }
Connections { Connections {
target: notesModel target: notes
onLastUpdateChanged: appSettings.lastUpdate = notesModel.lastUpdate onLastUpdateChanged: appSettings.lastUpdate = notes.lastUpdate
} }
initialPage: Component { FirstPage { } } initialPage: Component { FirstPage { } }

View file

@ -1,6 +1,5 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
//import harbour.nextcloudnotes 0.1
Page { Page {
id: page id: page
@ -10,7 +9,7 @@ Page {
anchors.fill: parent anchors.fill: parent
PullDownMenu { PullDownMenu {
busy: notesModel.busy busy: notes.busy
MenuItem { MenuItem {
text: qsTr("Settings") text: qsTr("Settings")
onClicked: pageStack.push(Qt.resolvedUrl("Settings.qml")) onClicked: pageStack.push(Qt.resolvedUrl("Settings.qml"))
@ -20,42 +19,33 @@ Page {
onClicked: console.log("Add note") onClicked: console.log("Add note")
} }
MenuLabel { MenuLabel {
text: qsTr("Last update") + ": " + appSettings.lastUpdate text: qsTr("Last update") + ": " + new Date(appSettings.lastUpdate).toLocaleString(Qt.locale(), Locale.ShortFormat)
} }
} }
header: SearchField { header: SearchField {
width: parent.width width: parent.width
placeholderText: qsTr("Nextcloud Notes") placeholderText: qsTr("Nextcloud Notes")
onTextChanged: notesModel.search(text.toLowerCase()) onTextChanged: notes.search(text.toLowerCase())
EnterKey.iconSource: "image://theme/icon-m-enter-close" EnterKey.iconSource: "image://theme/icon-m-enter-close"
EnterKey.onClicked: focus = false EnterKey.onClicked: focus = false
enabled: notesModel.json.length > 0 enabled: notes.json.length > 0
} }
currentIndex: -1 currentIndex: -1
Component.onCompleted: notesModel.update() Component.onCompleted: notes.getNotes()
//Component.onCompleted: notes.getNote("1212725")
//Component.onCompleted: notes.createNote("Hello World!", "Test")
//Component.onCompleted: notes.updateNote(1212725, "# Hello World!\nIs this working?", "Test")
//Component.onCompleted: notes.deleteNote(1212725)
model: notesModel model: notes.model
delegate: ListItem { delegate: ListItem {
id: note id: note
contentHeight: Theme.itemSizeMedium contentHeight: Theme.itemSizeMedium
onClicked: {
pageStack.push(Qt.resolvedUrl("NotePage.qml"),
{id: id,
etag: etag,
modified: modified,
title: title,
category: category,
favorite: favorite,
content: content,
error: error,
errorMessage: errorMessage})
}
IconButton { IconButton {
id: isFavoriteIcon id: isFavoriteIcon
x: Theme.horizontalPageMargin x: Theme.horizontalPageMargin
@ -66,6 +56,7 @@ Page {
onClicked: { onClicked: {
console.log("Toggle favorite") console.log("Toggle favorite")
favorite = !favorite favorite = !favorite
notes.updateNote(id, {'favorite': favorite} )
} }
} }
@ -86,11 +77,13 @@ Page {
anchors.leftMargin: Theme.paddingSmall anchors.leftMargin: Theme.paddingSmall
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.verticalCenter anchors.top: parent.verticalCenter
text: new Date(modified * 1000).toLocaleDateString() text: new Date(modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
color: note.highlighted ? Theme.highlightColor : Theme.primaryColor color: note.highlighted ? Theme.highlightColor : Theme.primaryColor
} }
onClicked: pageStack.push(Qt.resolvedUrl("NotePage.qml"), { note: notesList.model.get(index) } )
menu: ContextMenu { menu: ContextMenu {
Text { Text {
id: descriptionText id: descriptionText
@ -114,17 +107,23 @@ Page {
section.criteria: ViewSection.FullString section.criteria: ViewSection.FullString
section.labelPositioning: ViewSection.InlineLabels section.labelPositioning: ViewSection.InlineLabels
section.delegate: SectionHeader { section.delegate: SectionHeader {
text: section.empty ? qsTr("No category") : section text: section
} }
BusyIndicator { BusyIndicator {
id: busyIndicator id: busyIndicator
anchors.centerIn: parent anchors.centerIn: parent
size: BusyIndicatorSize.Large size: BusyIndicatorSize.Large
visible: notesList.count === 0 visible: notesList.count === 0 && notes.busy
running: visible running: visible
} }
ViewPlaceholder {
enabled: notesList.count === 0 && !notes.busy
text: qsTr("No notes yet")
hintText: qsTr("Pull down to add a note")
}
VerticalScrollDecorator { flickable: notesList } VerticalScrollDecorator { flickable: notesList }
} }
} }

View file

@ -4,6 +4,8 @@ import Sailfish.Silica 1.0
Page { Page {
id: page id: page
property var note
property int id property int id
property string etag property string etag
property date modified property date modified
@ -29,14 +31,13 @@ Page {
width: parent.width// - 2*x width: parent.width// - 2*x
PageHeader { PageHeader {
title: page.title title: note.title
} }
TextArea { TextArea {
id: note
width: parent.width width: parent.width
readOnly: true readOnly: true
text: page.content text: note.content
} }
} }
VerticalScrollDecorator {} VerticalScrollDecorator {}

View file

@ -1,17 +1,87 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import Nemo.Configuration 1.0
ListModel { Item {
property url url
property string json
property string name property string name
property var model: ListModel { }
property string json
property string file: StandardPaths.data + "/" + name + ".json" property string file: StandardPaths.data + "/" + name + ".json"
property bool saveFile: false property bool saveFile: false
property bool busy: false property bool busy: false
property int status: 200
property date lastUpdate: new Date(0) property date lastUpdate: new Date(0)
function callApi(method, data) {
busy = true
var endpoint = ""
if (data && (method === "GET" || method === "PUT" || method === "DELETE"))
if (data.id)
endpoint = "/" + data.id
var apiReq = new XMLHttpRequest
apiReq.open(method, appSettings.server + endpoint, true)
apiReq.setRequestHeader('User-Agent', 'SailfishOS/harbour-lidderbuch')
apiReq.setRequestHeader('OCS-APIRequest', 'true')
apiReq.setRequestHeader("Content-Type", "application/json");
apiReq.setRequestHeader("Authorization", "Basic " + Qt.btoa(appSettings.username + ":" + appSettings.password))
apiReq.onreadystatechange = function() {
if (apiReq.readyState === XMLHttpRequest.DONE) {
if (apiReq.status === 200) {
console.log("Successfull request!")
console.log(apiReq.responseText)
// TODO handle non arrays
var elements = JSON.parse(apiReq.responseText)
for (var element in elements) {
model.append(elements[element])
}
}
else if (apiReq.status === 404) {
console.log("Note does not exist!")
}
else {
console.log("Unknown error: " + apiReq.statusText + " (" + apiReq.status + ")")
}
busy = false
}
}
if (method === "GET") {
apiReq.send()
}
else if (method === "POST" || method === "PUT" || method === "DELETE") {
apiReq.send(JSON.stringify(data))
}
else {
console.log("Unsupported method: " + method)
apiReq.abort()
}
}
function getNotes() {
callApi("GET")
}
function getNote(id) {
if (id)
callApi("GET", { 'id': id } )
}
function createNote(data) {
callApi("POST", data)
}
function updateNote(id, data) {
if (id) {
data.id = id
callApi("PUT", data)
}
}
function deleteNote(id) {
if (id)
callApi("DELETE", { 'id': id } )
}
onJsonChanged: refresh() onJsonChanged: refresh()
function flush() { function flush() {
@ -19,7 +89,7 @@ ListModel {
var filePut = new XMLHttpRequest var filePut = new XMLHttpRequest
filePut.open("PUT", file) filePut.open("PUT", file)
filePut.send(json) filePut.send(json)
clear() model.clear()
lastUpdate = new Date(0) lastUpdate = new Date(0)
status = 200 status = 200
} }
@ -29,7 +99,7 @@ ListModel {
} }
function search(query) { function search(query) {
clear() model.clear()
var elements = parseJson() var elements = parseJson()
for (var element in elements) { for (var element in elements) {
elements[element].section = "" elements[element].section = ""
@ -40,7 +110,7 @@ ListModel {
} }
} }
if (query === "" || match) if (query === "" || match)
append(elements[element]) model.append(elements[element])
} }
} }
@ -53,43 +123,12 @@ ListModel {
return null return null
} }
else { else {
clear() model.clear()
return elements return elements
} }
} }
function update() { /*Component.onCompleted: {
busy = true
var apiReq = new XMLHttpRequest
apiReq.open("GET", url, true)//, appSettings.username, appSettings.password)
apiReq.setRequestHeader('User-Agent', 'SailfishOS/harbour-lidderbuch')
apiReq.setRequestHeader('OCS-APIRequest', 'true')
apiReq.setRequestHeader("Authorization", "Basic " + Qt.btoa(appSettings.username + ":" + appSettings.password))
apiReq.onreadystatechange = function() {
if (apiReq.readyState === XMLHttpRequest.DONE) {
if (apiReq.status === 200) {
console.log("Successfully loaded " + url)
json = apiReq.responseText
//console.log(json)
if (saveFile) {
var filePut = new XMLHttpRequest
filePut.open("PUT", file)
filePut.send(json)
}
lastUpdate = new Date()
}
else {
console.log("Error loading " + url + " - " + apiReq.status)
//lastUpdate = new Date(0)
}
status = apiReq.status
busy = false
}
}
apiReq.send()
}
Component.onCompleted: {
if (saveFile) { if (saveFile) {
if (name === "") { if (name === "") {
saveFile = false saveFile = false
@ -113,5 +152,5 @@ ListModel {
fileReq.send() fileReq.send()
} }
} }
} }*/
} }

View file

@ -1,4 +1,4 @@
# Rename this file as harbour-nextcloud-notes.changes to include changelog # Rename this file as harbour-nextcloudnotes.changes to include changelog
# entries in your RPM file. # entries in your RPM file.
# #
# Add new changelog entries following the format below. # Add new changelog entries following the format below.
@ -7,7 +7,7 @@
# #
# Alternatively, if your changelog is automatically generated (e.g. with # Alternatively, if your changelog is automatically generated (e.g. with
# the git-change-log command provided with Sailfish OS SDK), create a # the git-change-log command provided with Sailfish OS SDK), create a
# harbour-nextcloud-notes.changes.run script to let mb2 run the required commands for you. # harbour-nextcloudnotes.changes.run script to let mb2 run the required commands for you.
# * date Author's Name <author's email> version-release # * date Author's Name <author's email> version-release
# - Summary of changes # - Summary of changes

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# #
# Rename this file as harbour-nextcloud-notes.changes.run to let mb2 automatically # Rename this file as harbour-nextcloudnotes.changes.run to let mb2 automatically
# generate changelog from well formatted Git commit messages and tag # generate changelog from well formatted Git commit messages and tag
# annotations. # annotations.

View file

@ -3,7 +3,7 @@
# Generated by: spectacle version 0.27 # Generated by: spectacle version 0.27
# #
Name: harbour-nextcloud-notes Name: harbour-nextcloudnotes
# >> macros # >> macros
# << macros # << macros
@ -19,7 +19,7 @@ Group: Qt/Qt
License: LICENSE License: LICENSE
URL: http://example.org/ URL: http://example.org/
Source0: %{name}-%{version}.tar.bz2 Source0: %{name}-%{version}.tar.bz2
Source100: harbour-nextcloud-notes.yaml Source100: harbour-nextcloudnotes.yaml
Requires: sailfishsilica-qt5 >= 0.10.9 Requires: sailfishsilica-qt5 >= 0.10.9
BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 BuildRequires: pkgconfig(sailfishapp) >= 1.0.2
BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(Qt5Core)

View file

@ -1,4 +1,4 @@
Name: harbour-nextcloud-notes Name: harbour-nextcloudnotes
Summary: Nextcloud Notes Summary: Nextcloud Notes
Version: 0.1 Version: 0.1
Release: 1 Release: 1

View file

@ -8,16 +8,16 @@ int main(int argc, char *argv[])
{ {
QGuiApplication* app = SailfishApp::application(argc, argv); QGuiApplication* app = SailfishApp::application(argc, argv);
app->setApplicationDisplayName("Nextcloud Notes"); app->setApplicationDisplayName("Nextcloud Notes");
app->setApplicationName("harbour-nextcloud-notes"); app->setApplicationName("harbour-nextcloudnotes");
app->setApplicationVersion("0.1"); app->setApplicationVersion("0.1");
app->setOrganizationDomain("https://github.com/scharel"); app->setOrganizationDomain("https://github.com/scharel");
app->setOrganizationName("harbour-nextcloud-notes"); app->setOrganizationName("harbour-nextcloudnotes");
qDebug() << app->applicationDisplayName() << app->applicationVersion(); qDebug() << app->applicationDisplayName() << app->applicationVersion();
QQuickView* view = SailfishApp::createView(); QQuickView* view = SailfishApp::createView();
view->setSource(SailfishApp::pathTo("qml/harbour-nextcloud-notes.qml")); view->setSource(SailfishApp::pathTo("qml/harbour-nextcloudnotes.qml"));
view->show(); view->show();
return app->exec(); return app->exec();

View file

@ -18,6 +18,10 @@
<source>Add note</source> <source>Add note</source>
<translation>Neue Notiz</translation> <translation>Neue Notiz</translation>
</message> </message>
<message>
<source>Last update</source>
<translation>Zuletzt aktualisiert</translation>
</message>
<message> <message>
<source>Nextcloud Notes</source> <source>Nextcloud Notes</source>
<translation>Nextcloud Notizen</translation> <translation>Nextcloud Notizen</translation>
@ -27,16 +31,16 @@
<translation>Löschen</translation> <translation>Löschen</translation>
</message> </message>
<message> <message>
<source>No category</source> <source>No notes yet</source>
<translation>Ohne Kategorie</translation> <translatio>Noch keine Notizen</translation>
</message> </message>
<message> <message>
<source>Last update</source> <source>Pull down to add a note</source>
<translation>Zuletzt aktualisiert</translation> <translation>Herunterziehen um eine neue Notiz zu erzeugen</translation>
</message> </message>
</context> </context>
<context> <context>
<name>harbour-nextcloud-notes</name> <name>harbour-nextcloudnotes</name>
<message> <message>
<source>never</source> <source>never</source>
<translation>noch nie</translation> <translation>noch nie</translation>

View file

@ -18,6 +18,10 @@
<source>Add note</source> <source>Add note</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Last update</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Nextcloud Notes</source> <source>Nextcloud Notes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -27,16 +31,16 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>No category</source> <source>No notes yet</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Last update</source> <source>Pull down to add a note</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
<name>harbour-nextcloud-notes</name> <name>harbour-nextcloudnotes</name>
<message> <message>
<source>never</source> <source>never</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>