Improved offline mode

This commit is contained in:
Scharel Clemens 2020-05-05 19:44:31 +02:00
parent 054afd4ca2
commit 6818edd94a
15 changed files with 112 additions and 98 deletions

View file

@ -57,8 +57,7 @@ ApplicationWindow
notesProxyModel.sourceModel.clear()
account.path = "/apps/harbour-nextcloudnotes/accounts/" + currentAccount
notesStore.account = currentAccount
notesStore.getAllNotes()
notesApi.getAllNotes()
notesModel.getAllNotes()
}
onSortByChanged: {
@ -148,13 +147,7 @@ ApplicationWindow
running: interval > 0 && notesApi.networkAccessible && appWindow.visible
triggeredOnStart: true
onTriggered: {
notesStore.getAllNotes()
if (!notesApi.busy) {
notesApi.getAllNotes();
}
else {
restart()
}
notesModel.getAllNotes()
}
onIntervalChanged: {
if (interval > 0) {
@ -198,7 +191,13 @@ ApplicationWindow
apiErrorNotification.publish()
}
}
onLastSyncChanged: account.update = lastSync
onLastSyncChanged: {
console.log("Last API sync: " + lastSync)
account.update = lastSync
}
}
Component.onCompleted: {
}
Component.onDestruction: {

View file

@ -28,7 +28,7 @@ Dialog {
property string errorMessage
onAccepted: {
notesApi.updateNote(id, { 'category': categoryField.text, 'content': contentArea.text, 'favorite': favoriteButton.selected, 'modified': new Date().valueOf() / 1000 } )
notesModel.updateNote(id, { 'category': categoryField.text, 'content': contentArea.text, 'favorite': favoriteButton.selected, 'modified': new Date().valueOf() / 1000 } )
}
SilicaFlickable {
@ -162,7 +162,7 @@ Dialog {
}
onFocusChanged: {
if (focus === false && text !== category) {
notesApi.updateNote(id, {'content': content, 'category': text}) // This does not seem to work without adding the content
notesModel.updateNote(id, {'content': content, 'category': text}) // This does not seem to work without adding the content
}
}
}

View file

@ -99,12 +99,12 @@ Dialog {
MenuItem {
text: qsTr("Delete")
onClicked: remorse.execute("Deleting", function() { notesApi.deleteNote(note["id"]) } )
onClicked: remorse.execute("Deleting", function() { notesModel.deleteNote(note["id"]) } )
}
MenuItem {
text: enabled ? qsTr("Reload") : qsTr("Updating...")
enabled: !notesApi.busy
onClicked: notesApi.getNote(note["id"])
onClicked: notesModel.getNote(note["id"])
}
/*MenuItem {
text: qsTr("Edit")
@ -158,7 +158,7 @@ Dialog {
} )
note["content"] = newContent
parseContent()
notesApi.updateNote(id, { 'content': note["content"] } )
notesModel.updateNote(id, { 'content': note["content"] } )
}
else if (/^tasklist:uncheckbox_(\d+)$/m.test(link)) {
newContent = newContent.replace(/- \[[xX]\] (.*)$/gm,
@ -170,7 +170,7 @@ Dialog {
} )
note["content"] = newContent
parseContent()
notesApi.updateNote(id, { 'content': note["content"] } )
notesModel.updateNote(id, { 'content': note["content"] } )
}
else {
Qt.openUrlExternally(link)
@ -230,7 +230,7 @@ Dialog {
icon.source: (selected ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(favoriteButton.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
onClicked: {
notesApi.updateNote(note["id"], {'favorite': selected, 'modified': new Date().valueOf() / 1000 })
notesModel.updateNote(note["id"], {'favorite': selected, 'modified': new Date().valueOf() / 1000 })
}
}
TextField {
@ -244,7 +244,7 @@ Dialog {
}
onFocusChanged: {
if (focus === false && text !== note["category"]) {
notesApi.updateNote(id, {'content': note["content"], 'category': text, 'modified': new Date().valueOf() / 1000}) // This does not seem to work without adding the content
notesModel.updateNote(id, {'content': note["content"], 'category': text, 'modified': new Date().valueOf() / 1000}) // This does not seem to work without adding the content
}
}
}

View file

@ -35,12 +35,12 @@ Page {
MenuItem {
text: qsTr("Add note")
enabled: appSettings.currentAccount.length > 0 && notesApi.networkAccessible
onClicked: notesApi.createNote( { 'content': "", 'modified': new Date().valueOf() / 1000 } )
onClicked: notesModel.createNote( { 'content': "", 'modified': new Date().valueOf() / 1000 } )
}
MenuItem {
text: notesApi.networkAccessible && !notesApi.busy ? qsTr("Reload") : qsTr("Updating...")
enabled: appSettings.currentAccount.length > 0 && notesApi.networkAccessible && !notesApi.busy
onClicked: notesApi.getAllNotes()
onClicked: notesModel.getAllNotes()
}
MenuLabel {
visible: appSettings.currentAccount.length > 0
@ -124,8 +124,7 @@ Page {
(note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
onClicked: {
var newFavorite = !favorite
notesStore.updateNote(id, {'favorite': newFavorite } )
notesApi.updateNote(id, {'favorite': newFavorite } )
notesModel.updateNote(id, {'favorite': newFavorite } )
}
}
@ -195,8 +194,7 @@ Page {
text: qsTr("Delete")
onClicked: {
remorse.execute(note, qsTr("Deleting note"), function() {
notesStore.deleteNote(id)
notesApi.deleteNote(id)
notesModel.deleteNote(id)
})
}
}

View file

@ -12,6 +12,9 @@
# * date Author's Name <author's email> version-release
# - Summary of changes
* Tue May 05 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.9-0
- Working offline mode
* Thu Apr 13 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.8-1
- Updated Signals and Slots between the modules

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.8
Release: 1
Version: 0.9
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.8
Release: 1
Version: 0.9
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

@ -57,6 +57,10 @@ const QList<int> NotesApi::noteIds() {
return m_syncedNotes.keys();
}
bool NotesApi::noteExists(const int id) {
return m_syncedNotes.contains(id);
}
int NotesApi::noteModified(const int id) {
return m_syncedNotes.value(id, -1);
}
@ -618,6 +622,8 @@ void NotesApi::updateApiNotes(const QJsonArray &json) {
}
}
}
m_lastSync = QDateTime::currentDateTime();
emit lastSyncChanged(m_lastSync);
emit allNotesChanged(ids);
}

View file

@ -145,6 +145,7 @@ public:
void setAccount(const QString& account);
const QList<int> noteIds();
bool noteExists(const int id);
int noteModified(const int id);
public slots:

View file

@ -19,6 +19,7 @@ public:
virtual void setAccount(const QString& account) = 0;
virtual const QList<int> noteIds() = 0;
virtual bool noteExists(const int id) = 0;
virtual int noteModified(const int id) = 0;
public slots:

View file

@ -27,18 +27,6 @@ int NotesProxyModel::roleFromName(const QString &name) const {
return roleNames().key(name.toLocal8Bit());
}
const QVariantMap NotesProxyModel::getNote(const QModelIndex &index) const {
QMap<int, QVariant> item = sourceModel()->itemData(mapToSource(index));
QHash<int, QByteArray> names = roleNames();
QVariantMap note;
QMapIterator<int, QVariant> i(item);
while (i.hasNext()) {
i.next();
note[names.value(i.key())] = i.value();
}
return note;
}
bool NotesProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const {
QAbstractItemModel* source = sourceModel();
if (m_favoritesOnTop && source->data(source_left, NotesModel::FavoriteRole).toBool() != source->data(source_right, NotesModel::FavoriteRole).toBool())
@ -131,15 +119,19 @@ void NotesModel::setAccount(const QString &account) {
}
const QList<int> NotesModel::noteIds() {
return m_notes.keys();
return mp_notesStore->noteIds();
}
bool NotesModel::noteExists(const int id) {
return mp_notesStore->noteExists(id);
}
int NotesModel::noteModified(const int id) {
return m_notes.value(id).value("modified").toInt(-1);
return mp_notesStore->noteModified(id);
}
const QVariantMap NotesModel::getNoteById(const int id) const {
return m_notes[id].toVariantMap();
return mp_notesStore->readNoteFile(id).toVariantMap();
}
bool NotesModel::getAllNotes(const QStringList &exclude) {
@ -205,11 +197,12 @@ void NotesModel::insert(const int id, const QJsonObject& note) {
//emit noteInserted(id, note);
qDebug() << "Note inserted";
}
if (mp_notesApi && mp_notesStore) {
if (sender() == mp_notesApi) {
// TODO
if (!mp_notesStore->noteExists(id)) {
mp_notesStore->createNote(note);
}
}
if (sender() == mp_notesStore) {
// TODO
}
}
@ -230,11 +223,17 @@ void NotesModel::update(const int id, const QJsonObject &note) {
qDebug() << "Note changed";
}
}
if (mp_notesApi && mp_notesStore) {
if (sender() == mp_notesApi) {
// TODO
if (Note::modified(note) > mp_notesStore->noteModified(id)) {
mp_notesStore->updateNote(id, note);
}
}
if (sender() == mp_notesStore) {
// TODO
if (Note::modified(note) > mp_notesApi->noteModified(id) && !mp_notesApi->lastSync().isNull()) {
mp_notesApi->updateNote(id, note);
}
}
}
}
@ -250,11 +249,13 @@ void NotesModel::remove(const int id) {
}
endRemoveRows();
}
if (mp_notesApi && mp_notesStore) {
if (sender() == mp_notesApi) {
// TODO
mp_notesStore->deleteNote(id);
}
if (sender() == mp_notesStore) {
// TODO
mp_notesApi->deleteNote(id);
}
}
}
@ -287,6 +288,7 @@ int NotesModel::rowCount(const QModelIndex &parent) const {
}
QVariant NotesModel::data(const QModelIndex &index, int role) const {
//qDebug();
QVariant data;
if (index.isValid() && index.row() <= m_notes.size()) {
QMap<int, QJsonObject>::const_iterator i = m_notes.cbegin();
@ -297,6 +299,7 @@ QVariant NotesModel::data(const QModelIndex &index, int role) const {
}
bool NotesModel::setData(const QModelIndex &index, const QVariant &value, int role) {
//qDebug();
if (index.isValid() && index.row() <= m_notes.size()) {
QMap<int, QJsonObject>::iterator i = m_notes.begin();
i += index.row();
@ -308,6 +311,7 @@ bool NotesModel::setData(const QModelIndex &index, const QVariant &value, int ro
}
QMap<int, QVariant> NotesModel::itemData(const QModelIndex &index) const {
//qDebug();
QMap<int, QVariant> map;
if (index.isValid() && index.row() <= m_notes.size()) {
for (int role = IdRole; role < NoneRole; ++role) {
@ -318,6 +322,7 @@ QMap<int, QVariant> NotesModel::itemData(const QModelIndex &index) const {
}
bool NotesModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles) {
//qDebug();
bool retval = true;
QMapIterator<int, QVariant> role(roles);
while (role.hasNext()) {

View file

@ -23,7 +23,6 @@ public:
Q_INVOKABLE void sort();
Q_INVOKABLE int roleFromName(const QString &name) const;
Q_INVOKABLE const QVariantMap getNote(const QModelIndex &index) const;
protected:
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
@ -73,6 +72,7 @@ public:
void setAccount(const QString& account);
const QList<int> noteIds();
bool noteExists(const int id);
int noteModified(const int id);
Q_INVOKABLE const QVariantMap getNoteById(const int id) const;

View file

@ -1,4 +1,5 @@
#include "notesstore.h"
#include "note.h"
#include <QJsonDocument>
#include <QDateTime>
@ -64,8 +65,13 @@ const QList<int> NotesStore::noteIds() {
return ids;
}
bool NotesStore::noteExists(const int id) {
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(id).arg(m_suffix));
return fileinfo.exists();
}
int NotesStore::noteModified(const int id) {
return readNoteFile(id, { "content" }).value("modified").toInt(-1);
return Note::modified(readNoteFile(id, { "content" }));
}
const QString NotesStore::errorMessage(ErrorCodes error) const {
@ -99,11 +105,6 @@ const QString NotesStore::errorMessage(ErrorCodes error) const {
return message;
}
bool NotesStore::noteFileExists(const int id) const {
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(id).arg(m_suffix));
return fileinfo.exists();
}
QJsonObject NotesStore::readNoteFile(const int id, const QStringList& exclude) {
QJsonObject json;
QFileInfo fileinfo(m_dir, QString("%1.%2").arg(id).arg(m_suffix));
@ -201,7 +202,7 @@ bool NotesStore::createNote(const QJsonObject& note) {
// TODO probably crate files with an '.json.<NUMBER>.new' extension
qDebug() << "Creating notes without the server API is not supported yet!";
}
else if (!noteFileExists(id)) {
else if (!noteExists(id)) {
if (writeNoteFile(id, note)) {
emit noteUpdated(id, note);
return true;

View file

@ -25,6 +25,7 @@ public:
void setAccount(const QString& account);
const QList<int> noteIds();
bool noteExists(const int id);
int noteModified(const int id);
enum ErrorCodes {
@ -39,7 +40,6 @@ public:
Q_ENUM(ErrorCodes)
Q_INVOKABLE const QString errorMessage(ErrorCodes error) const;
bool noteFileExists(const int id) const;
QJsonObject readNoteFile(const int id, const QStringList& exclude = QStringList());
bool writeNoteFile(const int id, const QJsonObject& note);
bool removeNoteFile(const int id);

View file

@ -316,32 +316,32 @@
<context>
<name>NotesApi</name>
<message>
<location filename="../src/notesapi.cpp" line="332"/>
<location filename="../src/notesapi.cpp" line="336"/>
<source>No error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="335"/>
<location filename="../src/notesapi.cpp" line="339"/>
<source>No network connection available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="338"/>
<location filename="../src/notesapi.cpp" line="342"/>
<source>Failed to communicate with the Nextcloud server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="341"/>
<location filename="../src/notesapi.cpp" line="345"/>
<source>An error occured while establishing an encrypted connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="344"/>
<location filename="../src/notesapi.cpp" line="348"/>
<source>Could not authenticate to the Nextcloud instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesapi.cpp" line="347"/>
<location filename="../src/notesapi.cpp" line="351"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
@ -384,62 +384,62 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="192"/>
<location filename="../qml/pages/NotesPage.qml" line="191"/>
<source>Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="195"/>
<location filename="../qml/pages/NotesPage.qml" line="194"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="197"/>
<location filename="../qml/pages/NotesPage.qml" line="196"/>
<source>Deleting note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="228"/>
<location filename="../qml/pages/NotesPage.qml" line="226"/>
<source>Loading notes...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="234"/>
<location filename="../qml/pages/NotesPage.qml" line="232"/>
<source>No account yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="235"/>
<location filename="../qml/pages/NotesPage.qml" line="233"/>
<source>Got to the settings to add an account</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="241"/>
<location filename="../qml/pages/NotesPage.qml" line="239"/>
<source>No notes yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="242"/>
<location filename="../qml/pages/NotesPage.qml" line="240"/>
<source>Pull down to add a note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="248"/>
<location filename="../qml/pages/NotesPage.qml" line="246"/>
<source>No result</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="249"/>
<location filename="../qml/pages/NotesPage.qml" line="247"/>
<source>Try another query</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="255"/>
<location filename="../qml/pages/NotesPage.qml" line="253"/>
<source>An error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="266"/>
<location filename="../qml/pages/NotesPage.qml" line="264"/>
<source>Open the settings to configure your Nextcloud accounts</source>
<translation type="unfinished"></translation>
</message>
@ -447,42 +447,42 @@
<context>
<name>NotesStore</name>
<message>
<location filename="../src/notesstore.cpp" line="75"/>
<location filename="../src/notesstore.cpp" line="81"/>
<source>No error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="78"/>
<location filename="../src/notesstore.cpp" line="84"/>
<source>File not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="81"/>
<location filename="../src/notesstore.cpp" line="87"/>
<source>Cannot read from the file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="84"/>
<location filename="../src/notesstore.cpp" line="90"/>
<source>Cannot write to the file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="87"/>
<location filename="../src/notesstore.cpp" line="93"/>
<source>Directory not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="90"/>
<location filename="../src/notesstore.cpp" line="96"/>
<source>Cannot read from directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="93"/>
<location filename="../src/notesstore.cpp" line="99"/>
<source>Cannot create or write to directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notesstore.cpp" line="96"/>
<location filename="../src/notesstore.cpp" line="102"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
@ -883,27 +883,27 @@ You can also use other markdown syntax inside them.</source>
<context>
<name>harbour-nextcloudnotes</name>
<message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="124"/>
<location filename="../qml/harbour-nextcloudnotes.qml" line="123"/>
<source>Notes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="125"/>
<location filename="../qml/harbour-nextcloudnotes.qml" line="124"/>
<source>Offline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="126"/>
<location filename="../qml/harbour-nextcloudnotes.qml" line="125"/>
<source>Synced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="140"/>
<location filename="../qml/harbour-nextcloudnotes.qml" line="139"/>
<source>API error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="133"/>
<location filename="../qml/harbour-nextcloudnotes.qml" line="132"/>
<source>File error</source>
<translation type="unfinished"></translation>
</message>