Service selection dialog

This commit is contained in:
Bernhard Rosenkränzer 2024-09-03 15:40:08 +02:00
parent 892de92aa2
commit 32af5c8e93
15 changed files with 204 additions and 23 deletions

View File

@ -1,4 +1,5 @@
#include "Configurator.h"
#include <dialogs/ServicesDialog.h>
#include <iostream>
#include <QJsonDocument>
#include <QJsonObject>
@ -13,25 +14,37 @@ Configurator::Configurator(int &argc, char **&argv):QApplication(argc, argv),_na
}
void Configurator::loginRequested() {
QNetworkRequest *req=new QNetworkRequest("https://dashboard." + _loginDialog->domain() + "/apps");
connect(&_nam, &QNetworkAccessManager::finished, this, &Configurator::appListReceived);
QNetworkReply *r=_nam.get(*req);
}
void Configurator::appListReceived(QNetworkReply *reply) {
disconnect(&_nam, &QNetworkAccessManager::finished, this, &Configurator::appListReceived);
if(reply->error() != QNetworkReply::NoError) {
QByteArray servicesJson = download("https://dashboard." + _loginDialog->domain() + "/apps");
if(servicesJson.isEmpty()) {
_loginDialog->setMessage(tr("Failed to retrieve app list. Is the domain name correct?"));
_loginDialog->show();
return;
}
QJsonDocument services = QJsonDocument::fromJson(reply->readAll());
QJsonDocument services = QJsonDocument::fromJson(servicesJson);
if(!services.isArray()) {
_loginDialog->setMessage(tr("App list did not return an array. Is the domain name correct?"));
_loginDialog->show();
return;
}
_services = services.array();
for(auto i : _services)
std::cerr << qPrintable(i.title) << std::endl;
ServicesDialog *d = new ServicesDialog(0);
d->show();
}
QByteArray Configurator::download(QUrl const &url) {
QNetworkRequest req(url);
QNetworkReply *r = _nam.get(req);
waitForDownload(r);
QByteArray d = r->readAll();
delete r;
return d;
}
void Configurator::waitForDownload(QNetworkReply *r) const {
if(!r->isFinished()) {
QEventLoop loop;
connect(r, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
}
}

View File

@ -11,11 +11,17 @@ class Configurator:public QApplication {
Q_OBJECT
public:
Configurator(int &argc, char **&argv);
QNetworkAccessManager &nam() { return _nam; }
QString baseUrl() const { return "https://dashboard." + _loginDialog->domain(); }
QByteArray download(QUrl const &url);
void waitForDownload(QNetworkReply *r) const;
Services const &services() const { return _services; }
protected Q_SLOTS:
void loginRequested();
void appListReceived(QNetworkReply *reply);
private:
QNetworkAccessManager _nam;
FederatedLogin * _loginDialog;
Services _services;
};
#define app static_cast<Configurator*>(Configurator::instance())

View File

@ -1,2 +1,6 @@
add_library(dialogs STATIC FederatedLogin.cpp)
target_link_libraries(dialogs Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/lib)
add_library(dialogs STATIC FederatedLogin.cpp ServicesDialog.cpp)
target_link_libraries(dialogs Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets fed)

View File

@ -21,10 +21,13 @@ FederatedLogin::FederatedLogin(QWidget *parent):QDialog(parent),_layout(this) {
_password->setEchoMode(QLineEdit::Password);
_passwordLbl->setBuddy(_password);
_layout.addWidget(_password, y, 1);
_ok = new QPushButton(tr("&OK"), this);
_layout.addWidget(_ok, ++y, 0);
_cancel = new QPushButton(tr("&Cancel"), this);
_layout.addWidget(_cancel, y, 1);
_buttons = new ButtonRow(this);
_layout.addWidget(_buttons, ++y, 0, 1, 2);
_ok = new QPushButton(tr("&OK"), _buttons);
_ok->setDefault(true);
_buttons->add(_ok);
_cancel = new QPushButton(tr("&Cancel"), _buttons);
_buttons->add(_cancel);
connect(_ok, &QPushButton::clicked, this, &QDialog::accept);
connect(_cancel, &QPushButton::clicked, this, &QDialog::reject);
}

View File

@ -6,6 +6,8 @@
#include <QLineEdit>
#include <QPushButton>
#include "../lib/ButtonRow.h"
class FederatedLogin:public QDialog {
Q_OBJECT
public:
@ -23,6 +25,7 @@ protected:
QLineEdit * _user;
QLabel * _passwordLbl;
QLineEdit * _password;
ButtonRow * _buttons;
QPushButton * _ok;
QPushButton * _cancel;
};

View File

@ -0,0 +1,59 @@
#include "ServicesDialog.h"
#include "ServiceWidget.h"
#include "Configurator.h"
#include <QScrollBar>
#include <iostream>
ServicesDialog::ServicesDialog(QWidget *parent):QDialog(parent),_layout(this) {
int y = 0;
_welcome = new QLabel(tr("Welcome to your Federated Computer\n"
"We can automatically configure these services for you:"), this);
_layout.addWidget(_welcome, y, 0);
_knownServicesScroller = new QScrollArea(this);
_knownServices = new QWidget(this);
QBoxLayout *ksLayout = new QBoxLayout(QBoxLayout::TopToBottom, _knownServices);
_layout.addWidget(_knownServicesScroller, ++y, 0);
_usLabel = new QLabel(tr("Your subscription also includes the following services, which can not currently be auto-configured, but you can configure them manually:"), this);
_layout.addWidget(_usLabel, ++y, 0);
_unknownServicesScroller = new QScrollArea(this);
_unknownServices = new QWidget(this);
QBoxLayout *usLayout = new QBoxLayout(QBoxLayout::TopToBottom, _unknownServices);
_layout.addWidget(_unknownServicesScroller, ++y, 0);
int k = 0, u = 0;
for(auto i : app->services()) {
if(i.title == "Nextcloud" || i.title == "Panel") {
ServiceWidget *w=new ServiceWidget(i, _knownServices);
ksLayout->addWidget(w, ++k);
} else {
ServiceWidget *w=new ServiceWidget(i, _unknownServices);
usLayout->addWidget(w, ++u);
}
}
_knownServicesScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_unknownServicesScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_knownServicesScroller->setWidget(_knownServices);
_unknownServicesScroller->setWidget(_unknownServices);
_buttons = new ButtonRow(this);
QPushButton *ok = new QPushButton(tr("&OK"), _buttons);
connect(ok, &QPushButton::clicked, this, &QDialog::accept);
ok->setDefault(true);
QPushButton *cancel = new QPushButton(tr("&Cancel"), _buttons);
connect(cancel, &QPushButton::clicked, this, &QDialog::reject);
_buttons->add(ok);
_buttons->add(cancel);
_layout.addWidget(_buttons, ++y, 0);
resizeEvent(0);
}
void ServicesDialog::resizeEvent(QResizeEvent *e) {
// Make sure the known services and unknown services
// lists always use the full width available
if(e)
QDialog::resizeEvent(e);
int const w = _knownServicesScroller->width();
_knownServices->setFixedWidth(w);
_unknownServices->setFixedWidth(w);
}

27
dialogs/ServicesDialog.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <QDialog>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QResizeEvent>
#include <QScrollArea>
#include <lib/ButtonRow.h>
class ServicesDialog:public QDialog {
Q_OBJECT
public:
ServicesDialog(QWidget *parent=0);
protected:
void resizeEvent(QResizeEvent *e) override;
protected:
QGridLayout _layout;
QLabel * _welcome;
QScrollArea * _knownServicesScroller;
QWidget * _knownServices;
QLabel * _usLabel;
QScrollArea * _unknownServicesScroller;
QWidget * _unknownServices;
ButtonRow * _buttons;
};

4
lib/ButtonRow.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "ButtonRow.h"
ButtonRow::ButtonRow(QWidget *parent, QBoxLayout::Direction dir):QWidget(parent),_layout(dir, this) {
}

16
lib/ButtonRow.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <QWidget>
#include <QBoxLayout>
#include <QAbstractButton>
class ButtonRow:public QWidget {
Q_OBJECT
public:
ButtonRow(QWidget *parent=0, QBoxLayout::Direction dir=QBoxLayout::LeftToRight);
void add(QAbstractButton *btn) {
_layout.addWidget(btn);
}
protected:
QBoxLayout _layout;
};

View File

@ -1,2 +1,4 @@
add_library(fed STATIC Service.cpp)
target_link_libraries(fed Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets)
include_directories(${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_library(fed STATIC Service.cpp ButtonRow.cpp ServiceWidget.cpp)
target_link_libraries(fed Qt${QT_VERSION}::Core Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets Qt${QT_VERSION}::Network)

View File

@ -1,4 +1,8 @@
#include "Service.h"
#include "../Configurator.h"
#include <QEventLoop>
#include <QNetworkRequest>
#include <iostream>
Service::Service(QJsonObject const &o) {
@ -11,6 +15,13 @@ Service::Service(QJsonObject const &o) {
LDAP = o["LDAP"].toBool();
}
QPixmap const &Service::pixmap() {
if(_image.isNull())
_image.loadFromData(app->download(app->baseUrl() + image));
return _image;
}
Services::Services(QJsonArray const &a):QList<Service>() {
for(auto i : a) {
if(!i.isObject()) {

View File

@ -4,17 +4,22 @@
#include <QJsonObject>
#include <QString>
#include <QUrl>
#include <QPixmap>
struct Service {
Service(QJsonObject const &o);
QPixmap const &pixmap();
QString title;
QUrl url;
QUrl documentationUrl;
QUrl image;
QString image;
QString description;
QString specialNote;
bool LDAP;
protected:
QPixmap _image;
};
class Services:public QList<Service> {

11
lib/ServiceWidget.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "ServiceWidget.h"
ServiceWidget::ServiceWidget(Service &s, QWidget *parent):QWidget(parent),_layout(QBoxLayout::LeftToRight, this) {
_icon = new QLabel(this);
_icon->setPixmap(s.pixmap().scaled(32, 32));
_layout.addWidget(_icon);
_label = new QLabel(this);
_label->setText("<h3>" + s.title + "</h3>" + s.description);
_layout.addWidget(_label);
_layout.setSpacing(4);
}

17
lib/ServiceWidget.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <QWidget>
#include <QBoxLayout>
#include <QLabel>
#include "Service.h"
class ServiceWidget:public QWidget {
Q_OBJECT
public:
ServiceWidget(Service &s, QWidget *parent=0);
protected:
QBoxLayout _layout;
QLabel * _icon;
QLabel * _label;
};

View File

@ -1,6 +1,6 @@
#include "Configurator.h"
int main(int argc, char **argv) {
Configurator app(argc, argv);
app.exec();
Configurator c(argc, argv);
c.exec();
}