Just pushing to github to have the code available somewhere else

This commit is contained in:
Scharel Clemens 2020-04-15 08:31:04 +02:00
parent 4ff667e3d1
commit 312be40fcf
18 changed files with 232 additions and 333 deletions

View file

@ -18,7 +18,6 @@ DEFINES += APP_VERSION=\\\"$$VERSION\\\"
HEADERS += src/note.h \ HEADERS += src/note.h \
src/notesapi.h \ src/notesapi.h \
src/notesinterface.h \
src/notesmodel.h \ src/notesmodel.h \
src/notesstore.h src/notesstore.h

View file

@ -54,7 +54,7 @@ ApplicationWindow
property bool useCapitalX: value("useCapitalX", false, Boolean) property bool useCapitalX: value("useCapitalX", false, Boolean)
onCurrentAccountChanged: { onCurrentAccountChanged: {
notesModel.sourceModel.clear() notesProxyModel.sourceModel.clear()
account.path = "/apps/harbour-nextcloudnotes/accounts/" + currentAccount account.path = "/apps/harbour-nextcloudnotes/accounts/" + currentAccount
notesStore.account = currentAccount notesStore.account = currentAccount
notesStore.getAllNotes() notesStore.getAllNotes()
@ -64,12 +64,12 @@ ApplicationWindow
onSortByChanged: { onSortByChanged: {
if (sortBy == "none") if (sortBy == "none")
notesModel.invalidate() notesProxyModel.invalidate()
else else
notesModel.sortRole = notesModel.roleFromName(sortBy) notesProxyModel.sortRole = notesProxyModel.roleFromName(sortBy)
} }
onFavoritesOnTopChanged: { onFavoritesOnTopChanged: {
notesModel.favoritesOnTop = favoritesOnTop notesProxyModel.favoritesOnTop = favoritesOnTop
} }
function addAccount() { function addAccount() {

View file

@ -6,7 +6,7 @@ Dialog {
id: noteDialog id: noteDialog
property int index property int index
property var note: notesModel.getNote(notesModel.index(index, 0)) property var note: notesProxyModel.getNote(notesProxyModel.index(index, 0))
property var showdown: ShowDown.showdown property var showdown: ShowDown.showdown
@ -47,10 +47,10 @@ Dialog {
parseContent() parseContent()
} }
Connections { Connections {
target: notesModel target: notesProxyModel
onDataChanged: { onDataChanged: {
console.log(topLeft, bottomRight, index) console.log(topLeft, bottomRight, index)
if (notesModel.index(topLeft, bottomRight) === index) { if (notesProxyModel.index(topLeft, bottomRight) === index) {
console.log("This note changed") console.log("This note changed")
} }
else { else {

View file

@ -7,7 +7,7 @@ Page {
property string searchString property string searchString
onStatusChanged: { onStatusChanged: {
if (status === PageStatus.Active) { if (status === PageStatus.Activating) {
if (accounts.value.length <= 0) { if (accounts.value.length <= 0) {
addAccountHint.restart() addAccountHint.restart()
} }
@ -15,6 +15,9 @@ Page {
autoSyncTimer.restart() autoSyncTimer.restart()
} }
} }
else if (status === PageStatus.Deactivating) {
autoSyncTimer.stop()
}
} }
SilicaListView { SilicaListView {
@ -59,7 +62,7 @@ Page {
EnterKey.onClicked: focus = false EnterKey.onClicked: focus = false
onTextChanged: { onTextChanged: {
searchString = text searchString = text
notesModel.setFilterFixedString(text) notesProxyModel.setFilterFixedString(text)
} }
} }
Label { Label {
@ -84,7 +87,7 @@ Page {
currentIndex: -1 currentIndex: -1
model: notesModel model: notesProxyModel
delegate: BackgroundItem { delegate: BackgroundItem {
id: note id: note
@ -120,9 +123,9 @@ Page {
icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") + icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) (note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
onClicked: { onClicked: {
console.log("Setting favoirte: " + !favorite) var newFavorite = !favorite
notesStore.updateNote(id, {'favorite': !favorite, 'modified': new Date().valueOf() / 1000 } ) notesStore.updateNote(id, {'favorite': newFavorite } )
notesApi.updateNote(id, {'favorite': !favorite, 'modified': new Date().valueOf() / 1000 } ) notesApi.updateNote(id, {'favorite': newFavorite } )
} }
} }
@ -192,7 +195,7 @@ Page {
text: qsTr("Delete") text: qsTr("Delete")
onClicked: { onClicked: {
remorse.execute(note, qsTr("Deleting note"), function() { remorse.execute(note, qsTr("Deleting note"), function() {
//notesStore.deleteNote(id) notesStore.deleteNote(id)
notesApi.deleteNote(id) notesApi.deleteNote(id)
}) })
} }
@ -241,7 +244,7 @@ Page {
ViewPlaceholder { ViewPlaceholder {
id: noSearchPlaceholder id: noSearchPlaceholder
enabled: notesList.count === 0 && searchString !== "" //notesModel.filterRegExp !== "" enabled: notesList.count === 0 && searchString !== "" //notesProxyModel.filterRegExp !== ""
text: qsTr("No result") text: qsTr("No result")
hintText: qsTr("Try another query") hintText: qsTr("Try another query")
} }

View file

@ -2,7 +2,6 @@ import QtQuick 2.2
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import Nemo.Configuration 1.0 import Nemo.Configuration 1.0
import Nemo.Notifications 1.0 import Nemo.Notifications 1.0
//import harbour.nextcloudnotes.notesmodel 1.0
Page { Page {
id: page id: page

View file

@ -12,6 +12,9 @@
# * date Author's Name <author's email> version-release # * date Author's Name <author's email> version-release
# - Summary of changes # - Summary of changes
* Mon Apr 13 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.8-0
- New methods for data handling improved
* Fri Apr 10 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.7-0 * Fri Apr 10 2020 Scharel Clemens <harbour-nextcloudnotes@scharel.rocks> 0.7-0
- New methods for data handling are now usable - New methods for data handling are now usable

View file

@ -13,7 +13,7 @@ Name: harbour-nextcloudnotes
%{!?qtc_make:%define qtc_make make} %{!?qtc_make:%define qtc_make make}
%{?qtc_builddir:%define _builddir %qtc_builddir} %{?qtc_builddir:%define _builddir %qtc_builddir}
Summary: Nextcloud Notes Summary: Nextcloud Notes
Version: 0.7 Version: 0.8
Release: 0 Release: 0
Group: Applications/Editors Group: Applications/Editors
License: MIT License: MIT

View file

@ -1,6 +1,6 @@
Name: harbour-nextcloudnotes Name: harbour-nextcloudnotes
Summary: Nextcloud Notes Summary: Nextcloud Notes
Version: 0.7 Version: 0.8
Release: 0 Release: 0
# The contents of the Group field should be one of the groups listed here: # The contents of the Group field should be one of the groups listed here:
# https://github.com/mer-tools/spectacle/blob/master/data/GROUPS # https://github.com/mer-tools/spectacle/blob/master/data/GROUPS

View file

@ -31,7 +31,7 @@ int main(int argc, char *argv[])
NotesApi* notesApi = new NotesApi; NotesApi* notesApi = new NotesApi;
QObject::connect(notesApi, SIGNAL(noteUpdated(int, QJsonObject)), notesStore, SLOT(updateNote(int, QJsonObject))); QObject::connect(notesApi, SIGNAL(noteUpdated(int, QJsonObject)), notesStore, SLOT(updateNote(int, QJsonObject)));
//QObject::connect(notesStore, SIGNAL(noteUpdated(Note)), notesApi, SLOT(updateNote(Note))); //QObject::connect(notesStore, SIGNAL(noteUpdated(int, QJsonObject)), notesApi, SLOT(updateNote(int, QJsonObject)));
QObject::connect(notesApi, SIGNAL(noteDeleted(int)), notesStore, SLOT(deleteNote(int))); QObject::connect(notesApi, SIGNAL(noteDeleted(int)), notesStore, SLOT(deleteNote(int)));
//QObject::connect(notesStore, SIGNAL(noteDeleted(int)), notesApi, SLOT(deleteNote(int))); //QObject::connect(notesStore, SIGNAL(noteDeleted(int)), notesApi, SLOT(deleteNote(int)));
@ -46,7 +46,8 @@ int main(int argc, char *argv[])
#else #else
view->rootContext()->setContextProperty("debug", QVariant(false)); view->rootContext()->setContextProperty("debug", QVariant(false));
#endif #endif
view->rootContext()->setContextProperty("notesModel", notesProxyModel); view->rootContext()->setContextProperty("notesModel", notesModel);
view->rootContext()->setContextProperty("notesProxyModel", notesProxyModel);
view->rootContext()->setContextProperty("notesStore", notesStore); view->rootContext()->setContextProperty("notesStore", notesStore);
view->rootContext()->setContextProperty("notesApi", notesApi); view->rootContext()->setContextProperty("notesApi", notesApi);

View file

@ -8,6 +8,7 @@
#include <QMap> #include <QMap>
#include <QDebug> #include <QDebug>
// TODO derive from QJsonObject
class Note : public QObject { class Note : public QObject {
Q_OBJECT Q_OBJECT

View file

@ -3,10 +3,11 @@
#include <QAuthenticator> #include <QAuthenticator>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray>
#include <QDir> #include <QDir>
NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, const QString ocsEndpoint, const QString notesEndpoint, QObject *parent) NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, const QString ocsEndpoint, const QString notesEndpoint, QObject *parent)
: NotesInterface(parent), m_statusEndpoint(statusEndpoint), m_loginEndpoint(loginEndpoint), m_ocsEndpoint(ocsEndpoint), m_notesEndpoint(notesEndpoint) : m_statusEndpoint(statusEndpoint), m_loginEndpoint(loginEndpoint), m_ocsEndpoint(ocsEndpoint), m_notesEndpoint(notesEndpoint)
{ {
// TODO verify connections (also in destructor) // TODO verify connections (also in destructor)
m_loginPollTimer.setInterval(POLL_INTERVALL); m_loginPollTimer.setInterval(POLL_INTERVALL);
@ -41,15 +42,6 @@ NotesApi::~NotesApi() {
disconnect(&m_manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslError(QNetworkReply*,QList<QSslError>))); disconnect(&m_manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslError(QNetworkReply*,QList<QSslError>)));
} }
void NotesApi::setAccount(const QString &account) {
qDebug() << "Setting account: " << account;
if (account != m_account) {
m_account = account;
// TODO reset the class
emit accountChanged(m_account);
}
}
void NotesApi::getAllNotes(const QStringList& exclude) { void NotesApi::getAllNotes(const QStringList& exclude) {
qDebug() << "Getting all notes"; qDebug() << "Getting all notes";
QUrl url = apiEndpointUrl(m_notesEndpoint); QUrl url = apiEndpointUrl(m_notesEndpoint);
@ -113,14 +105,14 @@ void NotesApi::deleteNote(const int id) {
} }
bool NotesApi::busy() const { bool NotesApi::busy() const {
return !(m_getAllNotesReplies.empty() || return !(m_getAllNotesReplies.empty() &&
m_getNoteReplies.empty() || m_getNoteReplies.empty() &&
m_createNoteReplies.empty() || m_createNoteReplies.empty() &&
m_updateNoteReplies.empty() || m_updateNoteReplies.empty() &&
m_deleteNoteReplies.empty() || m_deleteNoteReplies.empty() &&
m_statusReplies.empty() || m_statusReplies.empty() &&
m_loginReplies.empty() || m_loginReplies.empty() &&
m_pollReplies.empty() || m_pollReplies.empty() &&
m_ocsReplies.empty()); m_ocsReplies.empty());
} }

View file

@ -2,6 +2,7 @@
#define NOTESAPI_H #define NOTESAPI_H
#include <QObject> #include <QObject>
#include <QJsonObject>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkReply> #include <QNetworkReply>
@ -9,9 +10,6 @@
#include <QTimer> #include <QTimer>
#include <QDebug> #include <QDebug>
#include "notesinterface.h"
#include "notesmodel.h"
#define STATUS_ENDPOINT "/status.php" #define STATUS_ENDPOINT "/status.php"
#define LOGIN_ENDPOINT "/index.php/login/v2" #define LOGIN_ENDPOINT "/index.php/login/v2"
#define NOTES_ENDPOINT "/index.php/apps/notes/api/v0.2/notes" #define NOTES_ENDPOINT "/index.php/apps/notes/api/v0.2/notes"
@ -19,7 +17,7 @@
#define EXCLUDE_QUERY "exclude=" #define EXCLUDE_QUERY "exclude="
#define POLL_INTERVALL 5000 #define POLL_INTERVALL 5000
class NotesApi : public NotesInterface class NotesApi : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -140,9 +138,6 @@ public:
Q_ENUM(ErrorCodes) Q_ENUM(ErrorCodes)
Q_INVOKABLE const QString errorMessage(int error) const; Q_INVOKABLE const QString errorMessage(int error) const;
QString account() const { return m_account; }
void setAccount(const QString& account);
public slots: public slots:
Q_INVOKABLE void getAllNotes(const QStringList& exclude = QStringList()); Q_INVOKABLE void getAllNotes(const QStringList& exclude = QStringList());
//void getAllNotes(Note::NoteField exclude); //void getAllNotes(Note::NoteField exclude);
@ -183,6 +178,11 @@ signals:
void loginStatusChanged(LoginStatus status); void loginStatusChanged(LoginStatus status);
void loginUrlChanged(QUrl url); void loginUrlChanged(QUrl url);
void noteCreated(const int id, const QJsonObject& note);
void noteUpdated(const int id, const QJsonObject& note);
void noteDeleted(const int id);
void noteError(ErrorCodes error);
public slots: public slots:
private slots: private slots:
@ -194,8 +194,6 @@ private slots:
void sslError(QNetworkReply* reply, const QList<QSslError> &errors); void sslError(QNetworkReply* reply, const QList<QSslError> &errors);
private: private:
QString m_account;
QUrl m_url; QUrl m_url;
QNetworkAccessManager m_manager; QNetworkAccessManager m_manager;
QNetworkRequest m_request; QNetworkRequest m_request;

View file

@ -1,42 +0,0 @@
#ifndef NOTESINTERFACE_H
#define NOTESINTERFACE_H
#include <QObject>
#include <QJsonObject>
class NotesInterface : public QObject
{
Q_OBJECT
Q_PROPERTY(QString account READ account WRITE setAccount NOTIFY accountChanged)
Q_CLASSINFO("author", "Scharel Clemens")
Q_CLASSINFO("url", "https://github.com/scharel/harbour-nextcloudnotes")
public:
explicit NotesInterface(QObject *parent = nullptr) : QObject(parent) {
}
virtual QString account() const = 0;
virtual void setAccount(const QString& account) = 0;
Q_INVOKABLE virtual const QString errorMessage(int error) const = 0;
public slots:
Q_INVOKABLE virtual void getAllNotes(const QStringList& exclude = QStringList()) = 0;
//virtual void getAllNotes(Note::NoteField exclude) = 0;
Q_INVOKABLE virtual void getNote(const int id, const QStringList& exclude = QStringList()) = 0;
//virtual void getNote(const int id, Note::NoteField) = 0;
Q_INVOKABLE virtual void createNote(const QJsonObject& note) = 0;
//virtual void createNote(const Note& note) = 0;
Q_INVOKABLE virtual void updateNote(const int id, const QJsonObject& note) = 0;
//virtual void updateNote(const Note& note) = 0;
Q_INVOKABLE virtual void deleteNote(const int id) = 0;
signals:
void accountChanged(const QString& account);
void noteError(int error);
void noteUpdated(const int id, const QJsonObject& note);
//void noteUpdated(const Note& note);
void noteDeleted(const int id);
};
#endif // NOTESINTERFACE_H

View file

@ -54,6 +54,19 @@ void NotesProxyModel::sort() {
QSortFilterProxyModel::sort(0); QSortFilterProxyModel::sort(0);
} }
const QHash<int, QByteArray> NotesModel::m_roleNames = QHash<int, QByteArray> ( {
{NotesModel::IdRole, "id"},
{NotesModel::ModifiedRole, "modified"},
{NotesModel::TitleRole, "title"},
{NotesModel::CategoryRole, "category"},
{NotesModel::ContentRole, "content"},
{NotesModel::FavoriteRole, "favorite"},
{NotesModel::EtagRole, "etag"},
{NotesModel::ErrorRole, "error"},
{NotesModel::ErrorMessageRole, "errorMessage"},
{NotesModel::ModifiedStringRole, "modifiedString"},
{NotesModel::NoneRole, "none"} } );
NotesModel::NotesModel(QObject *parent) : QAbstractListModel(parent) { NotesModel::NotesModel(QObject *parent) : QAbstractListModel(parent) {
} }
@ -62,55 +75,65 @@ NotesModel::~NotesModel() {
clear(); clear();
} }
QList<int> NotesModel::ids() const { const QJsonArray NotesModel::getAllNotes(const QStringList &exclude) {
QList<int> ids; qDebug() << "Getting all Notes";
for (int i = 0; i < m_notes.size(); ++i) { QJsonArray array;
ids.append(m_notes[i].id()); QMapIterator<int, QJsonObject> i(m_notes);
while (i.hasNext()) {
i.next();
array << QJsonValue(i.value());
} }
return ids; return array;
} }
int NotesModel::insertNote(const int id, const QJsonObject& note) { const QJsonObject NotesModel::getNote(const int id, const QStringList &exclude) {
qDebug() << "Inserting note: " << id; qDebug() << "Getting note: " << id;
Note tmpNote(note); return m_notes.value(id);
int position = m_notes.indexOf(tmpNote); }
if (position >= 0) {
if (m_notes.at(position).equal(tmpNote)) { void NotesModel::createNote(const int id, const QJsonObject &note) {
qDebug() << "Note already present and unchanged."; qDebug() << "New note, adding it";
if (!m_notes.contains(id)) {
beginInsertRows(QModelIndex(), indexOfNoteById(id), indexOfNoteById(id));
m_notes.insert(id, note);
emit noteUpdated(id, note);
endInsertRows();
}
else {
qDebug() << "Note already present";
}
}
void NotesModel::updateNote(const int id, const QJsonObject& note) {
qDebug() << "Updating note: " << id;
if (m_notes.contains(id)) {
if (m_notes.value(id) == note) {
qDebug() << "Note unchanged";
} }
else { else {
qDebug() << "Note already present, updating it."; m_notes.insert(id, note);
m_notes.replace(position, tmpNote); emit dataChanged(index(indexOfNoteById(id)), index(indexOfNoteById(id)));
emit dataChanged(index(position), index(position)); emit noteUpdated(id, note);
qDebug() << "Note changed";
} }
} }
else { else {
qDebug() << "New note, adding it"; qDebug() << "Note not found";
position = m_notes.size();
beginInsertRows(QModelIndex(), position, position);
m_notes.append(tmpNote);
endInsertRows();
emit dataChanged(index(position), index(position));
} }
return position;
} }
bool NotesModel::removeNote(const QJsonObject &note) { void NotesModel::deleteNote(const int id) {
Note tmpNote(note); qDebug() << "Removing note: " << id;
qDebug() << "Removing note: " << tmpNote.id(); if (m_notes.contains(id)) {
int position = m_notes.indexOf(tmpNote); beginRemoveRows(QModelIndex(), indexOfNoteById(id), indexOfNoteById(id));
if (position >= 0 && position < m_notes.size()) { if (m_notes.remove(id) == 0) {
beginRemoveRows(QModelIndex(), position, position); qDebug() << "Note not found";
m_notes.removeAt(position); }
else {
emit noteDeleted(id);
}
endRemoveRows(); endRemoveRows();
emit dataChanged(index(position), index(position));
return true;
} }
return false;
}
bool NotesModel::removeNote(int id) {
return removeNote(QJsonObject{ {"id", id} } );
} }
void NotesModel::clear() { void NotesModel::clear() {
@ -120,20 +143,12 @@ void NotesModel::clear() {
endResetModel(); endResetModel();
} }
int NotesModel::indexOfNoteById(int id) const {
return std::distance(m_notes.begin(), m_notes.lowerBound(id));
}
QHash<int, QByteArray> NotesModel::roleNames() const { QHash<int, QByteArray> NotesModel::roleNames() const {
return QHash<int, QByteArray> { return m_roleNames;
{NotesModel::IdRole, "id"},
{NotesModel::ModifiedRole, "modified"},
{NotesModel::TitleRole, "title"},
{NotesModel::CategoryRole, "category"},
{NotesModel::ContentRole, "content"},
{NotesModel::FavoriteRole, "favorite"},
{NotesModel::EtagRole, "etag"},
{NotesModel::ErrorRole, "error"},
{NotesModel::ErrorMessageRole, "errorMessage"},
{NotesModel::ModifiedStringRole, "modifiedString"},
{NotesModel::NoneRole, "none"}
};
} }
Qt::ItemFlags NotesModel::flags(const QModelIndex &index) const { Qt::ItemFlags NotesModel::flags(const QModelIndex &index) const {
@ -150,111 +165,29 @@ int NotesModel::rowCount(const QModelIndex &parent) const {
} }
QVariant NotesModel::data(const QModelIndex &index, int role) const { QVariant NotesModel::data(const QModelIndex &index, int role) const {
if (!index.isValid()) return QVariant(); QVariant data;
else if (role == IdRole) return m_notes[index.row()].id(); if (index.isValid() && index.row() <= m_notes.size()) {
else if (role == ModifiedRole) return m_notes[index.row()].modified(); QMap<int, QJsonObject>::const_iterator i = m_notes.cbegin();
else if (role == TitleRole) return m_notes[index.row()].title(); i += index.row();
else if (role == CategoryRole) return m_notes[index.row()].category(); data = i.value()[(m_roleNames[role])];
else if (role == ContentRole) return m_notes[index.row()].content(); }
else if (role == FavoriteRole) return m_notes[index.row()].favorite(); return data;
else if (role == EtagRole) return m_notes[index.row()].etag();
else if (role == ErrorRole) return m_notes[index.row()].error();
else if (role == ErrorMessageRole) return m_notes[index.row()].errorMessage();
else if (role == ModifiedStringRole) return m_notes[index.row()].modifiedString();
return QVariant();
} }
bool NotesModel::setData(const QModelIndex &index, const QVariant &value, int role) { bool NotesModel::setData(const QModelIndex &index, const QVariant &value, int role) {
bool retval = false; if (index.isValid() && index.row() <= m_notes.size()) {
if (index.isValid()) { QMap<int, QJsonObject>::iterator i = m_notes.begin();
switch (role) { i += index.row();
case IdRole: { i.value()[m_roleNames[role]] = QJsonValue::fromVariant(value);
double id = value.toInt(&retval); emit dataChanged(index, index, QVector<int>( role ));
if (retval && id != m_notes[index.row()].id()) { return true;
m_notes[index.row()].setId(id);
emit dataChanged(index, index, QVector<int>{ IdRole });
}
break;
}
case ModifiedRole: {
double modified = value.toInt(&retval);
if (retval && modified != m_notes[index.row()].modified()) {
m_notes[index.row()].setModified(modified);
emit dataChanged(index, index, QVector<int>{ ModifiedRole });
}
break;
}
case TitleRole: {
QString title = value.toString();
if (title != m_notes[index.row()].title()) {
m_notes[index.row()].setTitle(title);
emit dataChanged(index, index, QVector<int>{ TitleRole });
retval = true;
}
break;
}
case CategoryRole: {
QString category = value.toString();
if (category != m_notes[index.row()].category()) {
m_notes[index.row()].setCategory(category);
emit dataChanged(index, index, QVector<int>{ CategoryRole });
retval = true;
}
break;
}
case ContentRole: {
QString content = value.toString();
if (content != m_notes[index.row()].content()) {
m_notes[index.row()].setContent(content);
emit dataChanged(index, index, QVector<int>{ ContentRole });
retval = true;
}
break;
}
case FavoriteRole: {
bool favorite = value.toBool();
if (favorite != m_notes[index.row()].favorite()) {
m_notes[index.row()].setFavorite(favorite);
emit dataChanged(index, index, QVector<int>{ FavoriteRole });
retval = true;
}
break;
}
case EtagRole: {
QString etag = value.toString();
if (etag != m_notes[index.row()].etag()) {
m_notes[index.row()].setEtag(etag);
emit dataChanged(index, index, QVector<int>{ EtagRole });
retval = true;
}
break;
}
case ErrorRole: {
bool error = value.toBool();
if (error != m_notes[index.row()].error()) {
m_notes[index.row()].setError(error);
emit dataChanged(index, index, QVector<int>{ ErrorRole });
retval = true;
}
break;
}
case ErrorMessageRole: {
QString errorMessage = value.toString();
if (errorMessage != m_notes[index.row()].errorMessage()) {
m_notes[index.row()].setErrorMessage(errorMessage);
emit dataChanged(index, index, QVector<int>{ ErrorMessageRole });
retval = true;
}
break;
} }
} }
return retval; return false;
} }
QMap<int, QVariant> NotesModel::itemData(const QModelIndex &index) const { QMap<int, QVariant> NotesModel::itemData(const QModelIndex &index) const {
QMap<int, QVariant> map; QMap<int, QVariant> map;
if (!index.isValid()) return map; if (index.isValid() && index.row() <= m_notes.size()) {
else {
for (int role = IdRole; role < NoneRole; ++role) { for (int role = IdRole; role < NoneRole; ++role) {
map.insert(role, data(index, role)); map.insert(role, data(index, role));
} }

View file

@ -37,8 +37,6 @@ private:
class NotesModel : public QAbstractListModel { class NotesModel : public QAbstractListModel {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QList<int> ids READ ids NOTIFY idsChanged)
public: public:
explicit NotesModel(QObject *parent = 0); explicit NotesModel(QObject *parent = 0);
virtual ~NotesModel(); virtual ~NotesModel();
@ -66,18 +64,24 @@ public:
virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles); virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles);
public slots: public slots:
int insertNote(const int id, const QJsonObject& note); Q_INVOKABLE const QJsonArray getAllNotes(const QStringList& exclude = QStringList());
bool removeNote(const QJsonObject& note); Q_INVOKABLE const QJsonObject getNote(const int id, const QStringList& exclude = QStringList());
bool removeNote(int id); Q_INVOKABLE void createNote(const int id, const QJsonObject& note);
Q_INVOKABLE void updateNote(const int id, const QJsonObject& note);
Q_INVOKABLE void deleteNote(const int id);
Q_INVOKABLE void clear(); Q_INVOKABLE void clear();
Q_INVOKABLE QList<int> ids() const; Q_INVOKABLE int indexOfNoteById(int id) const;
signals: signals:
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int> ()); void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int> ());
void idsChanged(QList<int> ids); void noteCreated(const int id, const QJsonObject& note);
void noteUpdated(const int id, const QJsonObject& note);
void noteDeleted(const int id);
private: private:
QVector<Note> m_notes; QMap<int, QJsonObject> m_notes;
const static QHash<int, QByteArray> m_roleNames;
}; };
#endif // NOTESMODEL_H #endif // NOTESMODEL_H

View file

@ -6,7 +6,7 @@
const QString NotesStore::m_suffix = "json"; const QString NotesStore::m_suffix = "json";
NotesStore::NotesStore(QString directory, QObject *parent) : NotesInterface(parent) NotesStore::NotesStore(QString directory, QObject *parent)
{ {
m_dir.setCurrent(directory); m_dir.setCurrent(directory);
m_dir.setPath(""); m_dir.setPath("");
@ -45,7 +45,7 @@ void NotesStore::setAccount(const QString& account) {
} }
} }
const QString NotesStore::errorMessage(int error) const { const QString NotesStore::errorMessage(ErrorCodes error) const {
QString message; QString message;
switch (error) { switch (error) {
case NoError: case NoError:
@ -76,36 +76,39 @@ const QString NotesStore::errorMessage(int error) const {
return message; return message;
} }
void NotesStore::getAllNotes(const QStringList& exclude) { const QJsonArray NotesStore::getAllNotes(const QStringList& exclude) {
qDebug() << "Getting all notes"; qDebug() << "Getting all notes";
QJsonArray notes;
if (m_dir.exists()) { if (m_dir.exists()) {
QFileInfoList files = m_dir.entryInfoList(); QFileInfoList files = m_dir.entryInfoList();
for (int i = 0; i < files.size(); ++i) { for (int i = 0; i < files.size(); ++i) {
bool ok; bool ok;
int id = files[i].baseName().toInt(&ok); int id = files[i].baseName().toInt(&ok);
if (ok) { if (ok) {
getNote(id, exclude); notes.append(QJsonValue(getNote(id, exclude)));
} }
} }
} }
else { else {
qDebug() << errorMessage(DirNotFoundError);
emit noteError(DirCannotReadError); emit noteError(DirCannotReadError);
} }
return notes;
} }
void NotesStore::getNote(const int id, const QStringList& exclude) { const QJsonObject NotesStore::getNote(const int id, const QStringList& exclude) {
qDebug() << "Getting note: " << id; qDebug() << "Getting note: " << id;
QJsonObject note;
if (id >= 0) { if (id >= 0) {
QJsonObject note = readNoteFile(id, exclude); note = readNoteFile(id, exclude);
if (note.value("id").toInt(-1) >= 0)
emit noteUpdated(id, note);
} }
else { else {
qDebug() << "Skipping, invalid ID"; qDebug() << "Skipping, invalid ID";
} }
return note;
} }
void NotesStore::createNote(const QJsonObject& note) { bool NotesStore::createNote(const QJsonObject& note) {
int id = note.value("id").toInt(-1); int id = note.value("id").toInt(-1);
qDebug() << "Creating note: " << id; qDebug() << "Creating note: " << id;
if (id < 0) { if (id < 0) {
@ -115,14 +118,16 @@ void NotesStore::createNote(const QJsonObject& note) {
else if (!noteFileExists(id)) { else if (!noteFileExists(id)) {
if (writeNoteFile(id, note)) { if (writeNoteFile(id, note)) {
emit noteUpdated(id, note); emit noteUpdated(id, note);
return true;
} }
} }
else { else {
qDebug() << "Note already exists"; qDebug() << "Note already exists";
} }
return false;
} }
void NotesStore::updateNote(const int id, const QJsonObject& note) { const QJsonObject NotesStore::updateNote(const int id, const QJsonObject& note) {
qDebug() << "Updating note: " << id; qDebug() << "Updating note: " << id;
if (id >= 0) { if (id >= 0) {
QJsonObject tmpNote = readNoteFile(id); QJsonObject tmpNote = readNoteFile(id);
@ -133,14 +138,14 @@ void NotesStore::updateNote(const int id, const QJsonObject& note) {
tmpNote[fields[i]] = note[fields[i]]; tmpNote[fields[i]] = note[fields[i]];
} }
if (tmpNote.value("modified").toInt() == 0) { if (tmpNote.value("modified").toInt() == 0) {
tmpNote["modified"] = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000; tmpNote["modified"] = QJsonValue::fromVariant(QDateTime::currentDateTime().toTime_t());
} }
if (writeNoteFile(id, tmpNote)) { if (writeNoteFile(id, tmpNote)) {
emit noteUpdated(id, tmpNote); emit noteUpdated(id, tmpNote);
} }
} }
else { else {
qDebug() << "Skipping, note is older" << note.value("modified") << tmpNote.value("modified"); qDebug() << "Skipping, note is older" << QDateTime::fromTime_t(note.value("modified").toInt()) << QDateTime::fromTime_t(tmpNote.value("modified").toInt());
} }
} }
else { else {
@ -152,7 +157,7 @@ void NotesStore::updateNote(const int id, const QJsonObject& note) {
} }
} }
void NotesStore::deleteNote(const int id) { bool NotesStore::deleteNote(const int id) {
qDebug() << "Deleting note: " << id; qDebug() << "Deleting note: " << id;
if (removeNoteFile(id)) { if (removeNoteFile(id)) {
emit noteDeleted(id); emit noteDeleted(id);

View file

@ -2,12 +2,12 @@
#define NOTESSTORE_H #define NOTESSTORE_H
#include <QObject> #include <QObject>
#include <QStandardPaths> #include <QJsonArray>
#include <QJsonObject>
#include <QDir> #include <QDir>
#include <QStandardPaths>
#include "notesinterface.h" class NotesStore : public QObject
class NotesStore : public NotesInterface
{ {
Q_OBJECT Q_OBJECT
@ -30,18 +30,21 @@ public:
DirCannotWriteError DirCannotWriteError
}; };
Q_ENUM(ErrorCodes) Q_ENUM(ErrorCodes)
Q_INVOKABLE const QString errorMessage(int error) const; Q_INVOKABLE const QString errorMessage(ErrorCodes error) const;
public slots: public slots:
Q_INVOKABLE void getAllNotes(const QStringList& exclude = QStringList()); Q_INVOKABLE const QJsonArray getAllNotes(const QStringList& exclude = QStringList());
//void getAllNotes(Note::NoteField exclude); Q_INVOKABLE const QJsonObject getNote(const int id, const QStringList& exclude = QStringList());
Q_INVOKABLE void getNote(const int id, const QStringList& exclude = QStringList()); Q_INVOKABLE bool createNote(const QJsonObject& note);
//void getNote(const int id, Note::NoteField exclude); Q_INVOKABLE const QJsonObject updateNote(const int id, const QJsonObject& note);
Q_INVOKABLE void createNote(const QJsonObject& note); Q_INVOKABLE bool deleteNote(const int id);
//void createNote(const Note& note);
Q_INVOKABLE void updateNote(const int id, const QJsonObject& note); signals:
//void updateNote(const Note& note); void accountChanged(const QString& account);
Q_INVOKABLE void deleteNote(const int id); void noteCreated(const int id, const QJsonObject& note);
void noteUpdated(const int id, const QJsonObject& note);
void noteDeleted(const int id);
void noteError(const ErrorCodes error);
private: private:
QDir m_dir; QDir m_dir;

View file

@ -311,32 +311,32 @@
<context> <context>
<name>NotesApi</name> <name>NotesApi</name>
<message> <message>
<location filename="../src/notesapi.cpp" line="311"/> <location filename="../src/notesapi.cpp" line="303"/>
<source>No error</source> <source>No error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/notesapi.cpp" line="314"/> <location filename="../src/notesapi.cpp" line="306"/>
<source>No network connection available</source> <source>No network connection available</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/notesapi.cpp" line="317"/> <location filename="../src/notesapi.cpp" line="309"/>
<source>Failed to communicate with the Nextcloud server</source> <source>Failed to communicate with the Nextcloud server</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/notesapi.cpp" line="320"/> <location filename="../src/notesapi.cpp" line="312"/>
<source>An error occured while establishing an encrypted connection</source> <source>An error occured while establishing an encrypted connection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/notesapi.cpp" line="323"/> <location filename="../src/notesapi.cpp" line="315"/>
<source>Could not authenticate to the Nextcloud instance</source> <source>Could not authenticate to the Nextcloud instance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/notesapi.cpp" line="326"/> <location filename="../src/notesapi.cpp" line="318"/>
<source>Unknown error</source> <source>Unknown error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -344,97 +344,97 @@
<context> <context>
<name>NotesPage</name> <name>NotesPage</name>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="29"/> <location filename="../qml/pages/NotesPage.qml" line="32"/>
<source>Settings</source> <source>Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="33"/> <location filename="../qml/pages/NotesPage.qml" line="36"/>
<source>Add note</source> <source>Add note</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="38"/> <location filename="../qml/pages/NotesPage.qml" line="41"/>
<source>Reload</source> <source>Reload</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="38"/> <location filename="../qml/pages/NotesPage.qml" line="41"/>
<source>Updating...</source> <source>Updating...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="44"/> <location filename="../qml/pages/NotesPage.qml" line="47"/>
<source>Last update</source> <source>Last update</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="47"/> <location filename="../qml/pages/NotesPage.qml" line="50"/>
<source>never</source> <source>never</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="57"/> <location filename="../qml/pages/NotesPage.qml" line="60"/>
<source>Nextcloud Notes</source> <source>Nextcloud Notes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="189"/> <location filename="../qml/pages/NotesPage.qml" line="192"/>
<source>Modified</source> <source>Modified</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="192"/> <location filename="../qml/pages/NotesPage.qml" line="195"/>
<source>Delete</source> <source>Delete</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="194"/> <location filename="../qml/pages/NotesPage.qml" line="197"/>
<source>Deleting note</source> <source>Deleting note</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="225"/> <location filename="../qml/pages/NotesPage.qml" line="228"/>
<source>Loading notes...</source> <source>Loading notes...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="231"/> <location filename="../qml/pages/NotesPage.qml" line="234"/>
<source>No account yet</source> <source>No account yet</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="232"/> <location filename="../qml/pages/NotesPage.qml" line="235"/>
<source>Got to the settings to add an account</source> <source>Got to the settings to add an account</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="238"/> <location filename="../qml/pages/NotesPage.qml" line="241"/>
<source>No notes yet</source> <source>No notes yet</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="239"/> <location filename="../qml/pages/NotesPage.qml" line="242"/>
<source>Pull down to add a note</source> <source>Pull down to add a note</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="245"/> <location filename="../qml/pages/NotesPage.qml" line="248"/>
<source>No result</source> <source>No result</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="246"/> <location filename="../qml/pages/NotesPage.qml" line="249"/>
<source>Try another query</source> <source>Try another query</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="252"/> <location filename="../qml/pages/NotesPage.qml" line="255"/>
<source>An error occurred</source> <source>An error occurred</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/NotesPage.qml" line="263"/> <location filename="../qml/pages/NotesPage.qml" line="266"/>
<source>Open the settings to configure your Nextcloud accounts</source> <source>Open the settings to configure your Nextcloud accounts</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -485,188 +485,188 @@
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="17"/> <location filename="../qml/pages/SettingsPage.qml" line="16"/>
<source>About</source> <source>About</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="28"/> <location filename="../qml/pages/SettingsPage.qml" line="27"/>
<source>Settings</source> <source>Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="32"/> <location filename="../qml/pages/SettingsPage.qml" line="31"/>
<source>Accounts</source> <source>Accounts</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="37"/> <location filename="../qml/pages/SettingsPage.qml" line="36"/>
<source>No Nextcloud account yet</source> <source>No Nextcloud account yet</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="55"/> <location filename="../qml/pages/SettingsPage.qml" line="54"/>
<source>Unnamed account</source> <source>Unnamed account</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="54"/>
<location filename="../qml/pages/SettingsPage.qml" line="55"/> <location filename="../qml/pages/SettingsPage.qml" line="55"/>
<location filename="../qml/pages/SettingsPage.qml" line="56"/>
<source>unknown</source> <source>unknown</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="71"/> <location filename="../qml/pages/SettingsPage.qml" line="70"/>
<source>Edit</source> <source>Edit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="77"/> <location filename="../qml/pages/SettingsPage.qml" line="76"/>
<source>Delete</source> <source>Delete</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="79"/> <location filename="../qml/pages/SettingsPage.qml" line="78"/>
<source>Deleting account</source> <source>Deleting account</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="89"/> <location filename="../qml/pages/SettingsPage.qml" line="88"/>
<source>Add account</source> <source>Add account</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="98"/> <location filename="../qml/pages/SettingsPage.qml" line="97"/>
<source>Synchronization</source> <source>Synchronization</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="102"/> <location filename="../qml/pages/SettingsPage.qml" line="101"/>
<source>Auto-Sync</source> <source>Auto-Sync</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="103"/> <location filename="../qml/pages/SettingsPage.qml" line="102"/>
<source>Periodically pull notes from the server</source> <source>Periodically pull notes from the server</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="110"/> <location filename="../qml/pages/SettingsPage.qml" line="109"/>
<source>Disabled</source> <source>Disabled</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="110"/> <location filename="../qml/pages/SettingsPage.qml" line="109"/>
<source>every</source> <source>every</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="112"/> <location filename="../qml/pages/SettingsPage.qml" line="111"/>
<source>Minutes</source> <source>Minutes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="113"/> <location filename="../qml/pages/SettingsPage.qml" line="112"/>
<source>Seconds</source> <source>Seconds</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="134"/> <location filename="../qml/pages/SettingsPage.qml" line="133"/>
<source>The Answer is 42</source> <source>The Answer is 42</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="135"/> <location filename="../qml/pages/SettingsPage.qml" line="134"/>
<source>Congratulation you found the Answer to the Ultimate Question of Life, The Universe, and Everything!</source> <source>Congratulation you found the Answer to the Ultimate Question of Life, The Universe, and Everything!</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="143"/> <location filename="../qml/pages/SettingsPage.qml" line="142"/>
<source>Appearance</source> <source>Appearance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="151"/> <location filename="../qml/pages/SettingsPage.qml" line="150"/>
<source>No sorting</source> <source>No sorting</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="175"/> <location filename="../qml/pages/SettingsPage.qml" line="174"/>
<source>Favorites on top</source> <source>Favorites on top</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="176"/> <location filename="../qml/pages/SettingsPage.qml" line="175"/>
<source>Show notes marked as favorite above the others</source> <source>Show notes marked as favorite above the others</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="148"/> <location filename="../qml/pages/SettingsPage.qml" line="147"/>
<source>Last edited</source> <source>Last edited</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="149"/> <location filename="../qml/pages/SettingsPage.qml" line="148"/>
<source>Category</source> <source>Category</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="150"/> <location filename="../qml/pages/SettingsPage.qml" line="149"/>
<source>Title alphabetically</source> <source>Title alphabetically</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="153"/> <location filename="../qml/pages/SettingsPage.qml" line="152"/>
<source>Sort notes by</source> <source>Sort notes by</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="154"/> <location filename="../qml/pages/SettingsPage.qml" line="153"/>
<source>This will also change how the notes are grouped</source> <source>This will also change how the notes are grouped</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="181"/> <location filename="../qml/pages/SettingsPage.qml" line="180"/>
<source>Show separator</source> <source>Show separator</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="182"/> <location filename="../qml/pages/SettingsPage.qml" line="181"/>
<source>Show a separator line between the notes</source> <source>Show a separator line between the notes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="192"/> <location filename="../qml/pages/SettingsPage.qml" line="191"/>
<source>lines</source> <source>lines</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="193"/> <location filename="../qml/pages/SettingsPage.qml" line="192"/>
<source>Number of lines in the preview</source> <source>Number of lines in the preview</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="198"/> <location filename="../qml/pages/SettingsPage.qml" line="197"/>
<source>Editing</source> <source>Editing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="201"/> <location filename="../qml/pages/SettingsPage.qml" line="200"/>
<source>Monospaced font</source> <source>Monospaced font</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="202"/> <location filename="../qml/pages/SettingsPage.qml" line="201"/>
<source>Use a monospeced font to edit a note</source> <source>Use a monospeced font to edit a note</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="207"/> <location filename="../qml/pages/SettingsPage.qml" line="206"/>
<source>Capital &apos;X&apos; in checkboxes</source> <source>Capital &apos;X&apos; in checkboxes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="208"/> <location filename="../qml/pages/SettingsPage.qml" line="207"/>
<source>For interoperability with other apps such as Joplin</source> <source>For interoperability with other apps such as Joplin</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>