Worked on Login workflow and account handling
This commit is contained in:
parent
4e2a06bcde
commit
3e4d2de07b
9 changed files with 264 additions and 181 deletions
|
@ -15,7 +15,7 @@ ApplicationWindow
|
|||
|
||||
property bool initialized: false
|
||||
property var accounts: value("accounts", [], Array)
|
||||
property int currentAccountIndex: value("currentAccountIndex", -1, Number)
|
||||
property string currentAccount: value("currentAccount", "", String)
|
||||
property int autoSyncInterval: value("autoSyncInterval", 0, Number)
|
||||
property int previewLineCount: value("previewLineCount", 4, Number)
|
||||
property bool favoritesOnTop: value("favoritesOnTop", true, Boolean)
|
||||
|
@ -24,15 +24,8 @@ ApplicationWindow
|
|||
property bool useMonoFont: value("useMonoFont", false, Boolean)
|
||||
property bool useCapitalX: value("useCapitalX", false, Boolean)
|
||||
|
||||
onCurrentAccountIndexChanged: {
|
||||
console.log("Current account index: " + currentAccountIndex)
|
||||
if (currentAccountIndex >= 0 && currentAccountIndex < accounts.length) {
|
||||
account = accounts[currentAccountIndex]
|
||||
console.log("Current account: " + account.username + "@" + account.url)
|
||||
}
|
||||
else {
|
||||
account = null
|
||||
}
|
||||
onCurrentAccountChanged: {
|
||||
console.log("Current account: " + currentAccount)
|
||||
}
|
||||
|
||||
onSortByChanged: {
|
||||
|
@ -45,29 +38,60 @@ ApplicationWindow
|
|||
notesProxyModel.favoritesOnTop = favoritesOnTop
|
||||
}
|
||||
|
||||
function createAccount(user, password, url) {
|
||||
var hash = accountHash.hash(user, url)
|
||||
console.log("Hash(" + user + "@" + url + ") = " + hash)
|
||||
function createAccount(username, password, url, name) {
|
||||
var hash = accountHash.hash(username, url)
|
||||
var tmpaccounts = accounts
|
||||
tmpaccounts.push(hash)
|
||||
accounts = tmpaccounts
|
||||
|
||||
tmpAccount.path = appSettings.path + "/accounts/" + hash
|
||||
tmpAccount.url = url
|
||||
tmpAccount.username = username
|
||||
tmpAccount.passowrd = password
|
||||
tmpAccount.name = name
|
||||
|
||||
console.log("Hash(" + username + "@" + url + ") = " + hash)
|
||||
return hash
|
||||
}
|
||||
function removeAccount(hash) {
|
||||
accounts[hash] = null
|
||||
currentAccount = -1
|
||||
notesApi.deleteAppPassword(appSettings.value("accounts/" + hash + "/password"),
|
||||
appSettings.value("accounts/" + hash + "/username"),
|
||||
appSettings.value("accounts/" + hash + "/url"))
|
||||
var tmpaccounts = accounts
|
||||
tmpaccounts.pop(hash)
|
||||
accounts = tmpaccounts
|
||||
|
||||
tmpAccount.path = appSettings.path + "/accounts/" + hash
|
||||
tmpAccount.clear()
|
||||
currentAccount = accounts[-1]
|
||||
}
|
||||
}
|
||||
|
||||
property var account
|
||||
onAccountChanged: {
|
||||
if (account) {
|
||||
notesApi.server = server
|
||||
notesApi.username = username
|
||||
notesApi.password = password
|
||||
}
|
||||
else {
|
||||
notesApi.server = ""
|
||||
notesApi.username = ""
|
||||
notesApi.password = ""
|
||||
ConfigurationGroup {
|
||||
id: account
|
||||
Connections {
|
||||
target: appSettings
|
||||
onCurrentAccountChanged: path = appSettings.path + "/accounts/" + currentAccount
|
||||
}
|
||||
|
||||
property url url: value("url", "", String)
|
||||
property string username: value("username", "", String)
|
||||
property string passowrd: value("password", "", String)
|
||||
property string name: value("name", "", String)
|
||||
property var update: value("update", new Date(0), Date)
|
||||
}
|
||||
|
||||
ConfigurationGroup {
|
||||
id: tmpAccount
|
||||
property url url
|
||||
property string username
|
||||
property string passowrd
|
||||
property string name
|
||||
property var update
|
||||
}
|
||||
|
||||
function clearApp() {
|
||||
appSettings.clear()
|
||||
}
|
||||
|
||||
Notification {
|
||||
|
|
|
@ -8,7 +8,8 @@ Dialog {
|
|||
|
||||
canAccept: false
|
||||
|
||||
property int peviousAccountIndex: appSettings.currentAccountIndex
|
||||
property string account
|
||||
property string peviousAccount: appSettings.currentAccount
|
||||
|
||||
property bool legacyLoginPossible: false
|
||||
property bool flowLoginV2Possible: false
|
||||
|
@ -17,14 +18,15 @@ Dialog {
|
|||
property bool allowUnecrypted: false
|
||||
|
||||
Component.onCompleted: {
|
||||
appSettings.currentAccountIndex = -1
|
||||
appSettings.currentAccount = null
|
||||
}
|
||||
|
||||
onRejected: {
|
||||
appSettings.currentAccountIndex = peviousAccountIndex
|
||||
notesApi.abortFlowV2Login()
|
||||
appSettings.currentAccount = peviousAccount
|
||||
}
|
||||
onAccepted: {
|
||||
appSettings.createAccount(notesApi.username, notesApi.password, notesApi.server)
|
||||
appSettings.createAccount(notesApi.username, notesApi.password, notesApi.server, notesApi.statusProductName)
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
@ -93,6 +95,8 @@ Dialog {
|
|||
case NotesApi.LoginSuccess:
|
||||
console.log("LoginSuccess")
|
||||
apiProgressBar.label = qsTr("Login successfull!")
|
||||
if (legacyLoginPossible || forceLegacyButton.checked)
|
||||
notesApi.convertToAppPassword();
|
||||
loginDialog.canAccept = true
|
||||
break;
|
||||
case NotesApi.LoginFailed:
|
||||
|
@ -140,7 +144,8 @@ Dialog {
|
|||
label: verifyServerTimer.running ? qsTr("Verifying address") : " "
|
||||
indeterminate: notesApi.loginStatus === NotesApi.LoginFlowV2Initiating ||
|
||||
notesApi.loginStatus === NotesApi.LoginFlowV2Polling ||
|
||||
notesApi.ncStatusStatus === notesApi.NextcloudBusy || (verifyServerTimer.running)
|
||||
notesApi.ncStatusStatus === NotesApi.NextcloudBusy ||
|
||||
verifyServerTimer.running
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -199,8 +204,8 @@ Dialog {
|
|||
Behavior on opacity { FadeAnimator {} }
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: notesApi.loginStatus === notesApi.LoginFlowV2Polling ? qsTr("Abort") : notesApi.loginStatus === notesApi.LoginSuccess ? qsTr("Re-Login") : qsTr("Login")
|
||||
onClicked: notesApi.loginStatus === notesApi.LoginFlowV2Polling ? notesApi.abortFlowV2Login() : notesApi.initiateFlowV2Login()
|
||||
text: notesApi.loginStatus === NotesApi.LoginFlowV2Polling ? qsTr("Abort") : notesApi.loginStatus === NotesApi.LoginSuccess ? qsTr("Re-Login") : qsTr("Login")
|
||||
onClicked: notesApi.loginStatus === NotesApi.LoginFlowV2Polling ? notesApi.abortFlowV2Login() : notesApi.initiateFlowV2Login()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,12 +244,12 @@ Dialog {
|
|||
}
|
||||
EnterKey.enabled: text.length > 0
|
||||
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
|
||||
EnterKey.onClicked: notesApi.verifyLogin(usernameField.text, passwordField.text)
|
||||
EnterKey.onClicked: notesApi.verifyLogin()
|
||||
}
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: qsTr("Test Login")
|
||||
onClicked: notesApi.verifyLogin(usernameField.text, passwordField.text)
|
||||
onClicked: notesApi.verifyLogin(passwordField.text, usernameField.text, serverField.text)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,16 +52,14 @@ Page {
|
|||
|
||||
ConfigurationGroup {
|
||||
id: account
|
||||
path: "/apps/harbour-nextcloudnotes/accounts/" + modelData
|
||||
Component.onCompleted: {
|
||||
accountTextSwitch.text = account.value("username", qsTr("unknown"), String) + " @ " + value("name", qsTr("Unnamed account"), String)
|
||||
accountTextSwitch.description =account.value("server", qsTr("unknown"), String)
|
||||
}
|
||||
path: appSettings.path + "/accounts/" + modelData
|
||||
}
|
||||
|
||||
TextSwitch {
|
||||
id: accountTextSwitch
|
||||
automaticCheck: false
|
||||
text: account.username
|
||||
description: account.url
|
||||
checked: modelData === appSettings.currentAccount
|
||||
onClicked: {
|
||||
appSettings.currentAccount = modelData
|
||||
|
@ -72,14 +70,14 @@ Page {
|
|||
MenuItem {
|
||||
text: qsTr("Edit")
|
||||
onClicked: {
|
||||
var login = pageStack.push(Qt.resolvedUrl("LoginPage.qml"), { accountId: modelData })
|
||||
var login = pageStack.push(Qt.resolvedUrl("LoginPage.qml"), { account: modelData })
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("Delete")
|
||||
onClicked: {
|
||||
accountListItem.remorseAction(qsTr("Deleting account"), function() {
|
||||
console.log("Deleting " + modelData)
|
||||
console.log("Deleting account")
|
||||
appSettings.removeAccount(modelData)
|
||||
})
|
||||
}
|
||||
|
@ -217,12 +215,7 @@ Page {
|
|||
Button {
|
||||
text: qsTr("Reset app settings")
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
RemorseItem { id: resetRemorse }
|
||||
ConfigurationGroup {
|
||||
id: appConfig
|
||||
path: "/apps/harbour-nextcloudnotes"
|
||||
}
|
||||
onClicked: resetRemorse.execute(this, "Reset app", appConfig.clear())
|
||||
onClicked: Remorse.popupAction(page, qsTr("Cleared app data"), function() { clearApp() } )
|
||||
}
|
||||
LinkedLabel {
|
||||
text: qsTr("Resetting the app wipes all application data from the device! This includes offline synced notes, app settings and accounts.")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef ACCOUNTHASH_H
|
||||
#define ACCOUNTHASH_H
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
|
@ -7,7 +8,9 @@ class AccountHash : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE QByteArray hash(const QString username, const QString url) {
|
||||
return QCryptographicHash::hash(QString("%1@%2").arg(username).arg(url).toUtf8(), QCryptographicHash::Sha256);
|
||||
QByteArray data = QString("%1@%2").arg(username).arg(url).toUtf8();
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
|
||||
return hash.toHex();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
QVersionNumber NotesApi::m_capabilities_implementedApiVersion = QVersionNumber(1, 1);
|
||||
|
||||
NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, const QString ocsEndpoint, const QString notesEndpoint, QObject *parent)
|
||||
: m_statusEndpoint(statusEndpoint), m_loginEndpoint(loginEndpoint), m_ocsEndpoint(ocsEndpoint), m_notesEndpoint(notesEndpoint)
|
||||
NotesApi::NotesApi(QObject *parent)
|
||||
{
|
||||
// TODO verify connections (also in destructor)
|
||||
m_loginPollTimer.setInterval(POLL_INTERVALL);
|
||||
|
@ -169,7 +168,7 @@ bool NotesApi::busy() const {
|
|||
|
||||
// Callable functions
|
||||
bool NotesApi::getNcStatus() {
|
||||
QUrl url = apiEndpointUrl(m_statusEndpoint);
|
||||
QUrl url = apiEndpointUrl(STATUS_ENDPOINT);
|
||||
qDebug() << "GET" << url.toDisplayString();
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
setNcStatusStatus(NextcloudStatus::NextcloudBusy);
|
||||
|
@ -188,7 +187,7 @@ bool NotesApi::initiateFlowV2Login() {
|
|||
if (m_loginStatus == LoginStatus::LoginFlowV2Initiating || m_loginStatus == LoginStatus::LoginFlowV2Polling) {
|
||||
abortFlowV2Login();
|
||||
}
|
||||
QUrl url = apiEndpointUrl(m_loginEndpoint);
|
||||
QUrl url = apiEndpointUrl(LOGIN_ENDPOINT);
|
||||
qDebug() << "POST" << url.toDisplayString();
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Initiating);
|
||||
|
@ -226,18 +225,57 @@ void NotesApi::pollLoginUrl() {
|
|||
}
|
||||
}
|
||||
|
||||
void NotesApi::verifyLogin(QString username, QString password) {
|
||||
m_ocsRequest = m_authenticatedRequest;
|
||||
if (username.isEmpty())
|
||||
username = this->username();
|
||||
void NotesApi::verifyLogin(QString password, QString username, QUrl server) {
|
||||
QNetworkRequest ocsRequest = m_request;
|
||||
if (password.isEmpty())
|
||||
password = this->password();
|
||||
QUrl url = apiEndpointUrl(m_ocsEndpoint + QString("/users/%1").arg(username));
|
||||
m_ocsRequest.setRawHeader("Authorization", "Basic " + QString(username + ":" + password).toLocal8Bit().toBase64());
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
qDebug() << "GET" << url.toDisplayString();
|
||||
m_ocsRequest.setUrl(url);
|
||||
m_ocsReplies << m_manager.get(m_ocsRequest);
|
||||
if (username.isEmpty())
|
||||
username = this->username();
|
||||
if (server.isEmpty())
|
||||
server = apiEndpointUrl(USERS_ENDPOINT + QString("/%1").arg(username));
|
||||
else
|
||||
server.setPath(USERS_ENDPOINT + QString("/%1").arg(username));
|
||||
ocsRequest.setRawHeader("Authorization", "Basic " + QString(username + ":" + password).toLocal8Bit().toBase64());
|
||||
if (server.isValid() && !server.scheme().isEmpty() && !server.host().isEmpty()) {
|
||||
qDebug() << "GET" << server.toDisplayString();
|
||||
ocsRequest.setUrl(server);
|
||||
m_ocsReplies << m_manager.get(ocsRequest);
|
||||
emit busyChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
void NotesApi::convertToAppPassword(QString password, QString username, QUrl server) {
|
||||
QNetworkRequest ocsRequest = m_request;
|
||||
if (password.isEmpty())
|
||||
password = this->password();
|
||||
if (username.isEmpty())
|
||||
username = this->username();
|
||||
if (server.isEmpty())
|
||||
server = apiEndpointUrl(APPPASSWORD_ENDPOINT + QString("/%1").arg("getapppassword"));
|
||||
else
|
||||
server.setPath(APPPASSWORD_ENDPOINT + QString("/%1").arg("getapppassword"));
|
||||
ocsRequest.setRawHeader("Authorization", "Basic " + QString(this->username() + ":" + password).toLocal8Bit().toBase64());
|
||||
if (server.isValid() && !server.scheme().isEmpty() && !server.host().isEmpty()) {
|
||||
ocsRequest.setUrl(server);
|
||||
m_ocsReplies << m_manager.get(ocsRequest);
|
||||
emit busyChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
void NotesApi::deleteAppPassword(QString password, QString username, QUrl server) {
|
||||
QNetworkRequest ocsRequest = m_request;
|
||||
if (password.isEmpty())
|
||||
password = this->password();
|
||||
if (username.isEmpty())
|
||||
username = this->username();
|
||||
if (server.isEmpty())
|
||||
server = apiEndpointUrl(APPPASSWORD_ENDPOINT + QString ("/%1").arg("apppassword"));
|
||||
else
|
||||
server.setPath(APPPASSWORD_ENDPOINT + QString ("/%1").arg("apppassword"));
|
||||
ocsRequest.setRawHeader("Authorization", "Basic " + QString(this->username() + ":" + password).toLocal8Bit().toBase64());
|
||||
if (server.isValid() && !server.scheme().isEmpty() && !server.host().isEmpty()) {
|
||||
ocsRequest.setUrl(server);
|
||||
m_ocsReplies << m_manager.deleteResource(ocsRequest);
|
||||
emit busyChanged(true);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +294,7 @@ int NotesApi::noteModified(const int id) {
|
|||
|
||||
bool NotesApi::getAllNotes(const QStringList& exclude) {
|
||||
qDebug() << "Getting all notes";
|
||||
QUrl url = apiEndpointUrl(m_notesEndpoint);
|
||||
QUrl url = apiEndpointUrl(NOTES_ENDPOINT);
|
||||
|
||||
if (!exclude.isEmpty())
|
||||
url.setQuery(QString(EXCLUDE_QUERY).append(exclude.join(",")));
|
||||
|
@ -273,7 +311,7 @@ bool NotesApi::getAllNotes(const QStringList& exclude) {
|
|||
|
||||
bool NotesApi::getNote(const int id, const QStringList& exclude) {
|
||||
qDebug() << "Getting note: " << id;
|
||||
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/%1").arg(id));
|
||||
QUrl url = apiEndpointUrl(NOTES_ENDPOINT + QString("/%1").arg(id));
|
||||
if (!exclude.isEmpty())
|
||||
url.setQuery(QString(EXCLUDE_QUERY).append(exclude.join(",")));
|
||||
|
||||
|
@ -289,7 +327,7 @@ bool NotesApi::getNote(const int id, const QStringList& exclude) {
|
|||
|
||||
bool NotesApi::createNote(const QJsonObject& note) {
|
||||
qDebug() << "Creating note";
|
||||
QUrl url = apiEndpointUrl(m_notesEndpoint);
|
||||
QUrl url = apiEndpointUrl(NOTES_ENDPOINT);
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
qDebug() << "POST" << url.toDisplayString();
|
||||
m_authenticatedRequest.setUrl(url);
|
||||
|
@ -302,7 +340,7 @@ bool NotesApi::createNote(const QJsonObject& note) {
|
|||
|
||||
bool NotesApi::updateNote(const int id, const QJsonObject& note) {
|
||||
qDebug() << "Updating note: " << id;
|
||||
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/%1").arg(id));
|
||||
QUrl url = apiEndpointUrl(NOTES_ENDPOINT + QString("/%1").arg(id));
|
||||
if (id >= 0 && url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
qDebug() << "PUT" << url.toDisplayString();
|
||||
m_authenticatedRequest.setUrl(url);
|
||||
|
@ -315,7 +353,7 @@ bool NotesApi::updateNote(const int id, const QJsonObject& note) {
|
|||
|
||||
bool NotesApi::deleteNote(const int id) {
|
||||
qDebug() << "Deleting note: " << id;
|
||||
QUrl url = apiEndpointUrl(m_notesEndpoint + QString("/%1").arg(id));
|
||||
QUrl url = apiEndpointUrl(NOTES_ENDPOINT + QString("/%1").arg(id));
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
qDebug() << "DELETE" << url.toDisplayString();
|
||||
m_authenticatedRequest.setUrl(url);
|
||||
|
@ -470,7 +508,7 @@ void NotesApi::replyFinished(QNetworkReply *reply) {
|
|||
}
|
||||
else if (m_ocsReplies.contains(reply)) {
|
||||
qDebug() << "OCS reply";
|
||||
if (reply->error() == QNetworkReply::NoError && updateCapabilities(json.object())) {
|
||||
if (reply->error() == QNetworkReply::NoError && updateCore(json.object())) {
|
||||
setLoginStatus(LoginSuccess);
|
||||
qDebug() << "Login Succcessfull!";
|
||||
}
|
||||
|
@ -503,8 +541,8 @@ QUrl NotesApi::apiEndpointUrl(const QString endpoint) const {
|
|||
return url;
|
||||
}
|
||||
|
||||
bool NotesApi::updateCapabilities(const QJsonObject &capabilities) {
|
||||
QJsonValue ocsValue = capabilities.value("ocs");
|
||||
bool NotesApi::updateCore(const QJsonObject &ocs) {
|
||||
QJsonValue ocsValue = ocs.value("ocs");
|
||||
if (!ocsValue.isUndefined() && ocsValue.isObject()) {
|
||||
QJsonObject ocsObject = ocsValue.toObject();
|
||||
QJsonValue metaValue = ocsObject.value("meta");
|
||||
|
@ -535,6 +573,10 @@ bool NotesApi::updateCapabilities(const QJsonObject &capabilities) {
|
|||
}
|
||||
}
|
||||
}
|
||||
QJsonValue appPasswordValue = dataObject.value("apppassword");
|
||||
if (!appPasswordValue.isUndefined() && appPasswordValue.isString()) {
|
||||
setPassword(appPasswordValue.toString());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
|
||||
const QString STATUS_ENDPOINT("/status.php");
|
||||
const QString LOGIN_ENDPOINT("/index.php/login/v2");
|
||||
const QString USERS_ENDPOINT("/ocs/v1.php/cloud/users");
|
||||
const QString CAPABILITIES_ENDPOINT("/ocs/v1.php/cloud/capabilities");
|
||||
const QString APPPASSWORD_ENDPOINT("/ocs/v2.php/core/");
|
||||
const QString NOTES_ENDPOINT("/index.php/apps/notes/api/v0.2/notes");
|
||||
const QString OCS_ENDPOINT("/ocs/v1.php/cloud");
|
||||
const QString EXCLUDE_QUERY("exclude=");
|
||||
const QString PURGE_QUERY("purgeBefore=");
|
||||
const QString ETAG_HEADER("If-None-Match");
|
||||
|
@ -63,11 +65,7 @@ class NotesApi : public QObject
|
|||
Q_PROPERTY(QUrl loginUrl READ loginUrl NOTIFY loginUrlChanged)
|
||||
|
||||
public:
|
||||
explicit NotesApi(const QString statusEndpoint = STATUS_ENDPOINT,
|
||||
const QString loginEndpoint = LOGIN_ENDPOINT,
|
||||
const QString ocsEndpoint = OCS_ENDPOINT,
|
||||
const QString notesEndpoint = NOTES_ENDPOINT,
|
||||
QObject *parent = nullptr);
|
||||
explicit NotesApi(QObject *parent = nullptr);
|
||||
virtual ~NotesApi();
|
||||
|
||||
// Status codes
|
||||
|
@ -158,7 +156,9 @@ public:
|
|||
Q_INVOKABLE bool getNcStatus();
|
||||
Q_INVOKABLE bool initiateFlowV2Login();
|
||||
Q_INVOKABLE void abortFlowV2Login();
|
||||
Q_INVOKABLE void verifyLogin(QString username = QString(), QString password = QString());
|
||||
Q_INVOKABLE void verifyLogin(QString password = QString(), QString username = QString(), QUrl server = QUrl());
|
||||
Q_INVOKABLE void convertToAppPassword(QString password = QString(), QString username = QString(), QUrl server = QUrl());
|
||||
Q_INVOKABLE void deleteAppPassword(QString password = QString(), QString username = QString(), QUrl server = QUrl());
|
||||
|
||||
enum ErrorCodes {
|
||||
NoError,
|
||||
|
@ -244,10 +244,9 @@ private:
|
|||
QNetworkAccessManager m_manager;
|
||||
QNetworkRequest m_request;
|
||||
QNetworkRequest m_authenticatedRequest;
|
||||
QNetworkRequest m_ocsRequest;
|
||||
QUrl apiEndpointUrl(const QString endpoint) const;
|
||||
|
||||
bool updateCapabilities(const QJsonObject & capabilities);
|
||||
bool updateCore(const QJsonObject & ocs);
|
||||
CapabilitiesStatus m_capabilitiesStatus;
|
||||
void setCababilitiesStatus(CapabilitiesStatus status, bool *changed = NULL);
|
||||
bool m_capabilities_notesInstalled;
|
||||
|
@ -255,7 +254,6 @@ private:
|
|||
QStringList m_capabilities_notesApiVersions;
|
||||
|
||||
// Nextcloud status.php
|
||||
const QString m_statusEndpoint;
|
||||
QVector<QNetworkReply*> m_statusReplies;
|
||||
void updateNcStatus(const QJsonObject &status);
|
||||
NextcloudStatus m_ncStatusStatus;
|
||||
|
@ -270,7 +268,6 @@ private:
|
|||
bool m_status_extendedSupport;
|
||||
|
||||
// Nextcloud Login Flow v2 - https://docs.nextcloud.com/server/18/developer_manual/client_apis/LoginFlow/index.html#login-flow-v2
|
||||
const QString m_loginEndpoint;
|
||||
QVector<QNetworkReply*> m_loginReplies;
|
||||
QVector<QNetworkReply*> m_pollReplies;
|
||||
bool updateLoginFlow(const QJsonObject &login);
|
||||
|
@ -283,11 +280,9 @@ private:
|
|||
QString m_pollToken;
|
||||
|
||||
// Nextcloud OCS API - https://docs.nextcloud.com/server/18/developer_manual/client_apis/OCS/ocs-api-overview.html
|
||||
const QString m_ocsEndpoint;
|
||||
QVector<QNetworkReply*> m_ocsReplies;
|
||||
|
||||
// Nextcloud Notes API - https://github.com/nextcloud/notes/wiki/Notes-0.2
|
||||
const QString m_notesEndpoint;
|
||||
QVersionNumber m_notesApiVersion;
|
||||
QVector<QNetworkReply*> m_getAllNotesReplies;
|
||||
QVector<QNetworkReply*> m_getNoteReplies;
|
||||
|
|
|
@ -215,6 +215,17 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LoginWebView</name>
|
||||
<message>
|
||||
<source>%1 Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nextcloud Login</source>
|
||||
<translation type="unfinished">Nextcloud Login</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MITLicense</name>
|
||||
<message>
|
||||
|
@ -400,14 +411,6 @@
|
|||
<source>No Nextcloud account yet</source>
|
||||
<translation>Noch kein Nextcloud Konto eingerichtet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unnamed account</source>
|
||||
<translation>Unbenanntes Konto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>unknown</source>
|
||||
<translation>unbekannt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Edit</source>
|
||||
<translation>Bearbeiten</translation>
|
||||
|
@ -544,6 +547,10 @@
|
|||
<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>
|
||||
<source>Reset app</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SyntaxPage</name>
|
||||
|
|
|
@ -215,6 +215,17 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LoginWebView</name>
|
||||
<message>
|
||||
<source>%1 Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nextcloud Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MITLicense</name>
|
||||
<message>
|
||||
|
@ -408,10 +419,6 @@
|
|||
<source>Edit</source>
|
||||
<translation>Redigera</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unnamed account</source>
|
||||
<translation>Namnlöst konto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete</source>
|
||||
<translation>Ta bort</translation>
|
||||
|
@ -508,10 +515,6 @@
|
|||
<source>For interoperability with other apps such as Joplin</source>
|
||||
<translation>För samverkan med andra program som Joplin</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>unknown</source>
|
||||
<translation>okänd</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The Answer is 42</source>
|
||||
<translation>Svaret är 42</translation>
|
||||
|
@ -544,6 +547,10 @@
|
|||
<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>
|
||||
<source>Reset app</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SyntaxPage</name>
|
||||
|
|
|
@ -138,123 +138,123 @@
|
|||
<context>
|
||||
<name>LoginPage</name>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="125"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="129"/>
|
||||
<source>Nextcloud Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="217"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="223"/>
|
||||
<source>Username</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="229"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="239"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="201"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="207"/>
|
||||
<source>Abort</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="82"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="84"/>
|
||||
<source>Follow the instructions in the browser</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="95"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="97"/>
|
||||
<source>Login successfull!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="91"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="100"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="93"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="104"/>
|
||||
<source>Login failed!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="74"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="76"/>
|
||||
<source>Enter your credentials</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="153"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="158"/>
|
||||
<source>Nextcloud address</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="140"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="144"/>
|
||||
<source>Verifying address</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="152"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="157"/>
|
||||
<source>Enter Nextcloud address</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="183"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="189"/>
|
||||
<source>Enforce legacy login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="201"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="207"/>
|
||||
<source>Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="201"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="207"/>
|
||||
<source>Re-Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="216"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="222"/>
|
||||
<source>Enter Username</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="228"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="238"/>
|
||||
<source>Enter Password</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="237"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="251"/>
|
||||
<source>Test Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="243"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="257"/>
|
||||
<source>Note</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="251"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="265"/>
|
||||
<source>The <a href="https://apps.nextcloud.com/apps/notes">Notes</a> app needs to be installed on the Nextcloud server for this app to work.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="255"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="269"/>
|
||||
<source>Security</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="262"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="276"/>
|
||||
<source><strong>CAUTION: Your password will be saved without any encryption on the device!</strong><br>Please consider creating a dedicated app password! Open your Nextcloud in a browser and go to <i>Settings</i> → <i>Security</i>.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="267"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="281"/>
|
||||
<source>Do not check certificates</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="268"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="282"/>
|
||||
<source>Enable this option to allow selfsigned certificates</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="277"/>
|
||||
<location filename="../qml/pages/LoginPage.qml" line="291"/>
|
||||
<source>Allow unencrypted connections</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -264,6 +264,19 @@
|
|||
<translation></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LoginWebView</name>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginWebView.qml" line="8"/>
|
||||
<source>%1 Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/LoginWebView.qml" line="8"/>
|
||||
<source>Nextcloud Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MITLicense</name>
|
||||
<message>
|
||||
|
@ -341,32 +354,32 @@
|
|||
<context>
|
||||
<name>NotesApi</name>
|
||||
<message>
|
||||
<location filename="../src/notesapi.cpp" line="333"/>
|
||||
<location filename="../src/notesapi.cpp" line="371"/>
|
||||
<source>No error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/notesapi.cpp" line="336"/>
|
||||
<location filename="../src/notesapi.cpp" line="374"/>
|
||||
<source>No network connection available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/notesapi.cpp" line="339"/>
|
||||
<location filename="../src/notesapi.cpp" line="377"/>
|
||||
<source>Failed to communicate with the Nextcloud server</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/notesapi.cpp" line="342"/>
|
||||
<location filename="../src/notesapi.cpp" line="380"/>
|
||||
<source>An error occured while establishing an encrypted connection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/notesapi.cpp" line="345"/>
|
||||
<location filename="../src/notesapi.cpp" line="383"/>
|
||||
<source>Could not authenticate to the Nextcloud instance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/notesapi.cpp" line="348"/>
|
||||
<location filename="../src/notesapi.cpp" line="386"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -492,183 +505,177 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="57"/>
|
||||
<source>Unnamed account</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="57"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="58"/>
|
||||
<source>unknown</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="73"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="71"/>
|
||||
<source>Edit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="79"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="77"/>
|
||||
<source>Delete</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="81"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="79"/>
|
||||
<source>Deleting account</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="91"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="89"/>
|
||||
<source>Add account</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="99"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="97"/>
|
||||
<source>Synchronization</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="103"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="101"/>
|
||||
<source>Auto-Sync</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="104"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="102"/>
|
||||
<source>Periodically pull notes from the server</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="111"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="109"/>
|
||||
<source>Disabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="111"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="109"/>
|
||||
<source>every</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="113"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="111"/>
|
||||
<source>Minutes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="114"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="112"/>
|
||||
<source>Seconds</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="135"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="133"/>
|
||||
<source>The Answer is 42</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="136"/>
|
||||
<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>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="144"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="142"/>
|
||||
<source>Appearance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="152"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="150"/>
|
||||
<source>No sorting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="176"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="174"/>
|
||||
<source>Favorites on top</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="177"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="175"/>
|
||||
<source>Show notes marked as favorite above the others</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="215"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="213"/>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="218"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="217"/>
|
||||
<source>Reset app settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="228"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="219"/>
|
||||
<source>Reset app</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="222"/>
|
||||
<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>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="149"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="147"/>
|
||||
<source>Last edited</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="150"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="148"/>
|
||||
<source>Category</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="151"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="149"/>
|
||||
<source>Title alphabetically</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="154"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="152"/>
|
||||
<source>Sort notes by</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="155"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="153"/>
|
||||
<source>This will also change how the notes are grouped</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="182"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="180"/>
|
||||
<source>Show separator</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="183"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="181"/>
|
||||
<source>Show a separator line between the notes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="193"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="191"/>
|
||||
<source>lines</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="194"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="192"/>
|
||||
<source>Number of lines in the preview</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="199"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="197"/>
|
||||
<source>Editing</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="202"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="200"/>
|
||||
<source>Monospaced font</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="203"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="201"/>
|
||||
<source>Use a monospeced font to edit a note</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="208"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="206"/>
|
||||
<source>Capital 'X' in checkboxes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="209"/>
|
||||
<location filename="../qml/pages/SettingsPage.qml" line="207"/>
|
||||
<source>For interoperability with other apps such as Joplin</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -880,27 +887,27 @@ You can also use other markdown syntax inside them.</source>
|
|||
<context>
|
||||
<name>harbour-nextcloudnotes</name>
|
||||
<message>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="76"/>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="93"/>
|
||||
<source>Notes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="77"/>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="94"/>
|
||||
<source>Offline</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="78"/>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="95"/>
|
||||
<source>Synced</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="92"/>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="109"/>
|
||||
<source>API error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="85"/>
|
||||
<location filename="../qml/harbour-nextcloudnotes.qml" line="102"/>
|
||||
<source>File error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
Loading…
Reference in a new issue