diff --git a/Configurator.cpp b/Configurator.cpp index 9f3133b..05d6716 100644 --- a/Configurator.cpp +++ b/Configurator.cpp @@ -1,4 +1,5 @@ #include "Configurator.h" +#include #include #include #include @@ -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(); + } } diff --git a/Configurator.h b/Configurator.h index 3f7dd10..f96c575 100644 --- a/Configurator.h +++ b/Configurator.h @@ -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::instance()) diff --git a/dialogs/CMakeLists.txt b/dialogs/CMakeLists.txt index fed1b45..da4b607 100644 --- a/dialogs/CMakeLists.txt +++ b/dialogs/CMakeLists.txt @@ -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) diff --git a/dialogs/FederatedLogin.cpp b/dialogs/FederatedLogin.cpp index dd18488..17f834d 100644 --- a/dialogs/FederatedLogin.cpp +++ b/dialogs/FederatedLogin.cpp @@ -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); } diff --git a/dialogs/FederatedLogin.h b/dialogs/FederatedLogin.h index c33ac8e..53864ee 100644 --- a/dialogs/FederatedLogin.h +++ b/dialogs/FederatedLogin.h @@ -6,6 +6,8 @@ #include #include +#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; }; diff --git a/dialogs/ServicesDialog.cpp b/dialogs/ServicesDialog.cpp new file mode 100644 index 0000000..f0cbff1 --- /dev/null +++ b/dialogs/ServicesDialog.cpp @@ -0,0 +1,59 @@ +#include "ServicesDialog.h" +#include "ServiceWidget.h" +#include "Configurator.h" + +#include + +#include + +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); +} diff --git a/dialogs/ServicesDialog.h b/dialogs/ServicesDialog.h new file mode 100644 index 0000000..9b16014 --- /dev/null +++ b/dialogs/ServicesDialog.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +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; +}; diff --git a/lib/ButtonRow.cpp b/lib/ButtonRow.cpp new file mode 100644 index 0000000..ccea396 --- /dev/null +++ b/lib/ButtonRow.cpp @@ -0,0 +1,4 @@ +#include "ButtonRow.h" + +ButtonRow::ButtonRow(QWidget *parent, QBoxLayout::Direction dir):QWidget(parent),_layout(dir, this) { +} diff --git a/lib/ButtonRow.h b/lib/ButtonRow.h new file mode 100644 index 0000000..31e706e --- /dev/null +++ b/lib/ButtonRow.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +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; +}; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 30f2eb7..eb2da33 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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) diff --git a/lib/Service.cpp b/lib/Service.cpp index ab6e6c6..df6ba63 100644 --- a/lib/Service.cpp +++ b/lib/Service.cpp @@ -1,4 +1,8 @@ #include "Service.h" +#include "../Configurator.h" + +#include +#include #include 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() { for(auto i : a) { if(!i.isObject()) { diff --git a/lib/Service.h b/lib/Service.h index 6738d40..1d6552f 100644 --- a/lib/Service.h +++ b/lib/Service.h @@ -4,17 +4,22 @@ #include #include #include +#include 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 { diff --git a/lib/ServiceWidget.cpp b/lib/ServiceWidget.cpp new file mode 100644 index 0000000..14e1b5d --- /dev/null +++ b/lib/ServiceWidget.cpp @@ -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("

" + s.title + "

" + s.description); + _layout.addWidget(_label); + _layout.setSpacing(4); +} diff --git a/lib/ServiceWidget.h b/lib/ServiceWidget.h new file mode 100644 index 0000000..f0a6d38 --- /dev/null +++ b/lib/ServiceWidget.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +#include "Service.h" + +class ServiceWidget:public QWidget { + Q_OBJECT +public: + ServiceWidget(Service &s, QWidget *parent=0); +protected: + QBoxLayout _layout; + QLabel * _icon; + QLabel * _label; +}; diff --git a/main.cpp b/main.cpp index 588e4ac..e954a5d 100644 --- a/main.cpp +++ b/main.cpp @@ -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(); }