KNEO-Academy/src/views/components/device_popup.py

314 lines
13 KiB
Python

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QListWidget, QListWidgetItem, QFrame, QGridLayout, QSizePolicy
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtCore import Qt, QSize, QMargins
from PyQt5.QtGui import QPixmap, QIcon, QColor
import os
from src.config import SECONDARY_COLOR, BUTTON_STYLE, UXUI_ASSETS, DongleIconMap
def create_device_popup(parent, device_controller):
"""Create a popup window for device connection management"""
try:
# Device connection popup window
popup = QWidget(parent)
popup_width = int(parent.width() * 0.67)
popup_height = int(parent.height() * 0.67)
popup.setFixedSize(popup_width, popup_height)
popup.setStyleSheet(f"""
QWidget {{
background-color: {SECONDARY_COLOR};
border-radius: 20px;
padding: 20px;
}}
QLabel {{
color: white;
}}
QListWidget {{
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 5px;
color: white;
}}
QListWidget::item {{
border-radius: 5px;
background-color: rgba(255, 255, 255, 0.1);
margin-bottom: 5px;
}}
QListWidget::item:selected {{
background-color: rgba(52, 152, 219, 0.5);
}}
QFrame.device-info {{
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 10px;
margin-top: 15px;
}}
""")
popup_layout = QVBoxLayout(popup)
popup_layout.setContentsMargins(20, 20, 20, 20)
popup_layout.setSpacing(15)
# Title row
title_layout = QHBoxLayout()
title_layout.setAlignment(Qt.AlignCenter)
title_container = QWidget()
container_layout = QHBoxLayout(title_container)
container_layout.setSpacing(10)
device_icon = QSvgWidget(os.path.join(UXUI_ASSETS, "Assets_svg/ic_window_device.svg"))
device_icon.setFixedSize(35, 35)
container_layout.addWidget(device_icon)
popup_label = QLabel("Device Connection")
popup_label.setStyleSheet("color: white; font-size: 32px; font-weight: bold;")
container_layout.addWidget(popup_label)
container_layout.setAlignment(Qt.AlignCenter)
title_layout.addWidget(title_container)
popup_layout.addLayout(title_layout)
# Device list section - 設置為可捲動
list_section = QFrame(popup)
list_section.setStyleSheet("border: none; background: transparent;")
list_layout = QVBoxLayout(list_section)
list_layout.setContentsMargins(0, 0, 0, 0)
# Device list - 設置為可捲動的列表
device_list_widget_popup = QListWidget(popup)
device_list_widget_popup.setMinimumHeight(250) # 增加整個列表的高度
# 啟用垂直捲動條
device_list_widget_popup.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# 設置列表項高度和圖示大小
device_list_widget_popup.setIconSize(QSize(15, 15)) # 增大圖示
list_layout.addWidget(device_list_widget_popup)
# Store reference to this list widget for later use
parent.device_list_widget_popup = device_list_widget_popup
# Comment out the device details section
"""
# Device details section (initially hidden)
device_details = QFrame(popup)
device_details.setObjectName("device-details")
device_details.setProperty("class", "device-info")
device_details.setVisible(False) # Initially hidden
details_layout = QGridLayout(device_details)
details_layout.setColumnStretch(1, 1)
# 增加行間距
details_layout.setVerticalSpacing(2)
# Device Type
device_type_label_title = QLabel("Device Type:")
device_type_label_title.setStyleSheet("font-size: 14px;")
details_layout.addWidget(device_type_label_title, 0, 0)
device_type_label = QLabel("-")
device_type_label.setObjectName("device-type")
device_type_label.setStyleSheet("font-size: 14px;")
details_layout.addWidget(device_type_label, 0, 1)
# Port ID
port_id_label_title = QLabel("Port ID:")
port_id_label_title.setStyleSheet("font-size: 14px;")
details_layout.addWidget(port_id_label_title, 1, 0)
port_id_label = QLabel("-")
port_id_label.setObjectName("port-id")
port_id_label.setStyleSheet("font-size: 14px;")
details_layout.addWidget(port_id_label, 1, 1)
# KN Number
kn_number_label_title = QLabel("KN Number:")
kn_number_label_title.setStyleSheet("font-size: 14px;")
details_layout.addWidget(kn_number_label_title, 2, 0)
kn_number_label = QLabel("-")
kn_number_label.setObjectName("kn-number")
kn_number_label.setStyleSheet("font-size: 14px;")
details_layout.addWidget(kn_number_label, 2, 1)
# Status
status_label_title = QLabel("Status:")
status_label_title.setStyleSheet("font-size: 14px;")
details_layout.addWidget(status_label_title, 3, 0)
status_label = QLabel("-")
status_label.setObjectName("status")
status_label.setStyleSheet("font-size: 14px;")
details_layout.addWidget(status_label, 3, 1)
# Store references to labels
parent.device_detail_labels = {
"device-type": device_type_label,
"port-id": port_id_label,
"kn-number": kn_number_label,
"status": status_label,
"frame": device_details
}
# Connect item selection to show details
device_list_widget_popup.itemClicked.connect(lambda item: show_device_details(parent, item))
list_layout.addWidget(device_details)
"""
popup_layout.addWidget(list_section)
# Button area
button_layout = QHBoxLayout()
button_layout.setAlignment(Qt.AlignCenter)
refresh_button = QPushButton("Refresh")
refresh_button.clicked.connect(lambda: refresh_devices(parent, device_controller))
refresh_button.setFixedSize(150, 45)
refresh_button.setStyleSheet(BUTTON_STYLE)
button_layout.addWidget(refresh_button)
done_button = QPushButton("Done")
done_button.setStyleSheet(BUTTON_STYLE)
done_button.setFixedSize(150, 45)
done_button.clicked.connect(parent.hide_device_popup)
button_layout.addWidget(done_button)
button_layout.setSpacing(20)
# 減少底部間距,讓按鈕更靠近底部
popup_layout.addSpacing(5)
popup_layout.addLayout(button_layout)
return popup
except Exception as e:
print(f"Error in create_device_popup: {e}")
return QWidget(parent)
# Also need to comment out the show_device_details function since it's no longer used
# def show_device_details(parent, item):
# """Show details for the selected device"""
# try:
# # Get the device data from the item
# device_data = item.data(Qt.UserRole)
# print("device_data", device_data)
# if not device_data:
# return
# # Update the detail labels
# labels = parent.device_detail_labels
# # Set values
# labels["device-type"].setText(device_data.get("dongle", "-"))
# labels["port-id"].setText(str(device_data.get("usb_port_id", "-")))
# labels["kn-number"].setText(str(device_data.get("kn_number", "-")))
# labels["status"].setText("Connected" if device_data.get("is_connectable", True) else "Not Available")
# # Show the details frame
# labels["frame"].setVisible(True)
# except Exception as e:
# print(f"Error showing device details: {e}")
def refresh_devices(parent, device_controller):
"""Refresh the device list and update the UI"""
try:
# Call the refresh method from device controller
device_controller.refresh_devices()
# Clear the list
parent.device_list_widget_popup.clear()
# Comment out the details frame visibility setting
"""
# Hide details frame
if hasattr(parent, "device_detail_labels") and "frame" in parent.device_detail_labels:
parent.device_detail_labels["frame"].setVisible(False)
"""
# Track unique device models to avoid duplicates
seen_models = set()
# Add devices to the list
for device in device_controller.connected_devices:
try:
item = QListWidgetItem()
# Store the device data
item.setData(Qt.UserRole, device)
# 使用自定義 widget 來顯示設備信息
widget = QWidget()
widget.setFixedHeight(60) # 固定高度
# 使用水平佈局
main_layout = QHBoxLayout(widget)
# 減少內邊距保持足夠空間
main_layout.setContentsMargins(8, 4, 8, 4)
main_layout.setSpacing(5)
# 左側圖示容器(帶有背景色)
icon_container = QFrame()
icon_container.setFixedSize(30, 30)
icon_container.setStyleSheet("background-color: #182D4B; border-radius: 5px;")
icon_layout = QVBoxLayout(icon_container)
icon_layout.setContentsMargins(0, 0, 0, 0)
icon_layout.setAlignment(Qt.AlignCenter)
# 獲取設備圖示
product_id = hex(device.get("product_id", 0)).strip().lower()
icon_path = os.path.join(UXUI_ASSETS, "Assets_png", DongleIconMap.get(product_id, "unknown_dongle.png"))
if os.path.exists(icon_path):
icon_label = QLabel()
pixmap = QPixmap(icon_path)
# 確保圖標大小適中
scaled_pixmap = pixmap.scaled(30, 30, Qt.KeepAspectRatio, Qt.SmoothTransformation)
icon_label.setPixmap(scaled_pixmap)
icon_layout.addWidget(icon_label)
main_layout.addWidget(icon_container)
# 右側信息區域
info_container = QWidget()
info_layout = QVBoxLayout(info_container)
info_layout.setContentsMargins(0, 0, 0, 0)
# info_layout.setSpacing(2)
# 設備名稱和型號
dongle_name = device.get("dongle", "Unknown Device")
kn_number = device.get("kn_number", "Unknown")
status = "Connected" if device.get("is_connectable", True) else "Not Available"
# 只顯示型號名稱,避免重複
device_model_key = f"{dongle_name}_{product_id}"
if device_model_key in seen_models:
# 只顯示狀態
device_label_text = ""
else:
seen_models.add(device_model_key)
device_label_text = f"{dongle_name}"
device_label = QLabel(device_label_text)
device_label.setStyleSheet("color: white; font-weight: bold; font-size: 16px;")
info_layout.addWidget(device_label)
# KN 號碼
kn_label = QLabel(f"KN: {kn_number}")
kn_label.setStyleSheet("color: white; font-size: 14px;")
info_layout.addWidget(kn_label)
# 將信息容器添加到主佈局
main_layout.addWidget(info_container, 1) # 設置伸展因子為1
# 狀態標籤(右側)
status_label = QLabel(status)
status_label.setStyleSheet("color: white; font-size: 12px;")
main_layout.addWidget(status_label, 0, Qt.AlignRight | Qt.AlignVCenter) # 右對齊
# 設置自定義 widget 為列表項的 widget
parent.device_list_widget_popup.addItem(item)
parent.device_list_widget_popup.setItemWidget(item, widget)
# 設置項目大小
item.setSizeHint(widget.sizeHint())
except Exception as e:
print(f"Error adding device to list: {e}")
except Exception as e:
print(f"Error refreshing devices: {e}")