1
0
Fork 0
mirror of https://gitlab.com/niansa/qcommsy.git synced 2025-03-06 20:53:33 +01:00
qcommsy/main.cpp

389 lines
13 KiB
C++

#include "ui_overview.h"
#include "ui_info.h"
#include "ui_login.h"
#include "ui_failure.h"
#include "ui_offline.h"
#include "ui_postView.h"
#include "libcommsy.hpp"
#include "libcommsyauth.hpp"
#include <limits.h>
#include <string>
#include <vector>
#include <QMainWindow>
#include <QApplication>
#include <QPushButton>
#include <QString>
#include <QUrl>
#include <QDir>
#include <QFile>
#include <QTimer>
#include <QMainWindow>
#include <QListWidgetItem>
#include <QFont>
#include <QStyleFactory>
#include <QDesktopServices>
#include <QSettings>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#define QCommsy_NAME "QCommsy"
#define QCommsy_VERSION "1.1-dev"
#define UPDATE_WINDOW(a) a->processEvents();
static QSettings *settings;
static QApplication *a;
static QMainWindow *w;
class _UILoader {
libCommsy *connector = nullptr;
libCommsyAuth *auther = nullptr;
bool cacheInvalidate = true;
public:
void failureWindow();
void overviewWindow(bool catchInvalidRoomError = true);
void loginWindow(const QString& failure = "");
void infoWindow();
void postViewWindow(commsyPost *thispost, QString description);
void offlineWindow();
_UILoader () {
auther = new libCommsyAuth();
}
void reconnect() {
// Destroy old connector
if (connector != nullptr) {
if (not cacheInvalidate) {
return;
}
delete connector;
connector = nullptr;
}
cacheInvalidate = false;
// Connect to commsy
connector = new libCommsy(settings->value("server_url").toString().toStdString(), settings->value("server_sid").toString().toStdString(), settings->value("server_room").toString().toStdString());
}
void logout() {
settings->remove("server_sid");
}
void downloadAndOpenFile(QNetworkRequest mNetReq, const QString& filename) {
auto mNetMan = new QNetworkAccessManager();
// Set SID in request so we're authenticated TODO: think about a cleaner way
mNetReq.setRawHeader("Cookie", "SID=" + settings->value("server_sid").toString().toUtf8());
// Connect to downloading
w->connect(mNetMan, &QNetworkAccessManager::finished, [this, mNetMan, filename] (QNetworkReply *mNetReply) {
// Save and open downloaded file
{
// Initialise
QString destPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + '/' + filename;
QFile destFile(destPath);
// Write downloaded data to file
if (!destFile.open(QIODevice::WriteOnly)) {
return failureWindow();
}
destFile.write(mNetReply->readAll());
destFile.close();
// Open file in some application
//QDesktopServices::openUrl(destPath);
QDesktopServices::openUrl(QUrl::fromLocalFile(destPath));
}
// Clean up
mNetMan->deleteLater();
});
// Start download
mNetMan->get(mNetReq);
}
};
void _UILoader::infoWindow() {
Ui::infoWindow *thisui = new Ui::infoWindow;
// Show initial UI
thisui->setupUi(w);
w->show();
// Update version info
thisui->versionInfo->setText(
"<b>App frontend:</b> " QCommsy_NAME " version " QCommsy_VERSION "<br />"
"<b>Authentication backend:</b> " libCommsyAuth_NAME " version " libCommsyAuth_VERSION "<br />"
"<b>Scrapping backend:</b> " libCommsy_NAME " version " libCommsy_VERSION "<br />"
);
thisui->buildDateInfo->setText(
"Build date:\n"
__DATE__ " " __TIME__
);
// Add button handlers
w->connect(thisui->backButton, &QPushButton::pressed, [this] () { loginWindow(); });
}
void _UILoader::failureWindow() {
Ui::failureWindow *thisui = new Ui::failureWindow;
QString reason;
// Show initial UI
thisui->setupUi(w);
w->show();
// Get error message
reason = "Ein interner Fehler ist aufgetreten<br />"
"<i>Dies ist sehr wahrscheinlich ein Programmfehler. Sollte das zu häufig passieren, kontaktiere bitte den Entwickler</i>";
// Show error message
thisui->descriptionText->setText("<b>Verbindung fehlgeschlagen</b><br />" + reason);
// Add button handlers
w->connect(thisui->retryButton, &QPushButton::pressed, [this] () { loginWindow(); });
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
}
void _UILoader::offlineWindow() {
Ui::offlineWindow *thisui = new Ui::offlineWindow;
// Show initial UI
thisui->setupUi(w);
w->show();
// Add button handlers
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
}
void _UILoader::loginWindow(const QString& failure) {
Ui::loginWindow *thisui = new Ui::loginWindow;
// Check if logged in already
if (settings->contains("server_sid")) {
return overviewWindow();
}
// Show initial UI
thisui->setupUi(w);
w->show();
// Restore login data if wanted
bool restoreForm = settings->value("server_save", false).toBool();
if (restoreForm) {
thisui->saveBox->setCheckState(Qt::Checked);
thisui->adressLine->setText(settings->value("server_url", thisui->adressLine->text()).toString());
thisui->roomLine->setText(settings->value("server_room", "").toString());
thisui->usernameLine->setText(settings->value("server_username", "").toString());
thisui->passwordLine->setText(settings->value("server_password", "").toString());
}
// Set failure text
thisui->failureText->setText(failure);
// Connect connection handlers
w->connect(auther, &libCommsyAuth::authDone, [thisui] (QNetworkReply *) { // Finished authentication; reenable login button
thisui->loginButton->setDisabled(false);
});
w->connect(auther, &libCommsyAuth::authDone, [this, thisui] (QNetworkReply *netReply) { // Finished authentication; try to login
// Login
try {
settings->setValue("server_sid", auther->getSID(netReply));
auther->deleteLater();
cacheInvalidate = true;
return overviewWindow(false);
} catch (authFailureError&) {
thisui->failureText->setText("Die eingegebenen Anmeldedaten sind ungültig");
} catch (invalidRoomError&) {
thisui->failureText->setText("Der angegebene Raum existiert nicht");
}
});
w->connect(auther, &libCommsyAuth::connectionDone, [this, thisui] (QNetworkReply *netReply) { // Finished test connection
auther->sendAuth(auther->getAuthUrl(netReply), thisui->usernameLine->text(), thisui->passwordLine->text());
});
// Add button handlers
w->connect(thisui->loginButton, &QPushButton::pressed, [this, thisui] () {
// Check input lines
if (thisui->adressLine->text().isEmpty() or thisui->usernameLine->text().isEmpty() or thisui->roomLine->text().isEmpty() or thisui->passwordLine->text().isEmpty()) {
return;
}
// Make sure the adressLine doesn't end with /
if (thisui->adressLine->text().endsWith("/")) {
thisui->adressLine->backspace();
}
// Save basic server credentials
bool saveAllData = thisui->saveBox->checkState() == Qt::Checked;
settings->setValue("server_save", saveAllData);
settings->setValue("server_url", thisui->adressLine->text());
settings->setValue("server_room", thisui->roomLine->text());
if (saveAllData) {
settings->setValue("server_username", thisui->usernameLine->text());
settings->setValue("server_password", thisui->passwordLine->text());
}
// Disable login button
thisui->loginButton->setDisabled(true);
// Connect
auther->connectionInit(thisui->adressLine->text());
});
}
void _UILoader::postViewWindow(commsyPost *thispost, QString description) {
Ui::postViewWindow *thisui = new Ui::postViewWindow;
// Show initial UI
thisui->setupUi(w);
w->show();
thisui->statusText->setVisible(false);
// Remove trailing space from description
if (description.size() != 0 and description.back() == '\n') {
description.chop(1);
}
// Update informations
thisui->titleText->setText(QString::fromStdString(thispost->name));
thisui->metaText->setText(QString::fromStdString(thispost->meta));
thisui->descriptionText->setText(description);
// Update file list if required
if (thispost->files.size() != 0) {
for (const auto& thisfile : thispost->files) {
thisui->fileList->addItem(QString::fromStdString(thisfile.name));
}
} else { // If no files exist, hide the list
thisui->filesInfo->setHidden(true);
thisui->fileList->setHidden(true);
}
// Add button handlers
w->connect(thisui->fileList, &QListWidget::activated, [this, thisui, thispost] (QModelIndex index) {
// Get full file URL
commsyFile *thisfile = &thispost->files[static_cast<unsigned long>(index.row())];
QUrl fullFileUrl(settings->value("server_url").toString() + QString::fromStdString(thisfile->url));
// Start download
downloadAndOpenFile(QNetworkRequest(fullFileUrl), QString::fromStdString(thisfile->name));
// Show download status für 5 seconds
thisui->statusText->setVisible(true);
QTimer::singleShot(5 * 1000, thisui->statusText, &QLabel::hide);
});
w->connect(thisui->backButton, &QPushButton::pressed, [this] () { loginWindow(); });
}
void _UILoader::overviewWindow(bool catchInvalidRoomError) {
Ui::overviewWindow *thisui = new Ui::overviewWindow;
// Show initial UI
thisui->setupUi(w);
w->show();
// Add button handlers
w->connect(thisui->postList, &QListWidget::activated, [this, thisui] (QModelIndex index) {
auto postID = static_cast<unsigned long>(index.row());
commsyPost *thispost = connector->getPost(postID);
thisui->centralwidget->setDisabled(true);
thispost->unread = false; // Mark post as read locally
// Run blocking code
UPDATE_WINDOW(a) {
postViewWindow(thispost, QString::fromStdString(*connector->getDescription(postID)));
}
});
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
w->connect(thisui->infoButton, &QPushButton::pressed, [this] () { infoWindow(); });
// Run blocking code
UPDATE_WINDOW(a) {
// Connect if required
try {
reconnect();
} catch (invalidSIDError&) {
logout();
return loginWindow("Die Sitzung ist abgelaufen - bitte erneut anmelden");
} catch (invalidRoomError& exception) {
if (catchInvalidRoomError) {
logout();
return loginWindow("Der Raum existiert nicht mehr");
} else {
throw exception;
}
} catch (connectionFailError&) {
return offlineWindow();
} catch (std::exception&) {
return failureWindow();
}
// Get font used for unread posts
QFont unreadFont = QFont();
unreadFont.setBold(true);
// Refresh view
thisui->postCounter->setText(QString::number(connector->numposts) + " Einträge");
thisui->postList->clear();
for (const auto& thispost : connector->posts) {
QListWidgetItem *thisitem = new QListWidgetItem(QString::fromStdString(thispost.name), thisui->postList);
if (thispost.unread) {
thisitem->setFont(unreadFont);
}
QString postIcon;
switch(thispost.taskState) {
case taskState::done:
postIcon = "checkbox-checked-symbolic";
break;
case taskState::inProgress:
postIcon = "clock";
break;
case taskState::todo:
postIcon = "emblem-important-symbolic";
break;
default:
postIcon = "arrow-right";
break;
}
thisitem->setIcon(QIcon::fromTheme(postIcon));
}
}
}
int main(int argc, char *argv[]) {
// Initalise settings storage
QCoreApplication::setOrganizationName("QCommsy");
QCoreApplication::setOrganizationDomain("qcommsy.github.io");
QCoreApplication::setApplicationName("QCommsy");
settings = new QSettings();
//Initialise variables
a = new QApplication(argc, argv);
w = new QMainWindow;
_UILoader UILoader;
// Set theme
a->setStyle(QStyleFactory::create("android"));
// Load initial window
UILoader.loginWindow();
// Run forever
return a->exec();
}