From a35eb3d1a46b51604d1e544bfcb3dc187536ad35 Mon Sep 17 00:00:00 2001 From: Patrizio Bekerle Date: Mon, 5 Jun 2023 17:07:30 +0200 Subject: [PATCH] #2789 add: more Deck implementation --- src/dialogs/nextclouddeckdialog.cpp | 35 +++++- src/dialogs/nextclouddeckdialog.h | 8 +- src/dialogs/nextclouddeckdialog.ui | 133 ++++++++++++++++------ src/dialogs/notedialog.cpp | 6 +- src/dialogs/settingsdialog.ui | 12 +- src/services/nextclouddeckservice.cpp | 53 ++++++--- src/services/nextclouddeckservice.h | 8 +- src/utils/misc.cpp | 9 ++ src/utils/urlhandler.cpp | 3 + src/widgets/qownnotesmarkdowntextedit.cpp | 2 +- 10 files changed, 205 insertions(+), 64 deletions(-) diff --git a/src/dialogs/nextclouddeckdialog.cpp b/src/dialogs/nextclouddeckdialog.cpp index 6a392afcd3..be670523f7 100644 --- a/src/dialogs/nextclouddeckdialog.cpp +++ b/src/dialogs/nextclouddeckdialog.cpp @@ -2,12 +2,17 @@ #include "services/nextclouddeckservice.h" #include "ui_nextclouddeckdialog.h" +#include "mainwindow.h" +#include NextcloudDeckDialog::NextcloudDeckDialog(QWidget *parent) : - QDialog(parent), + MasterDialog(parent), ui(new Ui::NextcloudDeckDialog) { ui->setupUi(this); ui->dueDateTimeEdit->setDateTime(QDateTime::currentDateTime()); + ui->saveButton->setEnabled(false); + ui->dueDateTimeCheckBox->setChecked(true); + ui->titleLineEdit->setFocus(); } NextcloudDeckDialog::~NextcloudDeckDialog() { @@ -15,12 +20,26 @@ NextcloudDeckDialog::~NextcloudDeckDialog() { } void NextcloudDeckDialog::on_saveButton_clicked() { + ui->saveButton->setEnabled(false); NextcloudDeckService nextcloudDeckService(CloudConnection::currentCloudConnection().getId(), this); auto *dateTime = new QDateTime(ui->dueDateTimeEdit->dateTime()); - nextcloudDeckService.createCard(ui->titleLineEdit->text(), - "", - dateTime); + dateTime->setTimeZone(QTimeZone::systemTimeZone()); + const QString &title = ui->titleLineEdit->text(); + int cardId = nextcloudDeckService.createCard(title, + ui->descriptionTextEdit->toPlainText(), + ui->dueDateTimeCheckBox->isChecked() ? dateTime : nullptr); + auto linkText = QString("[%1](%2)").arg( + title, nextcloudDeckService.getCardLinkForId(cardId)); + +#ifndef INTEGRATION_TESTS + MainWindow *mainWindow = MainWindow::instance(); + if (mainWindow != nullptr) { + mainWindow->activeNoteTextEdit()->insertPlainText(linkText); + } +#endif + + close(); } void NextcloudDeckDialog::on_add1HourButton_clicked() { @@ -46,3 +65,11 @@ void NextcloudDeckDialog::on_sub1HourButton_clicked() { void NextcloudDeckDialog::on_subd1DayButton_clicked() { ui->dueDateTimeEdit->setDateTime(ui->dueDateTimeEdit->dateTime().addDays(-1)); } + +void NextcloudDeckDialog::on_titleLineEdit_textChanged(const QString &arg1) { + ui->saveButton->setEnabled(!arg1.isEmpty()); +} + +void NextcloudDeckDialog::on_dueDateTimeCheckBox_toggled(bool checked) { + ui->dueDateTimeEdit->setEnabled(checked); +} diff --git a/src/dialogs/nextclouddeckdialog.h b/src/dialogs/nextclouddeckdialog.h index 681999ede5..5ec4dd1223 100644 --- a/src/dialogs/nextclouddeckdialog.h +++ b/src/dialogs/nextclouddeckdialog.h @@ -3,11 +3,13 @@ #include +#include "masterdialog.h" + namespace Ui { class NextcloudDeckDialog; } -class NextcloudDeckDialog : public QDialog +class NextcloudDeckDialog : public MasterDialog { Q_OBJECT @@ -30,6 +32,10 @@ private slots: void on_subd1DayButton_clicked(); + void on_titleLineEdit_textChanged(const QString &arg1); + + void on_dueDateTimeCheckBox_toggled(bool checked); + private: Ui::NextcloudDeckDialog *ui; }; diff --git a/src/dialogs/nextclouddeckdialog.ui b/src/dialogs/nextclouddeckdialog.ui index f8301df990..97242bc19a 100644 --- a/src/dialogs/nextclouddeckdialog.ui +++ b/src/dialogs/nextclouddeckdialog.ui @@ -6,39 +6,39 @@ 0 0 - 400 - 300 + 463 + 412 Dialog - - + + - +1d + -10min - - - - Save the current todo item - + + - Save - - - - :/icons/breeze-qownnotes/16x16/document-save.svg:/icons/breeze-qownnotes/16x16/document-save.svg + +10min - - Ctrl+S + + + + + + +1d - + + + + QDateTimeEdit::HourSection @@ -48,60 +48,123 @@ - - - - Title + + + + -1d + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Save the current todo item + + + &Save + + + + :/icons/breeze-qownnotes/16x16/document-save.svg:/icons/breeze-qownnotes/16x16/document-save.svg + + + Ctrl+S + + + + - + +1h - - - - +10min + + + + Title - + -1h - - + + - -10min + Description: - - + + - -1d + Due date + + + QOwnNotesMarkdownTextEdit + QPlainTextEdit +
widgets/qownnotesmarkdowntextedit.h
+
+
titleLineEdit dueDateTimeEdit - saveButton add10MinButton add1HourButton add1DayButton sub10MinButton sub1HourButton subd1DayButton + saveButton + dueDateTimeCheckBox + descriptionTextEdit diff --git a/src/dialogs/notedialog.cpp b/src/dialogs/notedialog.cpp index 36bbb60235..5c31286a65 100644 --- a/src/dialogs/notedialog.cpp +++ b/src/dialogs/notedialog.cpp @@ -8,6 +8,7 @@ #include #include "ui_notedialog.h" +#include "utils/urlhandler.h" NoteDialog::NoteDialog(QWidget *parent) : MasterDialog(parent), ui(new Ui::NoteDialog) { ui->setupUi(this); @@ -37,11 +38,8 @@ NoteDialog::~NoteDialog() { delete ui; } void NoteDialog::on_noteTextView_anchorClicked(const QUrl &url) { qDebug() << __func__ << " - 'url': " << url; - const QString scheme = url.scheme(); - if ((scheme == QStringLiteral("note") || scheme == QStringLiteral("noteid") || - scheme == QStringLiteral("task") || scheme == QStringLiteral("checkbox")) || - (scheme == QStringLiteral("file") && Note::fileUrlIsNoteInCurrentNoteFolder(url))) { + if (UrlHandler::isUrlSchemeLocal(url)) { return; } diff --git a/src/dialogs/settingsdialog.ui b/src/dialogs/settingsdialog.ui index 066680f6cf..72c940d829 100644 --- a/src/dialogs/settingsdialog.ui +++ b/src/dialogs/settingsdialog.ui @@ -1497,11 +1497,14 @@ - 1 + 0 999999999 + + 0 + @@ -1521,11 +1524,14 @@ - 1 + 0 999999999 + + 0 + @@ -7036,8 +7042,8 @@ Just test yourself if you get sync conflicts and set a higher value if so.enableSocketServerCheckBox - + diff --git a/src/services/nextclouddeckservice.cpp b/src/services/nextclouddeckservice.cpp index e6ffc73c5f..7aea405045 100644 --- a/src/services/nextclouddeckservice.cpp +++ b/src/services/nextclouddeckservice.cpp @@ -1,24 +1,27 @@ #include "nextclouddeckservice.h" #include -#include +#include +#include #include #include -#include -#include +#include #include "entities/cloudconnection.h" +#include "utils/gui.h" #include "utils/misc.h" NextcloudDeckService::NextcloudDeckService(int cloudConnectionId, QObject *parent) : QObject(parent) { this->cloudConnection = CloudConnection::fetch(cloudConnectionId); + this->serverUrl = this->cloudConnection.getServerUrl(); this->boardId = this->cloudConnection.getNextcloudDeckBoardId(); this->stackId = this->cloudConnection.getNextcloudDeckStackId(); } -void NextcloudDeckService::createCard(const QString& title, +int NextcloudDeckService::createCard(const QString& title, const QString& description, QDateTime* dueDateTime) { + int cardId = -1; auto *manager = new QNetworkAccessManager(); QEventLoop loop; QTimer timer; @@ -31,9 +34,10 @@ void NextcloudDeckService::createCard(const QString& title, // 10 sec timeout for the request timer.start(10000); - QUrl url(this->cloudConnection.getServerUrl() + "/apps/deck/api/v1.1/boards/" + + QUrl url(serverUrl + "/apps/deck/api/v1.1/boards/" + QString::number(this->boardId) + "/stacks/" + QString::number(this->stackId) + "/cards"); + qDebug() << __func__ << " - 'url': " << url; QJsonObject bodyJson; bodyJson["title"] = title; @@ -45,9 +49,10 @@ void NextcloudDeckService::createCard(const QString& title, } if (dueDateTime != nullptr) { - bodyJson["dueDateTime"] = dueDateTime->toSecsSinceEpoch(); + bodyJson["duedate"] = dueDateTime->toString(Qt::ISODate); } + qDebug() << __func__ << " - 'bodyJson': " << bodyJson; QJsonDocument bodyJsonDoc(bodyJson); QNetworkRequest networkRequest = QNetworkRequest(url); @@ -65,11 +70,7 @@ void NextcloudDeckService::createCard(const QString& title, networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); networkRequest.setRawHeader("OCS-APIRequest", "true"); - - auto authString = this->cloudConnection.getUsername() + QStringLiteral(":") + this->cloudConnection.getPassword(); - QByteArray authStringBase64 = authString.toLocal8Bit().toBase64(); - QString headerData = QStringLiteral("Basic ") + authStringBase64; - networkRequest.setRawHeader("Authorization", headerData.toLocal8Bit()); + addAuthHeader(networkRequest); reply = manager->post(networkRequest, bodyJsonDoc.toJson()); @@ -87,15 +88,39 @@ void NextcloudDeckService::createCard(const QString& title, QJsonDocument jsonDoc = QJsonDocument::fromJson(data); QJsonObject jsonObject = jsonDoc.object(); - int id = jsonObject["id"].toInt(); + cardId = jsonObject["id"].toInt(); - qDebug() << __func__ << " - 'id': " << id; + qDebug() << __func__ << " - 'cardId': " << cardId; + qDebug() << __func__ << " - 'jsonDoc': " << jsonDoc; } else { + QString errorString = reply->errorString(); + Utils::Gui::warning(nullptr, tr("Error while creating card"), + tr("Creating a card failed with status code %1 and message: %2") + .arg(QString::number(returnStatusCode), errorString), + "nextcloud-deck-create-failed"); + qDebug() << __func__ << " - error: " << returnStatusCode; - qDebug() << __func__ << " - 'data': " << data; + qDebug() << __func__ << " - 'errorString': " << errorString; } } reply->deleteLater(); delete (manager); + + return cardId; +} + +QString NextcloudDeckService::getCardLinkForId(int cardId) { + qDebug() << __func__ << " - 'boardId': " << this->boardId; + + return QStringLiteral("%1/apps/deck/#/board/%2/card/%3").arg( + this->serverUrl, QString::number(this->boardId), QString::number(cardId)); +} + +void NextcloudDeckService::addAuthHeader(QNetworkRequest& networkRequest) { + auto authString = + cloudConnection.getUsername() + QStringLiteral(":") + cloudConnection.getPassword(); + QByteArray authStringBase64 = authString.toLocal8Bit().toBase64(); + QString headerData = QStringLiteral("Basic ") + authStringBase64; + networkRequest.setRawHeader("Authorization", headerData.toLocal8Bit()); } diff --git a/src/services/nextclouddeckservice.h b/src/services/nextclouddeckservice.h index 5cc7da59c1..e7feea042b 100644 --- a/src/services/nextclouddeckservice.h +++ b/src/services/nextclouddeckservice.h @@ -1,8 +1,9 @@ #ifndef QOWNNOTES_NEXTCLOUDDECKSERVICE_H #define QOWNNOTES_NEXTCLOUDDECKSERVICE_H -#include #include +#include +#include #include "entities/cloudconnection.h" class NextcloudDeckService : public QObject { @@ -10,12 +11,15 @@ class NextcloudDeckService : public QObject { public: NextcloudDeckService(int cloudConnectionId, QObject* parent); - void createCard(const QString& title, const QString& description = "", QDateTime* dueDateTime = nullptr); + int createCard(const QString& title, const QString& description = "", QDateTime* dueDateTime = nullptr); + QString getCardLinkForId(int cardId); private: CloudConnection cloudConnection; + QString serverUrl; int boardId; int stackId; + void addAuthHeader(QNetworkRequest& networkRequest); }; #endif // QOWNNOTES_NEXTCLOUDDECKSERVICE_H diff --git a/src/utils/misc.cpp b/src/utils/misc.cpp index 00c02be62d..4f64f3361a 100644 --- a/src/utils/misc.cpp +++ b/src/utils/misc.cpp @@ -1759,6 +1759,15 @@ QString Utils::Misc::generateDebugInformation(bool withGitHubLineBreaks) { cloudConnection.getUsername(), withGitHubLineBreaks); output += prepareDebugInformationLine(QStringLiteral("accountId"), cloudConnection.getAccountId(), withGitHubLineBreaks); + + if (cloudConnection.getNextcloudDeckEnabled()) { + output += prepareDebugInformationLine(QStringLiteral("Nextcloud Deck boardId"), + QString::number(cloudConnection.getNextcloudDeckBoardId()), + withGitHubLineBreaks); + output += prepareDebugInformationLine(QStringLiteral("Nextcloud Deck stackId"), + QString::number(cloudConnection.getNextcloudDeckStackId()), + withGitHubLineBreaks); + } } // add script information diff --git a/src/utils/urlhandler.cpp b/src/utils/urlhandler.cpp index 373fddd86e..7e0ca2fa82 100644 --- a/src/utils/urlhandler.cpp +++ b/src/utils/urlhandler.cpp @@ -17,6 +17,7 @@ bool UrlHandler::isUrlSchemeLocal(const QUrl &url) { const QString scheme = url.scheme(); return scheme == QLatin1String("note") || scheme == QLatin1String("noteid") || scheme == QLatin1String("task") || scheme == QLatin1String("checkbox") || + scheme == QStringLiteral("deck") || (scheme == QLatin1String("file") && Note::fileUrlIsNoteInCurrentNoteFolder(url)); } @@ -61,6 +62,8 @@ void UrlHandler::openUrl(QString urlString) { handleNoteUrl(urlString, fragment); } else if (scheme == QStringLiteral("task")) { MainWindow::instance()->openTodoDialog(url.host()); + } else if (scheme == QStringLiteral("deck")) { + // We currently don't need that } else if (scheme == QStringLiteral("checkbox")) { handleCheckboxUrl(urlString); } else if (scheme == QStringLiteral("file") && urlWasNotValid) { diff --git a/src/widgets/qownnotesmarkdowntextedit.cpp b/src/widgets/qownnotesmarkdowntextedit.cpp index 65b7d97070..5f06273456 100644 --- a/src/widgets/qownnotesmarkdowntextedit.cpp +++ b/src/widgets/qownnotesmarkdowntextedit.cpp @@ -57,7 +57,7 @@ QOwnNotesMarkdownTextEdit::QOwnNotesMarkdownTextEdit(QWidget *parent) } // ignores note clicks in QMarkdownTextEdit in the note text edit - setIgnoredClickUrlSchemata(QStringList({"note", "task"})); + setIgnoredClickUrlSchemata(QStringList({"note", "task", "deck"})); connect(this, &QOwnNotesMarkdownTextEdit::zoomIn, this, [this]() { onZoom(/*in=*/true); }); connect(this, &QOwnNotesMarkdownTextEdit::zoomOut, this, [this]() { onZoom(/*in=*/false); });