NotesStore and NotesApi Classes based on a common interface class. Seems to work fine :)

This commit is contained in:
Scharel Clemens 2020-04-10 20:40:23 +02:00
parent 1d4022bdbd
commit 4ea61c565f
16 changed files with 453 additions and 384 deletions

View file

@ -2,10 +2,6 @@ import QtQuick 2.2
import Sailfish.Silica 1.0
import Nemo.Configuration 1.0
import Nemo.Notifications 1.0
//import harbour.nextcloudnotes.note 1.0
//import harbour.nextcloudnotes.notesstore 1.0
import harbour.nextcloudnotes.notesapi 1.0
import harbour.nextcloudnotes.notesmodel 1.0
import "pages"
ApplicationWindow
@ -35,10 +31,10 @@ ApplicationWindow
onServerChanged: notesApi.server = server
onUsernameChanged: notesApi.username = username
onPasswordChanged: notesApi.password = password
onDoNotVerifySslChanged: notesApi.sslVerify = !doNotVerifySsl
onDoNotVerifySslChanged: notesApi.verifySsl = !doNotVerifySsl
onPathChanged: {
notesStore.account = appSettings.currentAccount
notesApi.dataFile = appSettings.currentAccount !== "" ? StandardPaths.data + "/" + appSettings.currentAccount + ".json" : ""
notesApi.account = appSettings.currentAccount
}
}
@ -142,55 +138,40 @@ ApplicationWindow
}
}
/*NotesStore {
id: notesStore
Component.onCompleted: getAllNotes()
onAccountChanged: {
console.log(account)
if (account !== "")
getAllNotes()
}
onNoteCreated: {
//console.log("Note created", createdNote.id)
}
onNoteUpdated: {
//console.log("Note updated", updatedNote.id)
}
onNoteDeleted: {
//console.log("Note deleted", deletedNoteId)
}
}*/
Connections {
target: notesStore
onAccountChanged: {
console.log(notesStore.account)
//console.log(notesStore.account)
if (notesStore.account !== "")
notesStore.getAllNotes()
}
onNoteUpdated: {
console.log("Note updated", note["id"])
//console.log("Note updated", note.id)
}
onNoteDeleted: {
console.log("Note deleted", note["id"])
//console.log("Note deleted", note.id)
}
}
NotesApi {
id: notesApi
Connections {
target: notesApi
onAccountChanged: {
//console.log(notesStore.account)
if (notesApi.account !== "")
notesApi.getAllNotes()
}
onNetworkAccessibleChanged: {
console.log("Device is " + (networkAccessible ? "online" : "offline"))
networkAccessible ? offlineNotification.close(Notification.Closed) : offlineNotification.publish()
console.log("Device is " + (accessible ? "online" : "offline"))
accessible ? offlineNotification.close(Notification.Closed) : offlineNotification.publish()
}
onError: {
if (error)
console.log("Error (" + error + "): " + errorMessage(error))
console.log("Error (" + error + "): " + notesApi.errorMessage(error))
errorNotification.close()
if (error && networkAccessible) {
errorNotification.body = errorMessage(error)
if (error && notesApi.networkAccessible) {
errorNotification.body = notesApi.errorMessage(error)
errorNotification.publish()
}
}

View file

@ -34,7 +34,7 @@ Page {
notesApi.server = server
notesApi.username = username
notesApi.password = password
notesApi.sslVerify = !doNotVerifySsl
notesApi.verifySsl = !doNotVerifySsl
notesApi.verifyLogin()
}
}
@ -277,7 +277,7 @@ Page {
description: qsTr("Enable this option to allow selfsigned certificates")
onCheckedChanged: {
account.doNotVerifySsl = checked
notesApi.sslVerify = !account.doNotVerifySsl
notesApi.verifySsl = !account.doNotVerifySsl
}
}
TextSwitch {

View file

@ -1,11 +1,10 @@
import QtQuick 2.2
import Sailfish.Silica 1.0
import harbour.nextcloudnotes.notesmodel 1.0
//import harbour.nextcloudnotes.notesmodel 1.0
Page {
id: page
property NotesModel notesModel: notesApi.model()
property string searchString
Connections {

View file

@ -12,6 +12,9 @@
# * date Author's Name <author's email> version-release
# - Summary of changes
* Fri Apr 10 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.7-0
- New methods for data handling are now usable
* Sun Apr 05 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.6-1
- Implementing new methods for data handling (files and API targets)

View file

@ -13,8 +13,8 @@ Name: harbour-nextcloudnotes
%{!?qtc_make:%define qtc_make make}
%{?qtc_builddir:%define _builddir %qtc_builddir}
Summary: Nextcloud Notes
Version: 0.6
Release: 1
Version: 0.7
Release: 0
Group: Applications/Editors
License: MIT
URL: https://github.com/scharel/harbour-nextcloudnotes

View file

@ -1,7 +1,7 @@
Name: harbour-nextcloudnotes
Summary: Nextcloud Notes
Version: 0.6
Release: 1
Version: 0.7
Release: 0
# 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: Applications/Editors

View file

@ -19,23 +19,54 @@ int main(int argc, char *argv[])
qDebug() << app->applicationDisplayName() << app->applicationVersion();
qRegisterMetaType<Note>();
qmlRegisterType<Note>("harbour.nextcloudnotes.note", 1, 0, "Note");
qmlRegisterType<NotesApi>("harbour.nextcloudnotes.notesapi", 1, 0, "NotesApi");
//qmlRegisterType<NotesStore>("harbour.nextcloudnotes.notesstore", 1, 0, "NotesStore");
qmlRegisterType<NotesProxyModel>("harbour.nextcloudnotes.notesmodel", 1, 0, "NotesModel");
NotesModel* notesModel = new NotesModel;
NotesProxyModel* notesProxyModel = new NotesProxyModel;
notesProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
notesProxyModel->setSortLocaleAware(true);
notesProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
notesProxyModel->setFilterRole(NotesModel::ContentRole);
notesProxyModel->setSourceModel(notesModel);
NotesStore* notesStore = new NotesStore;
NotesApi* notesApi = new NotesApi;
QObject::connect(notesApi, SIGNAL(noteUpdated(Note)), notesStore, SLOT(updateNote(Note)));
//QObject::connect(notesStore, SIGNAL(noteUpdated(Note)), notesApi, SLOT(updateNote(Note)));
QObject::connect(notesApi, SIGNAL(noteDeleted(int)), notesStore, SLOT(deleteNote(int)));
//QObject::connect(notesStore, SIGNAL(noteDeleted(int)), notesApi, SLOT(deleteNote(int)));
QObject::connect(notesStore, SIGNAL(noteUpdated(Note)), notesModel, SLOT(insertNote(Note)));
QObject::connect(notesStore, SIGNAL(noteDeleted(int)), notesModel, SLOT(removeNote(int)));
QObject::connect(notesApi, SIGNAL(noteUpdated(Note)), notesModel, SLOT(insertNote(Note)));
QObject::connect(notesApi, SIGNAL(noteDeleted(int)), notesModel, SLOT(removeNote(int)));
QQuickView* view = SailfishApp::createView();
view->rootContext()->setContextProperty("notesStore", notesStore);
view->setSource(SailfishApp::pathTo("qml/harbour-nextcloudnotes.qml"));
#ifdef QT_DEBUG
view->rootContext()->setContextProperty("debug", QVariant(true));
#else
view->rootContext()->setContextProperty("debug", QVariant(false));
#endif
view->rootContext()->setContextProperty("notesModel", notesProxyModel);
view->rootContext()->setContextProperty("notesStore", notesStore);
view->rootContext()->setContextProperty("notesApi", notesApi);
view->setSource(SailfishApp::pathTo("qml/harbour-nextcloudnotes.qml"));
view->show();
return app->exec();
int retval = app->exec();
QObject::disconnect(notesApi, SIGNAL(noteDeleted(int)), notesModel, SLOT(removeNote(int)));
QObject::disconnect(notesApi, SIGNAL(noteUpdated(Note)), notesModel, SLOT(insertNote(Note)));
QObject::disconnect(notesStore, SIGNAL(noteDeleted(int)), notesModel, SLOT(removeNote(int)));
QObject::disconnect(notesStore, SIGNAL(noteUpdated(Note)), notesModel, SLOT(insertNote(Note)));
//QObject::disconnect(notesStore, SIGNAL(noteDeleted(int)), notesApi, SLOT(deleteNote(int)));
QObject::disconnect(notesApi, SIGNAL(noteDeleted(int)), notesStore, SLOT(deleteNote(int)));
//QObject::disconnect(notesStore, SIGNAL(noteUpdated(Note)), notesApi, SLOT(updateNote(Note)));
QObject::disconnect(notesApi, SIGNAL(noteUpdated(Note)), notesStore, SLOT(updateNote(Note)));
notesApi->deleteLater();
notesStore->deleteLater();
notesProxyModel->deleteLater();
notesModel->deleteLater();
return retval;
}

View file

@ -1,5 +1,16 @@
#include "note.h"
const QMap<Note::NoteField, QString> Note::m_noteFieldNames = QMap<Note::NoteField, QString>( {
{Note::Id, "id"},
{Note::Modified, "modified"},
{Note::Title, "title"},
{Note::Category, "category"},
{Note::Content, "content"},
{Note::Favorite, "favorite"},
{Note::Etag, "etag"},
{Note::Error, "error"},
{Note::ErrorMessage, "errorMessage"} } );
Note::Note(QObject *parent) : QObject(parent) {
connectSignals();
}
@ -103,40 +114,54 @@ bool Note::operator >(const QJsonObject& note) const {
return modified() > modified(note);
}
QJsonObject Note::toJsonObject() const {
const QJsonObject Note::toJsonObject() const {
return m_json;
}
QJsonValue Note::toJsonValue() const {
const QJsonValue Note::toJsonValue() const {
return QJsonValue(m_json);
}
QJsonDocument Note::toJsonDocument() const {
const QJsonDocument Note::toJsonDocument() const {
return QJsonDocument(m_json);
}
int Note::id() const {
return m_json.value(ID).toInt(-1);
return m_json.value(noteFieldName(Id)).toInt(-1);
}
int Note::id(const QJsonObject &jobj) {
return jobj.value(ID).toInt(-1);
return jobj.value(noteFieldName(Id)).toInt(-1);
}
void Note::setId(int id) {
if (id >= 0) {
if (id != this->id()) {
m_json.insert(ID, QJsonValue(id));
m_json.insert(noteFieldName(Id), QJsonValue(id));
emit idChanged(this->id());
}
}
else {
m_json.remove(noteFieldName(Id));
emit idChanged(this->id());
}
}
int Note::modified() const {
return m_json.value(MODIFIED).toInt();
return m_json.value(noteFieldName(Modified)).toInt();
}
int Note::modified(const QJsonObject &jobj) {
return jobj.value(MODIFIED).toInt();
return jobj.value(noteFieldName(Modified)).toInt();
}
void Note::setModified(int modified) {
if (modified != this->modified()){
m_json.insert(MODIFIED, QJsonValue(modified));
if (modified > 0) {
if (modified != this->modified()) {
m_json.insert(noteFieldName(Modified), QJsonValue(modified));
emit modifiedChanged(this->modified());
emit modifiedStringChanged(modifiedString());
emit modifiedDateTimeChanged(modifiedDateTime());
}
}
else {
m_json.remove(noteFieldName(Modified));
emit modifiedChanged(this->modified());
emit modifiedStringChanged(modifiedString());
emit modifiedDateTimeChanged(modifiedDateTime());
@ -144,92 +169,128 @@ void Note::setModified(int modified) {
}
QString Note::title() const {
return m_json.value(TITLE).toString();
return m_json.value(noteFieldName(Title)).toString();
}
QString Note::title(const QJsonObject &jobj) {
return jobj.value(TITLE).toString();
return jobj.value(noteFieldName(Title)).toString();
}
void Note::setTitle(QString title) {
if (!title.isNull()) {
if (title != this->title()) {
m_json.insert(TITLE, QJsonValue(title));
m_json.insert(noteFieldName(Title), QJsonValue(title));
emit titleChanged(this->title());
}
}
else {
m_json.remove(noteFieldName(Title));
emit titleChanged(this->title());
}
}
QString Note::category() const {
return m_json.value(CATEGORY).toString();
return m_json.value(noteFieldName(Category)).toString();
}
QString Note::category(const QJsonObject &jobj) {
return jobj.value(CATEGORY).toString();
return jobj.value(noteFieldName(Category)).toString();
}
void Note::setCategory(QString category) {
if (!category.isNull()) {
if (category != this->category()) {
m_json.insert(CATEGORY, QJsonValue(category));
m_json.insert(noteFieldName(Category), QJsonValue(category));
emit categoryChanged(this->category());
}
}
else {
m_json.remove(noteFieldName(Category));
emit categoryChanged(this->category());
}
}
QString Note::content() const {
return m_json.value(CONTENT).toString();
return m_json.value(noteFieldName(Content)).toString();
}
QString Note::content(const QJsonObject &jobj) {
return jobj.value(CONTENT).toString();
return jobj.value(noteFieldName(Content)).toString();
}
void Note::setContent(QString content) {
if (!content.isNull()) {
if (content != this->content()) {
m_json.insert(CONTENT, QJsonValue(content));
m_json.insert(noteFieldName(Content), QJsonValue(content));
emit contentChanged(this->content());
}
}
else {
m_json.remove(noteFieldName(Content));
emit contentChanged(this->content());
}
}
bool Note::favorite() const {
return m_json.value(FAVORITE).toBool();
return m_json.value(noteFieldName(Favorite)).toBool();
}
bool Note::favorite(const QJsonObject &jobj) {
return jobj.value(FAVORITE).toBool();
return jobj.value(noteFieldName(Favorite)).toBool();
}
void Note::setFavorite(bool favorite) {
if (favorite != this->favorite()) {
m_json.insert(FAVORITE, QJsonValue(favorite));
m_json.insert(noteFieldName(Favorite), QJsonValue(favorite));
emit favoriteChanged(this->favorite());
}
}
QString Note::etag() const {
return m_json.value(ETAG).toString();
return m_json.value(noteFieldName(Etag)).toString();
}
QString Note::etag(const QJsonObject &jobj) {
return jobj.value(ETAG).toString();
return jobj.value(noteFieldName(Etag)).toString();
}
void Note::setEtag(QString etag) {
if (!etag.isNull()) {
if (etag != this->etag()) {
m_json.insert(ETAG, QJsonValue(etag));
m_json.insert(noteFieldName(Etag), QJsonValue(etag));
emit etagChanged(this->etag());
}
}
else {
m_json.remove(noteFieldName(Etag));
emit etagChanged(this->etag());
}
}
bool Note::error() const {
return m_json.value(ERROR).toBool(true);
return m_json.value(noteFieldName(Error)).toBool();
}
bool Note::error(const QJsonObject &jobj) {
return jobj.value(ERROR).toBool(true);
return jobj.value(noteFieldName(Error)).toBool();
}
void Note::setError(bool error) {
if (error) {
if (error != this->error()) {
m_json.insert(ERROR, QJsonValue(error));
m_json.insert(noteFieldName(Error), QJsonValue(error));
emit errorChanged(this->error());
}
}
else {
m_json.remove(noteFieldName(Error));
emit errorChanged(this->error());
}
}
QString Note::errorMessage() const {
return m_json.value(ERRORMESSAGE).toString();
return m_json.value(noteFieldName(ErrorMessage)).toString();
}
QString Note::errorMessage(const QJsonObject &jobj) {
return jobj.value(ERRORMESSAGE).toString();
return jobj.value(noteFieldName(ErrorMessage)).toString();
}
void Note::setErrorMessage(QString errorMessage) {
if (!errorMessage.isNull()) {
if (errorMessage != this->errorMessage()) {
m_json.insert(ERRORMESSAGE, QJsonValue(errorMessage));
m_json.insert(noteFieldName(ErrorMessage), QJsonValue(errorMessage));
emit errorMessageChanged(this->errorMessage());
}
}
else {
m_json.remove(noteFieldName(ErrorMessage));
emit errorMessageChanged(this->errorMessage());
}
}
@ -249,7 +310,7 @@ QString Note::modifiedString(const QJsonObject &jobj) {
dateString = date.toLocalTime().toString("dddd");
else if (date.toLocalTime().toString("yyyy") == QDateTime::currentDateTime().toString("yyyy"))
dateString = date.toLocalTime().toString("MMMM");
else
else if (!date.isValid())
dateString = date.toLocalTime().toString("MMMM yyyy");
return dateString;
}

View file

@ -1,22 +1,13 @@
#ifndef NOTE_H
#ifndef NOTE_H
#define NOTE_H
#include <QObject>
#include <QJsonObject>
#include <QJsonDocument>
#include <QDateTime>
#include <QMap>
#include <QDebug>
#define ID "id"
#define MODIFIED "modified"
#define TITLE "title"
#define CATEGORY "category"
#define CONTENT "content"
#define FAVORITE "favorite"
#define ETAG "etag"
#define ERROR "error"
#define ERRORMESSAGE "errorMessage"
class Note : public QObject {
Q_OBJECT
@ -37,50 +28,77 @@ public:
bool operator >(const Note& note) const;
bool operator >(const QJsonObject& note) const;
QJsonObject toJsonObject() const;
QJsonValue toJsonValue() const;
QJsonDocument toJsonDocument() const;
bool isValid() const { return id() >= 0; }
const QJsonObject toJsonObject() const;
const QJsonValue toJsonValue() const;
const QJsonDocument toJsonDocument() const;
enum NoteField {
None = 0x0000,
Id = 0x0001,
Modified = 0x0002,
Title = 0x0004,
Category = 0x0008,
Content = 0x0010,
Favorite = 0x0020,
Etag = 0x0040,
Error = 0x0080,
ErrorMessage = 0x0100
};
Q_DECLARE_FLAGS(NoteFields, NoteField)
Q_FLAG(NoteFields)
Q_INVOKABLE static QList<NoteField> noteFields() {
return m_noteFieldNames.keys();
}
Q_INVOKABLE static QString noteFieldName(NoteField field) {
return m_noteFieldNames[field];
}
Q_INVOKABLE static QStringList noteFieldNames() {
return m_noteFieldNames.values();
}
Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged)
Q_INVOKABLE int id() const;
int id() const;
void setId(int id);
Q_PROPERTY(int modified READ modified WRITE setModified NOTIFY modifiedChanged)
Q_INVOKABLE int modified() const;
int modified() const;
void setModified(int modified);
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
Q_INVOKABLE QString title() const;
QString title() const;
void setTitle(QString title);
Q_PROPERTY(QString category READ category WRITE setCategory NOTIFY categoryChanged)
Q_INVOKABLE QString category() const;
QString category() const;
void setCategory(QString category);
Q_PROPERTY(QString content READ content WRITE setContent NOTIFY contentChanged)
Q_INVOKABLE QString content() const;
QString content() const;
void setContent(QString content);
Q_PROPERTY(bool favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged)
Q_INVOKABLE bool favorite() const;
bool favorite() const;
void setFavorite(bool favorite);
Q_PROPERTY(QString etag READ etag WRITE setEtag NOTIFY etagChanged)
Q_INVOKABLE QString etag() const;
QString etag() const;
void setEtag(QString etag);
Q_PROPERTY(bool error READ error WRITE setError NOTIFY errorChanged)
Q_INVOKABLE bool error() const;
bool error() const;
void setError(bool error);
Q_PROPERTY(QString errorMessage READ errorMessage WRITE setErrorMessage NOTIFY errorMessageChanged)
Q_INVOKABLE QString errorMessage() const;
QString errorMessage() const;
void setErrorMessage(QString errorMessage);
Q_PROPERTY(QString modifiedString READ modifiedString NOTIFY modifiedStringChanged)
Q_INVOKABLE QString modifiedString() const;
QString modifiedString() const;
Q_INVOKABLE QDateTime modifiedDateTime() const;
Q_PROPERTY(QDateTime modifiedDateTime READ modifiedDateTime NOTIFY modifiedDateTimeChanged)
QDateTime modifiedDateTime() const;
static int id(const QJsonObject& jobj);
static int modified(const QJsonObject& jobj);
@ -110,6 +128,7 @@ signals:
private:
QJsonObject m_json;
const static QMap<NoteField, QString> m_noteFieldNames;
void connectSignals();
};

View file

@ -6,7 +6,7 @@
#include <QDir>
NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, const QString ocsEndpoint, const QString notesEndpoint, QObject *parent)
: QObject(parent), m_statusEndpoint(statusEndpoint), m_loginEndpoint(loginEndpoint), m_ocsEndpoint(ocsEndpoint), m_notesEndpoint(notesEndpoint)
: NotesInterface(parent), m_statusEndpoint(statusEndpoint), m_loginEndpoint(loginEndpoint), m_ocsEndpoint(ocsEndpoint), m_notesEndpoint(notesEndpoint)
{
// TODO verify connections (also in destructor)
m_loginPollTimer.setInterval(POLL_INTERVALL);
@ -22,13 +22,6 @@ NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, co
m_status_needsDbUpgrade = false;
m_status_extendedSupport = false;
m_loginStatus = LoginStatus::LoginUnknown;
mp_model = new NotesModel(this);
mp_modelProxy = new NotesProxyModel(this);
mp_modelProxy->setSourceModel(mp_model);
mp_modelProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
mp_modelProxy->setSortLocaleAware(true);
mp_modelProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
mp_modelProxy->setFilterRole(NotesModel::ContentRole);
connect(this, SIGNAL(urlChanged(QUrl)), this, SLOT(verifyUrl(QUrl)));
connect(&m_manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(requireAuthentication(QNetworkReply*,QAuthenticator*)));
connect(&m_manager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)));
@ -40,7 +33,6 @@ NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, co
m_request.setRawHeader("OCS-APIREQUEST", "true");
m_authenticatedRequest = m_request;
m_authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json").toUtf8());
connect(mp_model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(saveToFile(QModelIndex,QModelIndex,QVector<int>)));
}
NotesApi::~NotesApi() {
@ -50,22 +42,118 @@ NotesApi::~NotesApi() {
disconnect(&m_manager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)));
disconnect(&m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
disconnect(&m_manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslError(QNetworkReply*,QList<QSslError>)));
disconnect(mp_model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(saveToFile(QModelIndex,QModelIndex,QVector<int>)));
m_jsonFile.close();
if (mp_modelProxy)
delete mp_modelProxy;
if (mp_model)
delete mp_model;
}
void NotesApi::setSslVerify(bool verify) {
void NotesApi::setAccount(const QString &account) {
if (account != m_account) {
m_account = account;
// TODO reset the class
emit accountChanged(m_account);
}
}
void NotesApi::getAllNotes(Note::NoteField exclude) {
QUrl url = apiEndpointUrl(m_notesEndpoint);
QStringList excludeFields;
QList<Note::NoteField> noteFields = Note::noteFields();
QFlags<Note::NoteField> flags(exclude);
for (int i = 0; i < noteFields.size(); ++i) {
if (flags.testFlag(noteFields[i])) {
excludeFields << Note::noteFieldName(noteFields[i]);
}
}
if (!excludeFields.isEmpty())
url.setQuery(QString(EXCLUDE_QUERY).append(excludeFields.join(",")));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "GET" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.get(m_authenticatedRequest);
emit busyChanged(true);
}
}
void NotesApi::getNote(const int id, Note::NoteField exclude) {
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/%1").arg(id));
QStringList excludeFields;
QList<Note::NoteField> noteFields = Note::noteFields();
QFlags<Note::NoteField> flags(exclude);
for (int i = 0; i < noteFields.size(); ++i) {
if (flags.testFlag(noteFields[i])) {
excludeFields << Note::noteFieldName(noteFields[i]);
}
}
if (!excludeFields.isEmpty())
url.setQuery(QString(EXCLUDE_QUERY).append(excludeFields.join(",")));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "GET" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.get(m_authenticatedRequest);
emit busyChanged(true);
}
}
void NotesApi::createNote(const Note &note) {
QUrl url = apiEndpointUrl(m_notesEndpoint);
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "POST" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.post(m_authenticatedRequest, noteApiData(note));
emit busyChanged(true);
}
}
void NotesApi::updateNote(const Note &note) {
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/%1").arg(note.id()));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "PUT" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.put(m_authenticatedRequest, noteApiData(note));
emit busyChanged(true);
}
}
void NotesApi::deleteNote(const int id) {
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/%1").arg(id));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "DELETE" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.deleteResource(m_authenticatedRequest);
emit busyChanged(true);
}
}
const QByteArray NotesApi::noteApiData(const Note &note) {
QJsonObject json = note.toJsonObject();
json.remove(Note::noteFieldName(Note::Id));
if (note.modified() == 0)
json.remove(Note::noteFieldName(Note::Modified));
if (note.title().isNull())
json.remove(Note::noteFieldName(Note::Title));
if (note.category().isNull())
json.remove(Note::noteFieldName(Note::Category));
if (note.content().isNull())
json.remove(Note::noteFieldName(Note::Content));
json.remove(Note::noteFieldName(Note::Etag));
json.remove(Note::noteFieldName(Note::Error));
json.remove(Note::noteFieldName(Note::ErrorMessage));
return QJsonDocument(json).toJson(QJsonDocument::Compact);
}
// TODO ab hier überarbeiten
void NotesApi::setVerifySsl(bool verify) {
if (verify != (m_request.sslConfiguration().peerVerifyMode() == QSslSocket::VerifyPeer)) {
m_request.sslConfiguration().setPeerVerifyMode(verify ? QSslSocket::VerifyPeer : QSslSocket::VerifyNone);
emit sslVerifyChanged(verify);
emit verifySslChanged(verify);
}
if (verify != (m_authenticatedRequest.sslConfiguration().peerVerifyMode() == QSslSocket::VerifyPeer)) {
m_authenticatedRequest.sslConfiguration().setPeerVerifyMode(verify ? QSslSocket::VerifyPeer : QSslSocket::VerifyNone);
emit sslVerifyChanged(verify);
emit verifySslChanged(verify);
}
}
@ -164,17 +252,6 @@ void NotesApi::setPath(QString path) {
}
}
void NotesApi::setDataFile(const QString &dataFile) {
if (dataFile != m_jsonFile.fileName()) {
m_jsonFile.close();
m_jsonFile.setFileName(dataFile);
QFileInfo fileinfo(m_jsonFile);
QDir filepath;
filepath.mkpath(fileinfo.absolutePath());
emit dataFileChanged(m_jsonFile.fileName());
}
}
bool NotesApi::getNcStatus() {
QUrl url = apiEndpointUrl(m_statusEndpoint);
qDebug() << "POST" << url.toDisplayString();
@ -249,75 +326,6 @@ void NotesApi::verifyLogin(QString username, QString password) {
}
}
void NotesApi::getAllNotes(QStringList excludeFields) {
QUrl url = apiEndpointUrl(m_notesEndpoint + "/notes");
if (!excludeFields.isEmpty())
url.setQuery(QString("exclude=").append(excludeFields.join(",")));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "GET" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.get(m_authenticatedRequest);
emit busyChanged(true);
}
}
void NotesApi::getNote(int noteId, QStringList excludeFields) {
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/notes/%1").arg(noteId));
if (!excludeFields.isEmpty())
url.setQuery(QString("exclude=").append(excludeFields.join(",")));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "GET" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.get(m_authenticatedRequest);
emit busyChanged(true);
}
}
void NotesApi::createNote(QVariantMap fields) {
// Update note in the model
Note note(QJsonObject::fromVariantMap(fields));
//mp_model->insertNote(note);
// Create note via the API
QUrl url = apiEndpointUrl(m_notesEndpoint + "/notes");
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "POST" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.post(m_authenticatedRequest, note.toJsonDocument().toJson());
emit busyChanged(true);
}
}
void NotesApi::updateNote(int noteId, QVariantMap fields) {
// Update note in the model
Note note(QJsonObject::fromVariantMap(fields));
mp_model->insertNote(note);
// Update note on the server
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/notes/%1").arg(noteId));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "PUT" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.put(m_authenticatedRequest, note.toJsonDocument().toJson());
emit busyChanged(true);
}
}
void NotesApi::deleteNote(int noteId) {
// Remove note from the model
mp_model->removeNote(noteId);
// Remove note from the server
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/notes/%1").arg(noteId));
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
qDebug() << "DELETE" << url.toDisplayString();
m_authenticatedRequest.setUrl(url);
m_notesReplies << m_manager.deleteResource(m_authenticatedRequest);
emit busyChanged(true);
}
mp_model->removeNote(noteId);
}
const QString NotesApi::errorMessage(ErrorCodes error) const {
QString message;
switch (error) {
@ -407,12 +415,10 @@ void NotesApi::replyFinished(QNetworkReply *reply) {
}
else if (m_notesReplies.contains(reply)) {
qDebug() << "Notes reply";
if (mp_model) {
if (mp_model->fromJsonDocument(json)) {
m_lastSync = QDateTime::currentDateTimeUtc();
emit lastSyncChanged(m_lastSync);
}
}
if (json.isArray())
updateApiNotes(json.array());
else if (json.isObject())
updateApiNote(json.object());
m_notesReplies.removeOne(reply);
emit busyChanged(busy());
}
@ -463,18 +469,6 @@ void NotesApi::sslError(QNetworkReply *reply, const QList<QSslError> &errors) {
emit error(SslHandshakeError);
}
void NotesApi::saveToFile(QModelIndex, QModelIndex, QVector<int>) {
if (m_jsonFile.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) {
//qDebug() << "Writing data to file" << m_jsonFile.fileName();
QByteArray data = mp_model->toJsonDocument().toJson();
if (m_jsonFile.write(data) < data.size())
emit error(LocalFileWriteError);
m_jsonFile.close();
}
else
emit error(LocalFileWriteError);
}
QUrl NotesApi::apiEndpointUrl(const QString endpoint) const {
QUrl url = server();
url.setPath(url.path() + endpoint);
@ -593,3 +587,16 @@ void NotesApi::setLoginStatus(LoginStatus status, bool *changed) {
emit loginStatusChanged(m_loginStatus);
}
}
void NotesApi::updateApiNotes(const QJsonArray &json) {
for (int i = 0; i < json.size(); ++i) {
if (json[i].isObject())
updateApiNote(json[i].toObject());
}
}
void NotesApi::updateApiNote(const QJsonObject &json) {
Note note(json);
if (!note.error())
emit noteUpdated(note);
}

View file

@ -8,31 +8,22 @@
#include <QFile>
#include <QTimer>
#include <QDebug>
#include "notesinterface.h"
#include "notesmodel.h"
#define STATUS_ENDPOINT "/status.php"
#define LOGIN_ENDPOINT "/index.php/login/v2"
#define NOTES_ENDPOINT "/index.php/apps/notes/api/v0.2"
#define NOTES_ENDPOINT "/index.php/apps/notes/api/v0.2/notes"
#define OCS_ENDPOINT "/ocs/v1.php/cloud"
#define EXCLUDE_QUERY "exclude="
#define POLL_INTERVALL 5000
/*
m_noteFieldNames[Id] = "id";
m_noteFieldNames[Modified] = "modified";
m_noteFieldNames[Title] = "title";
m_noteFieldNames[Category] = "category";
m_noteFieldNames[Content] = "content";
m_noteFieldNames[Favorite] = "favorite";
m_noteFieldNames[Etag] = "etag";
m_noteFieldNames[Error] = "error";
m_noteFieldNames[ErrorMessage] = "errorMessage";
*/
class NotesApi : public QObject
class NotesApi : public NotesInterface
{
Q_OBJECT
Q_PROPERTY(bool sslVerify READ sslVerify WRITE setSslVerify NOTIFY sslVerifyChanged)
Q_PROPERTY(bool verifySsl READ verifySsl() WRITE setVerifySsl NOTIFY verifySslChanged)
Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(bool urlValid READ urlValid NOTIFY urlValidChanged)
Q_PROPERTY(QString server READ server WRITE setServer NOTIFY serverChanged)
@ -42,7 +33,6 @@ class NotesApi : public QObject
Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged)
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(QString dataFile READ dataFile WRITE setDataFile NOTIFY dataFileChanged)
Q_PROPERTY(bool networkAccessible READ networkAccessible NOTIFY networkAccessibleChanged)
Q_PROPERTY(QDateTime lastSync READ lastSync NOTIFY lastSyncChanged)
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
@ -68,8 +58,8 @@ public:
QObject *parent = nullptr);
virtual ~NotesApi();
bool sslVerify() const { return m_authenticatedRequest.sslConfiguration().peerVerifyMode() == QSslSocket::VerifyPeer; }
void setSslVerify(bool verify);
bool verifySsl() const { return m_authenticatedRequest.sslConfiguration().peerVerifyMode() == QSslSocket::VerifyPeer; }
void setVerifySsl(bool verify);
QUrl url() const { return m_url; }
void setUrl(QUrl url);
@ -97,9 +87,6 @@ public:
QString path() const { return m_url.path(); }
void setPath(QString path);
QString dataFile() const { return m_jsonFile.fileName(); }
void setDataFile(const QString &dataFile);
bool networkAccessible() const { return m_manager.networkAccessible() == QNetworkAccessManager::Accessible; }
QDateTime lastSync() const { return m_lastSync; }
@ -142,12 +129,6 @@ public:
Q_INVOKABLE bool initiateFlowV2Login();
Q_INVOKABLE void abortFlowV2Login();
Q_INVOKABLE void verifyLogin(QString username = QString(), QString password = QString());
Q_INVOKABLE void getAllNotes(QStringList excludeFields = QStringList());
Q_INVOKABLE void getNote(int noteId, QStringList excludeFields = QStringList());
Q_INVOKABLE void createNote(QVariantMap fields = QVariantMap());
Q_INVOKABLE void updateNote(int noteId, QVariantMap fields = QVariantMap());
Q_INVOKABLE void deleteNote(int noteId);
Q_INVOKABLE NotesProxyModel* model() const { return mp_modelProxy; }
enum ErrorCodes {
NoError,
@ -161,8 +142,18 @@ public:
Q_ENUM(ErrorCodes)
Q_INVOKABLE const QString errorMessage(ErrorCodes error) const;
QString account() const { return m_account; }
void setAccount(const QString& account);
public slots:
Q_INVOKABLE void getAllNotes(Note::NoteField exclude = Note::None);
Q_INVOKABLE void getNote(const int id, Note::NoteField exclude = Note::None);
Q_INVOKABLE void createNote(const Note& note);
Q_INVOKABLE void updateNote(const Note& note);
Q_INVOKABLE void deleteNote(const int id);
signals:
void sslVerifyChanged(bool verify);
void verifySslChanged(bool verify);
void urlChanged(QUrl url);
void urlValidChanged(bool valid);
void serverChanged(QString server);
@ -200,17 +191,16 @@ private slots:
void replyFinished(QNetworkReply* reply);
void pollLoginUrl();
void sslError(QNetworkReply* reply, const QList<QSslError> &errors);
void saveToFile(QModelIndex,QModelIndex,QVector<int>);
private:
QString m_account;
static const QByteArray noteApiData(const Note& note);
QUrl m_url;
QNetworkAccessManager m_manager;
QNetworkRequest m_request;
QNetworkRequest m_authenticatedRequest;
QNetworkRequest m_ocsRequest;
QFile m_jsonFile;
NotesModel* mp_model;
NotesProxyModel* mp_modelProxy;
QUrl apiEndpointUrl(const QString endpoint) const;
// Nextcloud status.php
@ -248,6 +238,8 @@ private:
// Nextcloud Notes API - https://github.com/nextcloud/notes/wiki/Notes-0.2
const QString m_notesEndpoint;
QVector<QNetworkReply*> m_notesReplies;
void updateApiNotes(const QJsonArray& json);
void updateApiNote(const QJsonObject& json);
QDateTime m_lastSync;
};

View file

@ -2,8 +2,8 @@
#define NOTESINTERFACE_H
#include <QObject>
#include <QMap>
#include <QJsonObject>
#include "note.h"
class NotesInterface : public QObject
{
@ -13,50 +13,22 @@ class NotesInterface : public QObject
Q_CLASSINFO("url", "https://github.com/scharel/harbour-nextcloudnotes")
public:
explicit NotesInterface(QObject *parent = nullptr) : QObject(parent) {
m_noteFieldNames = QMap<NoteField, QString>( { {Id, "id"}, {Modified, "modified"}, {Title, "title"}, {Category, "category"}, {Content, "content"}, {Favorite, "favorite"}, {Etag, "etag"}, {Error, "error"}, {ErrorMessage, "errorMessage"} } );
}
explicit NotesInterface(QObject *parent = nullptr) : QObject(parent) { }
virtual QString account() const = 0;
virtual void setAccount(const QString& account) = 0;
enum NoteField {
None = 0x0000,
Id = 0x0001,
Modified = 0x0002,
Title = 0x0004,
Category = 0x0008,
Content = 0x0010,
Favorite = 0x0020,
Etag = 0x0040,
Error = 0x0080,
ErrorMessage = 0x0100
};
Q_DECLARE_FLAGS(NoteFields, NoteField)
Q_FLAG(NoteFields)
Q_INVOKABLE QList<NoteField> noteFields() const {
return m_noteFieldNames.keys();
}
Q_INVOKABLE QString noteFieldName(NoteField field) {
return m_noteFieldNames[field];
}
Q_INVOKABLE virtual void getAllNotes(NoteField exclude = None) = 0;
Q_INVOKABLE virtual void getNote(const int id, NoteField exclude = None) = 0;
Q_INVOKABLE virtual void createNote(const QJsonObject& note) = 0;
Q_INVOKABLE virtual void updateNote(const QJsonObject& note) = 0;
public slots:
Q_INVOKABLE virtual void getAllNotes(Note::NoteField exclude = Note::None) = 0;
Q_INVOKABLE virtual void getNote(const int id, Note::NoteField exclude = Note::None) = 0;
Q_INVOKABLE virtual void createNote(const Note& note) = 0;
Q_INVOKABLE virtual void updateNote(const Note& note) = 0;
Q_INVOKABLE virtual void deleteNote(const int id) = 0;
signals:
void accountChanged(const QString account);
void noteUpdated(const QJsonObject note);
void noteDeleted(const int deletedNoteId);
public slots:
protected:
QMap<NoteField, QString> m_noteFieldNames;
void accountChanged(const QString& account);
void noteUpdated(const Note& note);
void noteDeleted(const int id);
};
#endif // NOTESINTERFACE_H

View file

@ -41,10 +41,6 @@ public:
bool fromJsonDocument(const QJsonDocument &jdoc);
QJsonDocument toJsonDocument() const;
int insertNote(const Note &note);
bool removeNote(const Note &note);
bool removeNote(int id);
enum NoteRoles {
IdRole = Qt::UserRole,
ModifiedRole = Qt::UserRole + 1,
@ -67,6 +63,12 @@ public:
QMap<int, QVariant> itemData(const QModelIndex &index) const;
virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles);
public slots:
int insertNote(const Note &note);
bool removeNote(const Note &note);
bool removeNote(int id);
protected:
//void addNote(const QJsonValue &note);
QVector<int> ids() const;

View file

@ -1,15 +1,15 @@
#include "notesstore.h"
#include "note.h"
#include <QDebug>
const QString NotesStore::m_suffix = "json";
NotesStore::NotesStore(QString directory, QObject *parent) : NotesInterface(parent)
{
m_dir.setCurrent(directory);
m_dir.setPath("");
m_dir.setFilter(QDir::Files);
m_dir.setNameFilters( { "*.json" } );
m_dir.setNameFilters( { "*." + m_suffix } );
}
NotesStore::~NotesStore() {
@ -39,7 +39,7 @@ void NotesStore::setAccount(const QString& account) {
}
}
void NotesStore::getAllNotes(NoteField exclude) {
void NotesStore::getAllNotes(Note::NoteField exclude) {
QFileInfoList files = m_dir.entryInfoList();
for (int i = 0; i < files.size(); ++i) {
bool ok;
@ -50,30 +50,30 @@ void NotesStore::getAllNotes(NoteField exclude) {
}
}
void NotesStore::getNote(const int id, NoteField exclude) {
void NotesStore::getNote(const int id, Note::NoteField exclude) {
if (id >= 0) {
QJsonObject file = readNoteFile(id, exclude);
if (!file.empty())
emit noteUpdated(file);
Note note = readNoteFile(id, exclude);
if (note.isValid())
emit noteUpdated(note);
}
}
void NotesStore::createNote(const QJsonObject& note) {
if (Note::id(note) < 0) {
void NotesStore::createNote(const Note& note) {
if (!note.isValid()) {
// TODO probably crate files with an '.json.<NUMBER>.new' extension
qDebug() << "Creating notes without the server API is not supported yet!";
}
else if (!noteFileExists(Note::id(note))) {
else if (!noteFileExists(note.id())) {
if (writeNoteFile(note)) {
emit noteUpdated(note);
}
}
}
void NotesStore::updateNote(const QJsonObject& note) {
if (Note::id(note) >= 0) {
QJsonObject file = readNoteFile(Note::id(note));
if (!Note(file).equal(note)) {
void NotesStore::updateNote(const Note& note) {
if (note.isValid()) {
Note file = readNoteFile(note.id());
if (!file.equal(note)) {
if (writeNoteFile(note)) {
emit noteUpdated(note);
}
@ -88,25 +88,24 @@ void NotesStore::deleteNote(const int id) {
}
bool NotesStore::noteFileExists(const int id) const {
QFileInfo fileinfo(m_dir, QString("%1.json").arg(id));
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(id).arg(m_suffix));
return fileinfo.exists();
}
QJsonObject NotesStore::readNoteFile(const int id, NoteField exclude) const {
Note NotesStore::readNoteFile(const int id, Note::NoteField exclude) const {
QJsonObject json;
QFileInfo fileinfo(m_dir, QString("%1.json").arg(id));
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(id).arg(m_suffix));
QFile file(fileinfo.filePath());
if (file.exists()) {
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QByteArray data = file.readAll();
json = QJsonDocument::fromJson(data).object();
file.close();
QFlags<NoteField> flags(exclude);
QMapIterator<NoteField, QString> fields(m_noteFieldNames);
while (fields.hasNext()) {
fields.next();
if (flags.testFlag(fields.key())) {
json.remove(fields.value());
QList<Note::NoteField> noteFields = Note::noteFields();
QFlags<Note::NoteField> flags(exclude);
for (int i = 0; i < noteFields.size(); ++i) {
if (flags.testFlag(noteFields[i])) {
json.remove(Note::noteFieldName(noteFields[i]));
}
}
}
@ -114,10 +113,11 @@ QJsonObject NotesStore::readNoteFile(const int id, NoteField exclude) const {
return json;
}
bool NotesStore::writeNoteFile(const QJsonObject &note) const {
bool NotesStore::writeNoteFile(const Note &note) const {
bool success = false;
QJsonDocument json(note);
QFileInfo fileinfo(m_dir, QString("%1.json").arg(Note::id(note)));
if (!account().isEmpty()) {
QJsonDocument json = note.toJsonDocument();
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(note.id()).arg(m_suffix));
QFile file(fileinfo.filePath());
if (file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) {
QByteArray data = json.toJson();
@ -126,17 +126,20 @@ bool NotesStore::writeNoteFile(const QJsonObject &note) const {
}
file.close();
}
}
return success;
}
bool NotesStore::removeNoteFile(const int id) const {
bool success = false;
QFileInfo fileinfo(m_dir, QString("%1.json").arg(id));
if (!account().isEmpty()) {
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(id).arg(m_suffix));
QFile file(fileinfo.filePath());
if (file.exists()) {
if (file.remove()) {
success = true;
}
}
}
return success;
}

View file

@ -1,11 +1,12 @@
#ifndef NOTESSTORE_H
#define NOTESSTORE_H
#include "notesinterface.h"
#include <QObject>
#include <QStandardPaths>
#include <QDir>
#include "notesinterface.h"
class NotesStore : public NotesInterface
{
Q_OBJECT
@ -19,22 +20,20 @@ public:
QString account() const;
void setAccount(const QString& account);
Q_INVOKABLE void getAllNotes(NoteField exclude = None);
Q_INVOKABLE void getNote(const int id, NoteField exclude = None);
Q_INVOKABLE void createNote(const QJsonObject& note);
Q_INVOKABLE void updateNote(const QJsonObject& note);
Q_INVOKABLE void deleteNote(const int id);
signals:
public slots:
Q_INVOKABLE void getAllNotes(Note::NoteField exclude = Note::None);
Q_INVOKABLE void getNote(const int id, Note::NoteField exclude = Note::None);
Q_INVOKABLE void createNote(const Note& note);
Q_INVOKABLE void updateNote(const Note& note);
Q_INVOKABLE void deleteNote(const int id);
private:
QDir m_dir;
const static QString m_suffix;
bool noteFileExists(const int id) const;
QJsonObject readNoteFile(const int id, NoteField exclude = None) const;
bool writeNoteFile(const QJsonObject& note) const;
Note readNoteFile(const int id, Note::NoteField exclude = Note::None) const;
bool writeNoteFile(const Note& note) const;
bool removeNoteFile(const int id) const;
};

View file

@ -245,12 +245,12 @@
<context>
<name>Note</name>
<message>
<location filename="../src/note.cpp" line="245"/>
<location filename="../src/note.cpp" line="306"/>
<source>Today</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/note.cpp" line="247"/>
<location filename="../src/note.cpp" line="308"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
@ -311,37 +311,37 @@
<context>
<name>NotesApi</name>
<message>
<location filename="../src/notesapi.cpp" line="327"/>
<location filename="../src/notesapi.cpp" line="335"/>
<source>No network connection available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="330"/>
<location filename="../src/notesapi.cpp" line="338"/>
<source>Failed to communicate with the Nextcloud server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="333"/>
<location filename="../src/notesapi.cpp" line="341"/>
<source>An error happened while reading from the local storage</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="336"/>
<location filename="../src/notesapi.cpp" line="344"/>
<source>An error happened while writing to the local storage</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="339"/>
<location filename="../src/notesapi.cpp" line="347"/>
<source>An error occured while establishing an encrypted connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="342"/>
<location filename="../src/notesapi.cpp" line="350"/>
<source>Could not authenticate to the Nextcloud instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="345"/>
<location filename="../src/notesapi.cpp" line="353"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
@ -349,97 +349,97 @@
<context>
<name>NotesPage</name>
<message>
<location filename="../qml/pages/NotesPage.qml" line="55"/>
<location filename="../qml/pages/NotesPage.qml" line="54"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="59"/>
<location filename="../qml/pages/NotesPage.qml" line="58"/>
<source>Add note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="64"/>
<location filename="../qml/pages/NotesPage.qml" line="63"/>
<source>Reload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="64"/>
<location filename="../qml/pages/NotesPage.qml" line="63"/>
<source>Updating...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="70"/>
<location filename="../qml/pages/NotesPage.qml" line="69"/>
<source>Last update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="73"/>
<location filename="../qml/pages/NotesPage.qml" line="72"/>
<source>never</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="83"/>
<location filename="../qml/pages/NotesPage.qml" line="82"/>
<source>Nextcloud Notes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="224"/>
<location filename="../qml/pages/NotesPage.qml" line="223"/>
<source>Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="227"/>
<location filename="../qml/pages/NotesPage.qml" line="226"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="229"/>
<location filename="../qml/pages/NotesPage.qml" line="228"/>
<source>Deleting note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="259"/>
<location filename="../qml/pages/NotesPage.qml" line="258"/>
<source>Loading notes...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="265"/>
<location filename="../qml/pages/NotesPage.qml" line="264"/>
<source>No account yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="266"/>
<location filename="../qml/pages/NotesPage.qml" line="265"/>
<source>Got to the settings to add an account</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="272"/>
<location filename="../qml/pages/NotesPage.qml" line="271"/>
<source>No notes yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="273"/>
<location filename="../qml/pages/NotesPage.qml" line="272"/>
<source>Pull down to add a note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="279"/>
<location filename="../qml/pages/NotesPage.qml" line="278"/>
<source>No result</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="280"/>
<location filename="../qml/pages/NotesPage.qml" line="279"/>
<source>Try another query</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="286"/>
<location filename="../qml/pages/NotesPage.qml" line="285"/>
<source>An error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="297"/>
<location filename="../qml/pages/NotesPage.qml" line="296"/>
<source>Open the settings to configure your Nextcloud accounts</source>
<translation type="unfinished"></translation>
</message>