Account handling

This commit is contained in:
scharel 2021-07-25 18:28:58 +02:00
parent 829660271a
commit 9fc188dbe6
13 changed files with 363 additions and 323 deletions

View file

@ -18,13 +18,20 @@ ApplicationWindow
//console.log("Current account: ", appSettings.currentAccount) //console.log("Current account: ", appSettings.currentAccount)
} }
// Workaround as ConfigurationGroup does not store arrays
ConfigurationValue {
id: accountList
key: appSettings.path + "/accountList"
defaultValue: []
}
// General settings of the app // General settings of the app
ConfigurationGroup { ConfigurationGroup {
id: appSettings id: appSettings
path: "/apps/harbour-nextcloudnotes" path: "/apps/harbour-nextcloudnotes"
property bool initialized: false property bool initialized: false
property var accountList: value("accountList", [], Array) //property var accountList: value("accountList", [], Array)
property string currentAccount: value("currentAccount", "", String) property string currentAccount: value("currentAccount", "", String)
property int autoSyncInterval: value("autoSyncInterval", 0, Number) property int autoSyncInterval: value("autoSyncInterval", 0, Number)
property int previewLineCount: value("previewLineCount", 4, Number) property int previewLineCount: value("previewLineCount", 4, Number)
@ -42,10 +49,10 @@ ApplicationWindow
} }
function createAccount(username, password, url, name) { function createAccount(username, password, url, name) {
var hash = accountHash.hash(username, url) var hash = nextcloudApi.accountHash(username, url)
var tmpaccounts = accountList var tmpAccountList = accountList.value
tmpaccounts.push(hash) tmpAccountList.push(hash)
accountList = tmpaccounts accountList.value = tmpAccountList
tmpAccount.path = appSettings.path + "/accounts/" + hash tmpAccount.path = appSettings.path + "/accounts/" + hash
tmpAccount.url = url tmpAccount.url = url
@ -60,14 +67,14 @@ ApplicationWindow
Nextcloud.deleteAppPassword(appSettings.value("accounts/" + hash + "/password"), Nextcloud.deleteAppPassword(appSettings.value("accounts/" + hash + "/password"),
appSettings.value("accounts/" + hash + "/username"), appSettings.value("accounts/" + hash + "/username"),
appSettings.value("accounts/" + hash + "/url")) appSettings.value("accounts/" + hash + "/url"))
var tmpaccounts = accountList var tmpAccountList = accountList.value
tmpaccounts.pop(hash) tmpAccountList.pop(hash)
accountList = tmpaccounts accountList.value = tmpAccountList
tmpAccount.path = appSettings.path + "/accounts/" + hash tmpAccount.path = appSettings.path + "/accounts/" + hash
tmpAccount.clear() tmpAccount.clear()
if (accountList[-1]) { if (accountList.value[-1]) {
currentAccount = accountList[-1] currentAccount = accountList.value[-1]
} }
else { else {
currentAccount = "" currentAccount = ""
@ -81,8 +88,7 @@ ApplicationWindow
target: appSettings target: appSettings
onCurrentAccountChanged: { onCurrentAccountChanged: {
account.path = appSettings.path + "/accounts/" + appSettings.currentAccount account.path = appSettings.path + "/accounts/" + appSettings.currentAccount
console.log("Current account: " + account.username + "@" + account.url) console.log("Current account: " + account.username + "@" + String(account.url).split('//')[1])
notesApp.model().account = appSettings.currentAccount
} }
} }

View file

@ -8,7 +8,7 @@ Page {
onStatusChanged: { onStatusChanged: {
if (status === PageStatus.Activating) { if (status === PageStatus.Activating) {
if (appSettings.accountList.length <= 0) { if (accountList.value.length <= 0) {
addAccountHint.restart() addAccountHint.restart()
} }
else { else {
@ -228,7 +228,7 @@ Page {
ViewPlaceholder { ViewPlaceholder {
id: noLoginPlaceholder id: noLoginPlaceholder
enabled: appSettings.accountList.length <= 0 enabled: accountList.value.length <= 0
text: qsTr("No account yet") text: qsTr("No account yet")
hintText: qsTr("Got to the settings to add an account") hintText: qsTr("Got to the settings to add an account")
} }

View file

@ -32,7 +32,7 @@ Page {
} }
Label { Label {
id: noAccountsLabel id: noAccountsLabel
visible: appSettings.accountList.length <= 0 visible: accountList.value.length <= 0
text: qsTr("No Nextcloud account yet") text: qsTr("No Nextcloud account yet")
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
color: Theme.secondaryHighlightColor color: Theme.secondaryHighlightColor
@ -43,7 +43,7 @@ Page {
} }
Repeater { Repeater {
id: accountRepeater id: accountRepeater
model: appSettings.accountList model: accountList.value
delegate: ListItem { delegate: ListItem {
id: accountListItem id: accountListItem
@ -63,7 +63,7 @@ Page {
TextSwitch { TextSwitch {
id: accountTextSwitch id: accountTextSwitch
text: settingsAccount.name text: settingsAccount.name
description: settingsAccount.username + "@" + settingsAccount.url description: settingsAccount.username + "@" + String(settingsAccount.url).split('//')[1]
automaticCheck: false automaticCheck: false
checked: modelData === appSettings.currentAccount checked: modelData === appSettings.currentAccount
onClicked: { onClicked: {

View file

@ -3,6 +3,7 @@
NotesApp::NotesApp(QObject *parent, NextcloudApi* api) NotesApp::NotesApp(QObject *parent, NextcloudApi* api)
: AbstractNextcloudApp(parent, "notes", api) { : AbstractNextcloudApp(parent, "notes", api) {
m_notesProxy.setSourceModel(&m_notesModel); m_notesProxy.setSourceModel(&m_notesModel);
connect(api, SIGNAL(readyChanged(bool)), this, SLOT(onApiReady(bool)));
connect(this, SIGNAL(capabilitiesChanged(QJsonObject*)), this, SLOT(updateCapabilities(QJsonObject*))); connect(this, SIGNAL(capabilitiesChanged(QJsonObject*)), this, SLOT(updateCapabilities(QJsonObject*)));
connect(this, SIGNAL(replyReceived(QNetworkReply*)), this, SLOT(updateReply(QNetworkReply*))); connect(this, SIGNAL(replyReceived(QNetworkReply*)), this, SLOT(updateReply(QNetworkReply*)));
} }
@ -38,6 +39,15 @@ QList<QVersionNumber> NotesApp::apiVersions() const {
return versions; return versions;
} }
// FIXME
void NotesApp::updateUrl(QUrl* url) {
if (url->isValid() && m_api->ready()) {
QUrl myUrl = m_api->url();
myUrl.setUserInfo(QString());
m_notesModel.setAccount(m_api->accountHash(m_api->username(), myUrl.toString()));
}
}
bool NotesApp::getAllNotes(const QStringList& exclude) { bool NotesApp::getAllNotes(const QStringList& exclude) {
qDebug() << "Getting all notes"; qDebug() << "Getting all notes";
QUrlQuery query; QUrlQuery query;

View file

@ -24,7 +24,6 @@ class NotesApp : public AbstractNextcloudApp {
public: public:
NotesApp(QObject *parent = nullptr, NextcloudApi* api = nullptr); NotesApp(QObject *parent = nullptr, NextcloudApi* api = nullptr);
virtual ~NotesApp() {} virtual ~NotesApp() {}
// QML singleton // QML singleton
@ -32,8 +31,10 @@ public:
static AbstractNextcloudApp & getInstance(); static AbstractNextcloudApp & getInstance();
static QObject * provider(QQmlEngine *, QJSEngine *); static QObject * provider(QQmlEngine *, QJSEngine *);
// Notes model
Q_INVOKABLE NotesProxyModel* model() { return &m_notesProxy; } Q_INVOKABLE NotesProxyModel* model() { return &m_notesProxy; }
// Properties
Q_INVOKABLE QVersionNumber serverVersion() const; Q_INVOKABLE QVersionNumber serverVersion() const;
Q_INVOKABLE QList<QVersionNumber> apiVersions() const; Q_INVOKABLE QList<QVersionNumber> apiVersions() const;
@ -45,6 +46,7 @@ public slots:
Q_INVOKABLE bool deleteNote(const int id, bool local = false); Q_INVOKABLE bool deleteNote(const int id, bool local = false);
//Q_INVOKABLE bool getSettings(); //Q_INVOKABLE bool getSettings();
//Q_INVOKABLE bool changeSettings(const QJsonObject& settings); //Q_INVOKABLE bool changeSettings(const QJsonObject& settings);
void updateUrl(QUrl* url);
protected slots: protected slots:
void updateCapabilities(QJsonObject*) { } void updateCapabilities(QJsonObject*) { }

View file

@ -107,6 +107,7 @@ void NotesModel::setAccount(const QString& account) {
} }
if (!account.isEmpty()) { if (!account.isEmpty()) {
m_fileDir.setPath(account); m_fileDir.setPath(account);
qDebug() << m_fileDir.absolutePath();
if (m_fileDir.mkpath(".")) { if (m_fileDir.mkpath(".")) {
m_fileDir.setFilter(QDir::Files | QDir::NoDotAndDotDot); m_fileDir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
m_fileDir.setSorting(QDir::Name | QDir::DirsLast); m_fileDir.setSorting(QDir::Name | QDir::DirsLast);
@ -156,6 +157,84 @@ int NotesModel::noteModified(const int id) {
} }
*/ */
void NotesModel::insert(int id, const QJsonObject& json) {
if (id < 0) {
id = json.value(m_roleNames[IdRole]).toInt(-1);
}
if (id >= 0) {
qDebug() << "Inserting note: " << id;
if (indexOfNoteById(id) >= 0) {
qDebug() << "Note already present";
update(id, json);
}
else {
int newPosition = indexOfNoteById(id, true);
qDebug() << "New position: " << newPosition;
beginInsertRows(QModelIndex(), newPosition, newPosition);
setNoteFile(json.toVariantMap(), id);
endInsertRows();
//emit noteInserted(id, note);
qDebug() << "Note inserted";
}
}
}
void NotesModel::update(int id, const QJsonObject &json) {
if (id < 0) {
id = json.value(m_roleNames[IdRole]).toInt(-1);
}
if (id >= 0) {
qDebug() << "Updating note: " << id;
if (indexOfNoteById(id) < 0) {
qDebug() << "Note is new";
insert(id, json);
}
else {
int newPosition = indexOfNoteById(id);
setNoteFile(json.toVariantMap(), id);
emit dataChanged(index(newPosition), index(newPosition));
qDebug() << "Note changed";
}
}
}
void NotesModel::remove(int id) {
qDebug() << "Removing note: " << id;
int newPosition = indexOfNoteById(id);
if (newPosition >= 0) {
beginRemoveRows(QModelIndex(), newPosition, newPosition);
deleteNoteFile(id);
endRemoveRows();
qDebug() << "Note removed";
}
}
int NotesModel::indexOfNoteById(int id, bool nonexistant) const {
int index = -1;
if (m_fileDir.exists() && !account().isEmpty()) {
QStringList fileList = m_fileDir.entryList();
if (nonexistant) {
fileList << QString("^%1.%2$").arg(id).arg(m_fileSuffix);
fileList.sort(Qt::CaseInsensitive);
}
qDebug() << fileList;
index = fileList.indexOf(QRegExp(QString("^%1.%2$").arg(id).arg(m_fileSuffix)));
}
return index;
}
int NotesModel::idOfNoteByINdex(int index) const {
int id = -1;
if (m_fileDir.exists() && !account().isEmpty()) {
QFileInfo fileName = m_fileDir.entryInfoList().value(index);
bool ok;
id = fileName.baseName().toInt(&ok);
if (!ok) id = -1;
}
return id;
}
/*
int NotesModel::newNotePosition(const int id) const { int NotesModel::newNotePosition(const int id) const {
if (m_fileDir.exists() && !account().isEmpty() && id >= 0) { if (m_fileDir.exists() && !account().isEmpty() && id >= 0) {
QStringList fileList = m_fileDir.entryList(); QStringList fileList = m_fileDir.entryList();
@ -167,8 +246,9 @@ int NotesModel::newNotePosition(const int id) const {
} }
return -1; return -1;
} }
*/
const QVariantMap NotesModel::note(const int id) const { const QVariantMap NotesModel::getNoteFile(const int id) const {
QVariantMap json; QVariantMap json;
if (m_fileDir.exists() && !account().isEmpty() && id >= 0) { if (m_fileDir.exists() && !account().isEmpty() && id >= 0) {
QFileInfo fileinfo(m_fileDir, QString("%1.%2").arg(id).arg(m_fileSuffix)); QFileInfo fileinfo(m_fileDir, QString("%1.%2").arg(id).arg(m_fileSuffix));
@ -183,7 +263,7 @@ const QVariantMap NotesModel::note(const int id) const {
return json; return json;
} }
bool NotesModel::setNote(const QVariantMap &note, int id) { bool NotesModel::setNoteFile(const QVariantMap &note, int id) {
bool ok; bool ok;
if (id < 0) { if (id < 0) {
id = note.value(m_roleNames[IdRole]).toInt(&ok); id = note.value(m_roleNames[IdRole]).toInt(&ok);
@ -204,7 +284,7 @@ bool NotesModel::setNote(const QVariantMap &note, int id) {
return ok; return ok;
} }
bool NotesModel::deleteNote(const int id) { bool NotesModel::deleteNoteFile(const int id) {
if (m_fileDir.exists() && !account().isEmpty() && id >= 0) { if (m_fileDir.exists() && !account().isEmpty() && id >= 0) {
QFileInfo fileinfo(m_fileDir, QString("%1.%2").arg(id).arg(m_fileSuffix)); QFileInfo fileinfo(m_fileDir, QString("%1.%2").arg(id).arg(m_fileSuffix));
QFile file(fileinfo.filePath()); QFile file(fileinfo.filePath());
@ -217,74 +297,6 @@ bool NotesModel::deleteNote(const int id) {
return false; return false;
} }
void NotesModel::insert(int id, const QJsonObject& json) {
if (id < 0) {
id = json.value(m_roleNames[IdRole]).toInt(-1);
}
if (id >= 0) {
qDebug() << "Inserting note: " << id;
if (indexOfNoteById(id) >= 0) {
qDebug() << "Note already present";
update(id, json);
}
else {
qDebug() << "New position: " << newNotePosition(id);
beginInsertRows(QModelIndex(), newNotePosition(id), newNotePosition(id));
setNote(json.toVariantMap(), id);
endInsertRows();
//emit noteInserted(id, note);
qDebug() << "Note inserted";
}
}
}
void NotesModel::update(int id, const QJsonObject &json) {
if (id < 0) {
id = json.value(m_roleNames[IdRole]).toInt(-1);
}
if (id >= 0) {
qDebug() << "Updating note: " << id;
if (indexOfNoteById(id) < 0) {
qDebug() << "Note is new";
insert(id, json);
}
else {
setNote(json.toVariantMap(), id);
emit dataChanged(index(indexOfNoteById(id)), index(indexOfNoteById(id)));
qDebug() << "Note changed";
}
}
}
void NotesModel::remove(int id) {
qDebug() << "Removing note: " << id;
if (indexOfNoteById(id) >= 0) {
beginRemoveRows(QModelIndex(), indexOfNoteById(id), indexOfNoteById(id));
deleteNote(id);
endRemoveRows();
qDebug() << "Note removed";
}
}
int NotesModel::indexOfNoteById(int id) const {
int index = -1;
if (m_fileDir.exists() && !account().isEmpty()) {
index = m_fileDir.entryList().indexOf(QRegExp(QString("^%1.%2$").arg(id).arg(m_fileSuffix)));
}
return index;
}
int NotesModel::idOfNoteByINdex(int index) const {
int id = -1;
if (m_fileDir.exists() && !account().isEmpty()) {
QFileInfo fileName = m_fileDir.entryInfoList().value(index);
bool ok;
id = fileName.baseName().toInt(&ok);
if (!ok) id = -1;
}
return id;
}
QHash<int, QByteArray> NotesModel::roleNames() const { QHash<int, QByteArray> NotesModel::roleNames() const {
return m_roleNames; return m_roleNames;
} }
@ -326,7 +338,7 @@ bool NotesModel::setData(const QModelIndex &index, const QVariant &value, int ro
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() && index.row() < rowCount()) { if (index.isValid() && index.row() < rowCount()) {
QVariantMap note = this->note(idOfNoteByINdex(index.row())); QVariantMap note = this->getNoteFile(idOfNoteByINdex(index.row()));
for (int role = IdRole; role <= ErrorMessageRole; ++role) { for (int role = IdRole; role <= ErrorMessageRole; ++role) {
map.insert(role, note.value(m_roleNames[role])); map.insert(role, note.value(m_roleNames[role]));
} }
@ -337,13 +349,13 @@ QMap<int, QVariant> NotesModel::itemData(const QModelIndex &index) const {
bool NotesModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles) { bool NotesModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles) {
QVariantMap note; QVariantMap note;
if (index.isValid() && index.row() < rowCount()) { if (index.isValid() && index.row() < rowCount()) {
note = this->note(idOfNoteByINdex(index.row())); note = this->getNoteFile(idOfNoteByINdex(index.row()));
QMapIterator<int, QVariant> i(roles); QMapIterator<int, QVariant> i(roles);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
note.insert(m_roleNames[i.key()], i.value()); note.insert(m_roleNames[i.key()], i.value());
} }
return setNote(note, idOfNoteByINdex(index.row())); return setNoteFile(note, idOfNoteByINdex(index.row()));
} }
return false; return false;
} }

View file

@ -24,8 +24,10 @@ public:
void setFavoritesOnTop(bool favoritesOnTop); void setFavoritesOnTop(bool favoritesOnTop);
QString sortBy() const { return roleNames().value(m_sortByRole); } QString sortBy() const { return roleNames().value(m_sortByRole); }
void setSortBy(const QString sortBy); void setSortBy(const QString sortBy);
Q_INVOKABLE void clearSortBy() { setSortRole(-1); }
QString searchFilter() const { return m_searchFilterString; } QString searchFilter() const { return m_searchFilterString; }
void setSearchFilter(const QString searchFilter); void setSearchFilter(const QString searchFilter);
Q_INVOKABLE void clearSearchFilter() { setFilterFixedString(""); }
//Q_INVOKABLE void sort(); //Q_INVOKABLE void sort();
@ -80,17 +82,12 @@ public:
virtual QMap<int, QVariant> itemData(const QModelIndex &index) const; virtual QMap<int, QVariant> itemData(const QModelIndex &index) const;
virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles); virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles);
int newNotePosition(const int id) const;
Q_INVOKABLE const QVariantMap note(const int id) const;
Q_INVOKABLE bool setNote(const QVariantMap& note, int id = -1);
Q_INVOKABLE bool deleteNote(const int id);
public slots: public slots:
void insert(int id, const QJsonObject& json); void insert(int id, const QJsonObject& json);
void update(int id, const QJsonObject& json); void update(int id, const QJsonObject& json);
void remove(int id); void remove(int id);
Q_INVOKABLE int indexOfNoteById(int id) const; Q_INVOKABLE int indexOfNoteById(int id, bool nonexistant = false) const;
Q_INVOKABLE int idOfNoteByINdex(int index) const; Q_INVOKABLE int idOfNoteByINdex(int index) const;
signals: signals:
@ -100,6 +97,14 @@ signals:
private: private:
const static QHash<int, QByteArray> m_roleNames; const static QHash<int, QByteArray> m_roleNames;
/*
int newNotePosition(const int id) const;
*/
Q_INVOKABLE const QVariantMap getNoteFile(const int id) const;
Q_INVOKABLE bool setNoteFile(const QVariantMap& note, int id = -1);
Q_INVOKABLE bool deleteNoteFile(const int id);
QDir m_fileDir; QDir m_fileDir;
const static QString m_fileSuffix; const static QString m_fileSuffix;
}; };

View file

@ -2,7 +2,6 @@
#include <sailfishapp.h> #include <sailfishapp.h>
#include <QtQml> #include <QtQml>
#include <QObject> #include <QObject>
#include "accounthash.h"
#include "nextcloudapi.h" #include "nextcloudapi.h"
#include "apps/abstractnextcloudapp.h" #include "apps/abstractnextcloudapp.h"
#include "apps/notes/notesapp.h" #include "apps/notes/notesapp.h"
@ -18,7 +17,6 @@ int main(int argc, char *argv[])
qDebug() << app->applicationDisplayName() << app->applicationVersion(); qDebug() << app->applicationDisplayName() << app->applicationVersion();
AccountHash* accountHash = new AccountHash;
NextcloudApi::instantiate(app); NextcloudApi::instantiate(app);
qmlRegisterSingletonType<NextcloudApi>("harbour.nextcloudapi", 1, 0, "Nextcloud", NextcloudApi::provider); qmlRegisterSingletonType<NextcloudApi>("harbour.nextcloudapi", 1, 0, "Nextcloud", NextcloudApi::provider);
NotesApp::instantiate(&NextcloudApi::getInstance(), &NextcloudApi::getInstance()); NotesApp::instantiate(&NextcloudApi::getInstance(), &NextcloudApi::getInstance());
@ -33,7 +31,6 @@ 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("accountHash", accountHash);
view->setSource(SailfishApp::pathTo("qml/harbour-nextcloudnotes.qml")); view->setSource(SailfishApp::pathTo("qml/harbour-nextcloudnotes.qml"));
view->show(); view->show();

View file

@ -152,6 +152,12 @@ void NextcloudApi::setPassword(QString password) {
} }
} }
const QString NextcloudApi::accountHash(const QString username, const QString url) {
QByteArray data = QString("%1@%2").arg(username).arg(url).toUtf8();
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
return hash.toHex();
}
bool NextcloudApi::appInstalled(const QString& name) const { bool NextcloudApi::appInstalled(const QString& name) const {
QJsonObject app = m_capabilities.value(name).toObject(); QJsonObject app = m_capabilities.value(name).toObject();
return !app.isEmpty(); return !app.isEmpty();

View file

@ -150,6 +150,8 @@ public:
QString password() const { return m_url.password(); } QString password() const { return m_url.password(); }
void setPassword(QString password); void setPassword(QString password);
Q_INVOKABLE static const QString accountHash(const QString username, const QString url);
// Class status information // Class status information
bool ready() const { return urlValid() && networkAccessible() && !busy() && statusInstalled() && !statusMaintenance() && loginStatus() == LoginSuccess; } bool ready() const { return urlValid() && networkAccessible() && !busy() && statusInstalled() && !statusMaintenance() && loginStatus() == LoginSuccess; }
bool urlValid() const { return m_url.isValid(); } bool urlValid() const { return m_url.isValid(); }

View file

@ -413,143 +413,147 @@
<name>SettingsPage</name> <name>SettingsPage</name>
<message> <message>
<source>About</source> <source>About</source>
<translation>Über</translation> <translation type="unfinished">Über</translation>
</message> </message>
<message> <message>
<source>Settings</source> <source>Settings</source>
<translation>Einstellungen</translation> <translation type="unfinished">Einstellungen</translation>
</message> </message>
<message> <message>
<source>Accounts</source> <source>Accounts</source>
<translation>Benutzerkonten</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>No Nextcloud account yet</source> <source>No Nextcloud account yet</source>
<translation>Noch kein Nextcloud Konto eingerichtet</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Account %1</source>
<translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Edit</source> <source>Edit</source>
<translation>Bearbeiten</translation> <translation type="unfinished">Bearbeiten</translation>
</message> </message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Löschen</translation> <translation type="unfinished">Löschen</translation>
</message> </message>
<message> <message>
<source>Deleting account</source> <source>Deleting account</source>
<translation>Lösche Konto</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Add account</source> <source>Add account</source>
<translation>Konto hinzufügen</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Synchronization</source> <source>Synchronization</source>
<translation>Synchronisierung</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Auto-Sync</source> <source>Auto-Sync</source>
<translation>Auto-Sync</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Periodically pull notes from the server</source> <source>Periodically pull notes from the server</source>
<translation>Notizen regelmäßig abrufen</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Disabled</source> <source>Disabled</source>
<translation>Deaktiviert</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>every</source> <source>every</source>
<translation>alle</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Minutes</source> <source>Minutes</source>
<translation>Minuten</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Seconds</source> <source>Seconds</source>
<translation>Sekunden</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Appearance</source>
<translation>Aussehen</translation>
</message>
<message>
<source>Last edited</source>
<translation>Zuletzt bearbeitet</translation>
</message>
<message>
<source>Category</source>
<translation>Kategorie</translation>
</message>
<message>
<source>Title alphabetically</source>
<translation>Alphabetisch nach Titel</translation>
</message>
<message>
<source>Sort notes by</source>
<translation>Notizen sortieren nach</translation>
</message>
<message>
<source>This will also change how the notes are grouped</source>
<translation>Dies beeinflusst auch die Gruppierung</translation>
</message>
<message>
<source>Show separator</source>
<translation>Trennlinie einblenden</translation>
</message>
<message>
<source>Show a separator line between the notes</source>
<translation>Eine Trennlinie zwischen den Notizen anzeigen</translation>
</message>
<message>
<source>lines</source>
<translation>Zeilen</translation>
</message>
<message>
<source>Number of lines in the preview</source>
<translation>Anzahl der Zeiten in der Vorschau</translation>
</message>
<message>
<source>Editing</source>
<translation>Bearbeitung</translation>
</message>
<message>
<source>Monospaced font</source>
<translation>Nichtproportionale Schrift</translation>
</message>
<message>
<source>Use a monospeced font to edit a note</source>
<translation>Nichtproportionale Schrift beim Bearbeiten benutzen</translation>
</message>
<message>
<source>Capital &apos;X&apos; in checkboxes</source>
<translation>Großes &quot;X&quot; in Kontrollkästchen</translation>
</message>
<message>
<source>For interoperability with other apps such as Joplin</source>
<translation>Kann für die Interoperabilität mit anderen Apps (z.B. Joplin) nützlich sein</translation>
</message> </message>
<message> <message>
<source>The Answer is 42</source> <source>The Answer is 42</source>
<translation>Die Antwort lautet 42</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<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>Glückwunsch, du hast die Antwort auf die Frage nach dem Leben, dem Universum und dem ganzen Rest gefunden!</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Favorites on top</source> <source>Appearance</source>
<translation>Favoriten oben anzeigen</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Show notes marked as favorite above the others</source> <source>Last edited</source>
<translation>Markierte Notizen vor allen anderen anzeigen</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Category</source>
<translation type="unfinished">Kategorie</translation>
</message>
<message>
<source>Title alphabetically</source>
<translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>No sorting</source> <source>No sorting</source>
<translation>Keine Sortierung</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Sort notes by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will also change how the notes are grouped</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Favorites on top</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show notes marked as favorite above the others</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show separator</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show a separator line between the notes</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>lines</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Number of lines in the preview</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Editing</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Monospaced font</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use a monospeced font to edit a note</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Capital &apos;X&apos; in checkboxes</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>For interoperability with other apps such as Joplin</source>
<translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Reset</source> <source>Reset</source>
@ -559,16 +563,12 @@
<source>Reset app settings</source> <source>Reset app settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Cleared app data</source> <source>Cleared app data</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Account %1</source> <source>Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>

View file

@ -411,133 +411,105 @@
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
<message>
<source>About</source>
<translation type="unfinished">Om</translation>
</message>
<message> <message>
<source>Settings</source> <source>Settings</source>
<translation>Inställningar</translation> <translation type="unfinished">Inställningar</translation>
</message> </message>
<message> <message>
<source>Accounts</source> <source>Accounts</source>
<translation>Konton</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>About</source>
<translation>Om</translation>
</message> </message>
<message> <message>
<source>No Nextcloud account yet</source> <source>No Nextcloud account yet</source>
<translation>Inget Nextcloud-konto ännu</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Add account</source> <source>Account %1</source>
<translation>Lägg till konto</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Edit</source> <source>Edit</source>
<translation>Redigera</translation> <translation type="unfinished">Redigera</translation>
</message> </message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Ta bort</translation> <translation type="unfinished">Ta bort</translation>
</message> </message>
<message> <message>
<source>Deleting account</source> <source>Deleting account</source>
<translation>Tar bort konto</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Add account</source>
<translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Synchronization</source> <source>Synchronization</source>
<translation>Synkronisering</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Auto-Sync</source> <source>Auto-Sync</source>
<translation>Autosynk</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Periodically pull notes from the server</source> <source>Periodically pull notes from the server</source>
<translation>Hämta anteckningar från servern periodiskt</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Disabled</source> <source>Disabled</source>
<translation>Inaktiverad</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Minutes</source>
<translation>Minuter</translation>
</message>
<message>
<source>Seconds</source>
<translation>Sekunder</translation>
</message>
<message>
<source>Appearance</source>
<translation>Utseende</translation>
</message>
<message>
<source>Show separator</source>
<translation>Visa avdelare</translation>
</message>
<message>
<source>Show a separator line between the notes</source>
<translation>Visa en separatorlinje mellan anteckningarna</translation>
</message>
<message>
<source>lines</source>
<translation>rader</translation>
</message> </message>
<message> <message>
<source>every</source> <source>every</source>
<translation>varje</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Category</source> <source>Minutes</source>
<translation>Kategori</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Title alphabetically</source> <source>Seconds</source>
<translation>Titlar alfabetiskt</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Sort notes by</source>
<translation>Sortera anteckningar efter</translation>
</message>
<message>
<source>Last edited</source>
<translation>Senast redigerad</translation>
</message>
<message>
<source>This will also change how the notes are grouped</source>
<translation>Detta ändrar också hur anteckningarna grupperas</translation>
</message>
<message>
<source>Number of lines in the preview</source>
<translation>Antal rader i förhandsgranskningen</translation>
</message>
<message>
<source>Editing</source>
<translation>Redigering</translation>
</message>
<message>
<source>Monospaced font</source>
<translation>Monospace teckensnitt</translation>
</message>
<message>
<source>Use a monospeced font to edit a note</source>
<translation>Använd ett monospace teckensnitt för redigering</translation>
</message>
<message>
<source>Capital &apos;X&apos; in checkboxes</source>
<translation>Stort &quot;X&quot; i kryssrutor</translation>
</message>
<message>
<source>For interoperability with other apps such as Joplin</source>
<translation>För samverkan med andra program som Joplin</translation>
</message> </message>
<message> <message>
<source>The Answer is 42</source> <source>The Answer is 42</source>
<translation>Svaret är 42</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<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>Grattulerar! Du har funnit svaret den ultimata frågan om livet, universum och allt!</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>Appearance</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Last edited</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Category</source>
<translation type="unfinished">Kategori</translation>
</message>
<message>
<source>Title alphabetically</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No sorting</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Sort notes by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will also change how the notes are grouped</source>
<translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Favorites on top</source> <source>Favorites on top</source>
@ -548,7 +520,39 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>No sorting</source> <source>Show separator</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show a separator line between the notes</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>lines</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Number of lines in the preview</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Editing</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Monospaced font</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use a monospeced font to edit a note</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Capital &apos;X&apos; in checkboxes</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>For interoperability with other apps such as Joplin</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
@ -559,16 +563,12 @@
<source>Reset app settings</source> <source>Reset app settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Cleared app data</source> <source>Cleared app data</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Account %1</source> <source>Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>

View file

@ -275,32 +275,32 @@
<context> <context>
<name>NextcloudApi</name> <name>NextcloudApi</name>
<message> <message>
<location filename="../src/nextcloudapi.cpp" line="178"/> <location filename="../src/nextcloudapi.cpp" line="184"/>
<source>No error</source> <source>No error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/nextcloudapi.cpp" line="181"/> <location filename="../src/nextcloudapi.cpp" line="187"/>
<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/nextcloudapi.cpp" line="184"/> <location filename="../src/nextcloudapi.cpp" line="190"/>
<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/nextcloudapi.cpp" line="187"/> <location filename="../src/nextcloudapi.cpp" line="193"/>
<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/nextcloudapi.cpp" line="190"/> <location filename="../src/nextcloudapi.cpp" line="196"/>
<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/nextcloudapi.cpp" line="193"/> <location filename="../src/nextcloudapi.cpp" line="199"/>
<source>Unknown error</source> <source>Unknown error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -599,41 +599,6 @@
<source>Appearance</source> <source>Appearance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="157"/>
<source>No sorting</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="181"/>
<source>Favorites on top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="182"/>
<source>Show notes marked as favorite above the others</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="220"/>
<source>Reset</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="223"/>
<source>Reset app settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="225"/>
<source>Cleared app data</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="228"/>
<source>Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="154"/> <location filename="../qml/pages/SettingsPage.qml" line="154"/>
<source>Last edited</source> <source>Last edited</source>
@ -649,6 +614,11 @@
<source>Title alphabetically</source> <source>Title alphabetically</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="157"/>
<source>No sorting</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="159"/> <location filename="../qml/pages/SettingsPage.qml" line="159"/>
<source>Sort notes by</source> <source>Sort notes by</source>
@ -659,6 +629,16 @@
<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>
<location filename="../qml/pages/SettingsPage.qml" line="181"/>
<source>Favorites on top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="182"/>
<source>Show notes marked as favorite above the others</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="../qml/pages/SettingsPage.qml" line="187"/> <location filename="../qml/pages/SettingsPage.qml" line="187"/>
<source>Show separator</source> <source>Show separator</source>
@ -704,6 +684,26 @@
<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>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="220"/>
<source>Reset</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="223"/>
<source>Reset app settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="225"/>
<source>Cleared app data</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/SettingsPage.qml" line="228"/>
<source>Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SyntaxPage</name> <name>SyntaxPage</name>
@ -912,27 +912,27 @@ You can also use other markdown syntax inside them.</source>
<context> <context>
<name>harbour-nextcloudnotes</name> <name>harbour-nextcloudnotes</name>
<message> <message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="116"/> <location filename="../qml/harbour-nextcloudnotes.qml" line="123"/>
<source>Notes</source> <source>Notes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="117"/> <location filename="../qml/harbour-nextcloudnotes.qml" line="124"/>
<source>Offline</source> <source>Offline</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="118"/> <location filename="../qml/harbour-nextcloudnotes.qml" line="125"/>
<source>Synced</source> <source>Synced</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="132"/> <location filename="../qml/harbour-nextcloudnotes.qml" line="139"/>
<source>API error</source> <source>API error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../qml/harbour-nextcloudnotes.qml" line="125"/> <location filename="../qml/harbour-nextcloudnotes.qml" line="132"/>
<source>File error</source> <source>File error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>