You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					124 lines
				
				4.9 KiB
			
		
		
			
		
	
	
					124 lines
				
				4.9 KiB
			| 
								 
											2 years ago
										 
									 | 
							
								#include "tools/cabana/streams/routes.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <QDateTime>
							 | 
						||
| 
								 | 
							
								#include <QDialogButtonBox>
							 | 
						||
| 
								 | 
							
								#include <QFormLayout>
							 | 
						||
| 
								 | 
							
								#include <QJsonArray>
							 | 
						||
| 
								 | 
							
								#include <QJsonDocument>
							 | 
						||
| 
								 | 
							
								#include <QListWidget>
							 | 
						||
| 
								 | 
							
								#include <QMessageBox>
							 | 
						||
| 
								 | 
							
								#include <QPainter>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "system/hardware/hw.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The RouteListWidget class extends QListWidget to display a custom message when empty
							 | 
						||
| 
								 | 
							
								class RouteListWidget : public QListWidget {
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								  RouteListWidget(QWidget *parent = nullptr) : QListWidget(parent) {}
							 | 
						||
| 
								 | 
							
								  void setEmptyText(const QString &text) {
							 | 
						||
| 
								 | 
							
								    empty_text_ = text;
							 | 
						||
| 
								 | 
							
								    viewport()->update();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  void paintEvent(QPaintEvent *event) override {
							 | 
						||
| 
								 | 
							
								    QListWidget::paintEvent(event);
							 | 
						||
| 
								 | 
							
								    if (count() == 0) {
							 | 
						||
| 
								 | 
							
								      QPainter painter(viewport());
							 | 
						||
| 
								 | 
							
								      painter.drawText(viewport()->rect(), Qt::AlignCenter, empty_text_);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  QString empty_text_ = tr("No items");
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RoutesDialog::RoutesDialog(QWidget *parent) : QDialog(parent) {
							 | 
						||
| 
								 | 
							
								  setWindowTitle(tr("Remote routes"));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  QFormLayout *layout = new QFormLayout(this);
							 | 
						||
| 
								 | 
							
								  layout->addRow(tr("Device"), device_list_ = new QComboBox(this));
							 | 
						||
| 
								 | 
							
								  layout->addRow(tr("Duration"), period_selector_ = new QComboBox(this));
							 | 
						||
| 
								 | 
							
								  layout->addRow(route_list_ = new RouteListWidget(this));
							 | 
						||
| 
								 | 
							
								  auto button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
							 | 
						||
| 
								 | 
							
								  layout->addRow(button_box);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  device_list_->addItem(tr("Loading..."));
							 | 
						||
| 
								 | 
							
								  // Populate period selector with predefined durations
							 | 
						||
| 
								 | 
							
								  period_selector_->addItem(tr("Last week"), 7);
							 | 
						||
| 
								 | 
							
								  period_selector_->addItem(tr("Last 2 weeks"), 14);
							 | 
						||
| 
								 | 
							
								  period_selector_->addItem(tr("Last month"), 30);
							 | 
						||
| 
								 | 
							
								  period_selector_->addItem(tr("Last 6 months"), 180);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Connect signals and slots
							 | 
						||
| 
								 | 
							
								  connect(device_list_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &RoutesDialog::fetchRoutes);
							 | 
						||
| 
								 | 
							
								  connect(period_selector_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &RoutesDialog::fetchRoutes);
							 | 
						||
| 
								 | 
							
								  connect(route_list_, &QListWidget::itemDoubleClicked, this, &QDialog::accept);
							 | 
						||
| 
								 | 
							
								  QObject::connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
							 | 
						||
| 
								 | 
							
								  QObject::connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Send request to fetch devices
							 | 
						||
| 
								 | 
							
								  HttpRequest *http = new HttpRequest(this, !Hardware::PC());
							 | 
						||
| 
								 | 
							
								  QObject::connect(http, &HttpRequest::requestDone, this, &RoutesDialog::parseDeviceList);
							 | 
						||
| 
								 | 
							
								  http->sendRequest(CommaApi::BASE_URL + "/v1/me/devices/");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void RoutesDialog::parseDeviceList(const QString &json, bool success, QNetworkReply::NetworkError err) {
							 | 
						||
| 
								 | 
							
								  if (success) {
							 | 
						||
| 
								 | 
							
								    device_list_->clear();
							 | 
						||
| 
								 | 
							
								    auto devices = QJsonDocument::fromJson(json.toUtf8()).array();
							 | 
						||
| 
								 | 
							
								    for (const QJsonValue &device : devices) {
							 | 
						||
| 
								 | 
							
								      QString dongle_id = device["dongle_id"].toString();
							 | 
						||
| 
								 | 
							
								      device_list_->addItem(dongle_id, dongle_id);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    bool unauthorized = (err == QNetworkReply::ContentAccessDenied || err == QNetworkReply::AuthenticationRequiredError);
							 | 
						||
| 
								 | 
							
								    QMessageBox::warning(this, tr("Error"), unauthorized ? tr("Unauthorized, Authenticate with tools/lib/auth.py") : tr("Network error"));
							 | 
						||
| 
								 | 
							
								    reject();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  sender()->deleteLater();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void RoutesDialog::fetchRoutes() {
							 | 
						||
| 
								 | 
							
								  if (device_list_->currentIndex() == -1 || device_list_->currentData().isNull())
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  route_list_->clear();
							 | 
						||
| 
								 | 
							
								  route_list_->setEmptyText(tr("Loading..."));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  HttpRequest *http = new HttpRequest(this, !Hardware::PC());
							 | 
						||
| 
								 | 
							
								  QObject::connect(http, &HttpRequest::requestDone, this, &RoutesDialog::parseRouteList);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Construct URL with selected device and date range
							 | 
						||
| 
								 | 
							
								  auto dongle_id = device_list_->currentData().toString();
							 | 
						||
| 
								 | 
							
								  QDateTime current = QDateTime::currentDateTime();
							 | 
						||
| 
								 | 
							
								  QString url = QString("%1/v1/devices/%2/routes_segments?start=%3&end=%4")
							 | 
						||
| 
								 | 
							
								                    .arg(CommaApi::BASE_URL).arg(dongle_id)
							 | 
						||
| 
								 | 
							
								                    .arg(current.addDays(-(period_selector_->currentData().toInt())).toMSecsSinceEpoch())
							 | 
						||
| 
								 | 
							
								                    .arg(current.toMSecsSinceEpoch());
							 | 
						||
| 
								 | 
							
								  http->sendRequest(url);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void RoutesDialog::parseRouteList(const QString &json, bool success, QNetworkReply::NetworkError err) {
							 | 
						||
| 
								 | 
							
								  if (success) {
							 | 
						||
| 
								 | 
							
								    for (const QJsonValue &route : QJsonDocument::fromJson(json.toUtf8()).array()) {
							 | 
						||
| 
								 | 
							
								      uint64_t start_time = route["start_time_utc_millis"].toDouble();
							 | 
						||
| 
								 | 
							
								      uint64_t end_time = route["end_time_utc_millis"].toDouble();
							 | 
						||
| 
								 | 
							
								      auto datetime = QDateTime::fromMSecsSinceEpoch(start_time);
							 | 
						||
| 
								 | 
							
								      auto item = new QListWidgetItem(QString("%1    %2min").arg(datetime.toString()).arg((end_time - start_time) / (1000 * 60)));
							 | 
						||
| 
								 | 
							
								      item->setData(Qt::UserRole, route["fullname"].toString());
							 | 
						||
| 
								 | 
							
								      route_list_->addItem(item);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Select first route if available
							 | 
						||
| 
								 | 
							
								    if (route_list_->count() > 0) route_list_->setCurrentRow(0);
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    QMessageBox::warning(this, tr("Error"), tr("Failed to fetch routes. Check your network connection."));
							 | 
						||
| 
								 | 
							
								    reject();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  route_list_->setEmptyText(tr("No items"));
							 | 
						||
| 
								 | 
							
								  sender()->deleteLater();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void RoutesDialog::accept() {
							 | 
						||
| 
								 | 
							
								  if (auto current_item = route_list_->currentItem()) {
							 | 
						||
| 
								 | 
							
								    route_ = current_item->data(Qt::UserRole).toString();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  QDialog::accept();
							 | 
						||
| 
								 | 
							
								}
							 |