vdi-cloud/terminal/kiosk-shell/src/desktop_list_page.cpp

197 lines
6.7 KiB
C++
Raw Normal View History

#include "desktop_list_page.h"
#include <QFont>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QScrollArea>
#include <QVBoxLayout>
namespace vdi {
namespace {
// 在信息行里加一个拉伸占位(独立函数避免在类外重复声明)
void addStretchToRow(QHBoxLayout* row) {
row->addStretch(1);
}
} // namespace
DesktopListPage::DesktopListPage(QWidget* parent) : QWidget(parent) {
auto* root = new QVBoxLayout(this);
root->setContentsMargins(80, 50, 80, 40);
root->setSpacing(16);
// ---- 标题区 ----
auto* title = new QLabel(QStringLiteral("选择云桌面"), this);
QFont titleFont = title->font();
titleFont.setPointSize(26);
titleFont.setBold(true);
title->setFont(titleFont);
title->setAlignment(Qt::AlignCenter);
root->addWidget(title);
auto* infoRow = new QHBoxLayout();
labelUser_ = new QLabel(this);
labelUser_->setStyleSheet(QStringLiteral("color: #8a94a6;"));
// 无登录页演示模式下不设"退出登录"(用户身份由设备/平台承担,
// 正式认证接入后由 DesktopService 驱动恢复登录流程)
infoRow->addWidget(labelUser_);
addStretchToRow(infoRow);
root->addLayout(infoRow);
// ---- 卡片区 ----
auto* scroll = new QScrollArea(this);
scroll->setWidgetResizable(true);
scroll->setFrameShape(QFrame::NoFrame);
scroll->setStyleSheet(QStringLiteral(
"QScrollArea { background: transparent; }"
"QWidget { background: transparent; }"));
auto* cardsHost = new QWidget(scroll);
cardsLayout_ = new QVBoxLayout(cardsHost);
cardsLayout_->setSpacing(14);
cardsLayout_->addStretch(1);
scroll->setWidget(cardsHost);
root->addWidget(scroll, 1);
// ---- 状态条 ----
labelStatus_ = new QLabel(this);
labelStatus_->setAlignment(Qt::AlignCenter);
labelStatus_->setStyleSheet(QStringLiteral("color: #8a94a6;"));
root->addWidget(labelStatus_);
}
void DesktopListPage::setDesktops(const std::vector<DesktopInfo>& desktops) {
desktops_ = desktops;
rebuildCards();
}
void DesktopListPage::rebuildCards() {
actionButtons_.clear();
// 清空旧卡片(最后一项是 stretch)
while (cardsLayout_->count() > 1) {
QLayoutItem* item = cardsLayout_->takeAt(0);
if (item->widget()) {
item->widget()->deleteLater();
}
delete item;
}
for (const DesktopInfo& d : desktops_) {
auto* card = new QFrame(this);
card->setMinimumHeight(96);
card->setStyleSheet(QStringLiteral(
"QFrame { background: #1a2233; border: 1px solid #2b3654; border-radius: 10px; }"
"QFrame:hover { border: 1px solid #2f6feb; }"
"QLabel { border: none; background: transparent; }"));
auto* row = new QHBoxLayout(card);
row->setContentsMargins(24, 16, 24, 16);
row->setSpacing(18);
auto* textCol = new QVBoxLayout();
textCol->setSpacing(4);
auto* name = new QLabel(d.name, card);
QFont nameFont = name->font();
nameFont.setPointSize(15);
nameFont.setBold(true);
name->setFont(nameFont);
auto* osLine = new QLabel(d.os, card);
osLine->setStyleSheet(QStringLiteral("color: #8a94a6;"));
textCol->addWidget(name);
textCol->addWidget(osLine);
row->addLayout(textCol, 1);
// 状态标签(会话通道统一 Moonlight,无需按桌面标注协议)
QString stateText;
QString stateColor;
switch (d.state) {
case DesktopState::kAvailable:
stateText = QStringLiteral("可连接");
stateColor = QStringLiteral("#3fb950");
break;
case DesktopState::kPending:
stateText = QStringLiteral("任务进行中");
stateColor = QStringLiteral("#d29922");
break;
case DesktopState::kUnassigned:
stateText = QStringLiteral("待分配");
stateColor = QStringLiteral("#8a94a6");
break;
}
auto* state = new QLabel(stateText, card);
state->setStyleSheet(QStringLiteral("color: %1; font-weight: bold;").arg(stateColor));
row->addWidget(state);
// “设置”:每张卡都可编辑连接参数(协议/地址/应用名/分辨率/帧率)
auto* editBtn = new QPushButton(QStringLiteral("设置"), card);
editBtn->setMinimumSize(88, 42);
editBtn->setEnabled(!busy_);
actionButtons_.push_back(editBtn);
connect(editBtn, &QPushButton::clicked, this, [this, id = d.id]() {
if (!busy_) {
emit editRequested(id);
}
});
row->addWidget(editBtn);
if (d.state == DesktopState::kAvailable) {
auto* connectBtn = new QPushButton(QStringLiteral("连接"), card);
connectBtn->setMinimumSize(110, 42);
connectBtn->setStyleSheet(QStringLiteral(
"QPushButton { background: #2f6feb; color: white; border: none; "
"border-radius: 6px; font-weight: bold; }"
"QPushButton:disabled { background: #3a4a63; }"));
connectBtn->setEnabled(!busy_);
actionButtons_.push_back(connectBtn);
connect(connectBtn, &QPushButton::clicked, this, [this, id = d.id]() {
if (!busy_) {
setBusy(true);
setStatus(QStringLiteral("正在连接,请稍候…"));
emit desktopSelected(id);
}
});
row->addWidget(connectBtn);
} else {
auto* btn = new QPushButton(QStringLiteral("连接"), card);
btn->setMinimumSize(110, 42);
btn->setEnabled(false);
row->addWidget(btn);
}
cardsLayout_->insertWidget(cardsLayout_->count() - 1, card);
}
}
void DesktopListPage::setStatus(const QString& text, bool error) {
labelStatus_->setText(text);
labelStatus_->setStyleSheet(
QStringLiteral("color: %1;").arg(error ? QStringLiteral("#e05561")
: QStringLiteral("#8a94a6")));
}
void DesktopListPage::setBusy(bool busy) {
busy_ = busy;
for (QPushButton* button : actionButtons_) {
if (button) {
button->setEnabled(!busy_);
}
}
}
QString DesktopListPage::currentUser() const {
return currentUser_;
}
void DesktopListPage::setCurrentUser(const QString& user) {
currentUser_ = user;
labelUser_->setText(user.isEmpty()
? QStringLiteral("当前用户:未登录")
: QStringLiteral("当前用户:%1").arg(user));
}
} // namespace vdi