Skip to content

Commit 28abf43

Browse files
committed
feat: add About tab with update checker and license info- Implement AboutTab in gui/about_tab.py displaying version, author, OS details, and license.- Add Check for Updates functionality querying GitHub Releases API.- Define application version constant in core/__init__.py.- Integrate About tab into the main window tab widget.- Add About option to the system tray context menu for quick access.
1 parent 05390cd commit 28abf43

File tree

7 files changed

+163
-0
lines changed

7 files changed

+163
-0
lines changed

core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
VERSION = "1.0.0"
-10 Bytes
Binary file not shown.
9.94 KB
Binary file not shown.
992 Bytes
Binary file not shown.

gui/about_tab.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QLabel, QPushButton,
2+
QTextEdit, QHBoxLayout, QMessageBox, QFrame)
3+
from PyQt6.QtCore import Qt, QUrl, QThread, pyqtSignal
4+
from PyQt6.QtGui import QDesktopServices, QFont
5+
import platform
6+
import json
7+
import urllib.request
8+
import os
9+
import sys
10+
from core import VERSION
11+
12+
class UpdateChecker(QThread):
13+
finished = pyqtSignal(dict)
14+
def run(self):
15+
try:
16+
url = "https://api.github.com/repos/Deadpool2000/WASP/releases/latest"
17+
with urllib.request.urlopen(url, timeout=5) as response:
18+
if response.status == 200:
19+
data = json.loads(response.read().decode())
20+
self.finished.emit({"success": True, "data": data})
21+
else:
22+
self.finished.emit({"success": False, "error": f"Status code: {response.status}"})
23+
except Exception as e:
24+
self.finished.emit({"success": False, "error": str(e)})
25+
26+
class AboutTab(QWidget):
27+
def __init__(self):
28+
super().__init__()
29+
self.init_ui()
30+
31+
def init_ui(self):
32+
layout = QVBoxLayout(self)
33+
layout.setSpacing(15)
34+
layout.setContentsMargins(20, 20, 20, 20)
35+
header_layout = QVBoxLayout()
36+
title = QLabel("WASP")
37+
title.setFont(QFont("Segoe UI", 24, QFont.Weight.Bold))
38+
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
39+
title.setStyleSheet("color: #3daee9;")
40+
header_layout.addWidget(title)
41+
subtitle = QLabel("Workplace Activity Simulation Program")
42+
subtitle.setFont(QFont("Segoe UI", 11))
43+
subtitle.setAlignment(Qt.AlignmentFlag.AlignCenter)
44+
subtitle.setStyleSheet("color: #aaaaaa; font-style: italic;")
45+
header_layout.addWidget(subtitle)
46+
layout.addLayout(header_layout)
47+
48+
info_frame = QFrame()
49+
info_frame.setStyleSheet("""
50+
QFrame {
51+
background-color: #1e1e1e;
52+
border-radius: 8px;
53+
border: 1px solid #3a3a3a;
54+
}
55+
QLabel {
56+
padding: 5px;
57+
}
58+
""")
59+
info_layout = QVBoxLayout(info_frame)
60+
61+
def add_info_row(label_text, value_text, is_link=False):
62+
row = QHBoxLayout()
63+
label = QLabel(label_text)
64+
label.setStyleSheet("color: #888888; font-weight: bold;")
65+
66+
if is_link:
67+
value = QLabel(f'<a href="{value_text}" style="color: #3daee9; text-decoration: none;">{value_text}</a>')
68+
value.setOpenExternalLinks(True)
69+
else:
70+
value = QLabel(value_text)
71+
value.setStyleSheet("color: #ffffff;")
72+
73+
value.setAlignment(Qt.AlignmentFlag.AlignRight)
74+
75+
row.addWidget(label)
76+
row.addWidget(value)
77+
info_layout.addLayout(row)
78+
add_info_row("Version:", f"v{VERSION}")
79+
add_info_row("Author:", "Deadpool2000")
80+
add_info_row("OS:", f"{platform.system()} {platform.release()}")
81+
add_info_row("GitHub:", "https://github.com/Deadpool2000/WASP", is_link=True)
82+
layout.addWidget(info_frame)
83+
84+
self.check_btn = QPushButton("Check for Updates")
85+
self.check_btn.setCursor(Qt.CursorShape.PointingHandCursor)
86+
self.check_btn.clicked.connect(self.check_updates)
87+
layout.addWidget(self.check_btn)
88+
89+
license_label = QLabel("License")
90+
license_label.setFont(QFont("Segoe UI", 10, QFont.Weight.Bold))
91+
layout.addWidget(license_label)
92+
93+
self.license_text = QTextEdit()
94+
self.license_text.setReadOnly(True)
95+
self.license_text.setStyleSheet("""
96+
QTextEdit {
97+
background-color: #1e1e1e;
98+
border: 1px solid #3a3a3a;
99+
border-radius: 4px;
100+
font-family: 'Consolas', monospace;
101+
font-size: 8pt;
102+
color: #cccccc;
103+
}
104+
""")
105+
try:
106+
license_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "LICENSE")
107+
if os.path.exists(license_path):
108+
with open(license_path, "r", encoding="utf-8") as f:
109+
self.license_text.setText(f.read())
110+
else:
111+
self.license_text.setText("License file not found.")
112+
except Exception as e:
113+
self.license_text.setText(f"Error loading license: {str(e)}")
114+
115+
layout.addWidget(self.license_text)
116+
117+
def check_updates(self):
118+
self.check_btn.setText("Checking...")
119+
self.check_btn.setEnabled(False)
120+
self.checker = UpdateChecker()
121+
self.checker.finished.connect(self.on_check_finished)
122+
self.checker.start()
123+
124+
def on_check_finished(self, result):
125+
self.check_btn.setEnabled(True)
126+
self.check_btn.setText("Check for Updates")
127+
128+
if result["success"]:
129+
data = result["data"]
130+
latest_tag = data.get("tag_name", "").lstrip('v')
131+
current_version = VERSION.lstrip('v')
132+
if latest_tag and latest_tag != current_version:
133+
reply = QMessageBox.question(
134+
self,
135+
"Update Available",
136+
f"A new version ({latest_tag}) is available.\n\nDo you want to visit the download page?",
137+
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
138+
)
139+
if reply == QMessageBox.StandardButton.Yes:
140+
QDesktopServices.openUrl(QUrl(data.get("html_url", "")))
141+
else:
142+
QMessageBox.information(self, "Up to Date", f"You are running the latest version (v{VERSION}).")
143+
else:
144+
QMessageBox.warning(self, "Check Failed", f"Could not check for updates.\nError: {result.get('error')}")

gui/main_window.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from core.scheduler import Scheduler
1111
from core.hotkey_listener import HotkeyListener
1212
from core.window_switcher import WindowSwitcher
13+
from gui.about_tab import AboutTab
1314

1415
class MainWindow(QMainWindow):
1516
"""Main application window with compact layout"""
@@ -65,6 +66,7 @@ def init_ui(self):
6566
self.create_scheduler_tab()
6667
self.create_window_switcher_tab()
6768
self.create_status_tab()
69+
self.create_about_tab()
6870

6971
main_layout.addWidget(self.tab_widget)
7072

@@ -132,6 +134,12 @@ def setup_tray(self):
132134

133135
tray_menu.addSeparator()
134136

137+
about_action = QAction("About", self)
138+
about_action.triggered.connect(self.show_about)
139+
tray_menu.addAction(about_action)
140+
141+
tray_menu.addSeparator()
142+
135143
exit_action = QAction("Exit", self)
136144
exit_action.triggered.connect(self.clean_exit)
137145
tray_menu.addAction(exit_action)
@@ -167,6 +175,11 @@ def clean_exit(self):
167175
"""Clean exit through tray"""
168176
self.close()
169177

178+
def show_about(self):
179+
"""Show about tab"""
180+
self.show_normal()
181+
self.tab_widget.setCurrentWidget(self.about_tab)
182+
170183
def create_header(self, layout):
171184
"""Create header section"""
172185
header_frame = QFrame()
@@ -530,6 +543,11 @@ def create_status_tab(self):
530543

531544
self.tab_widget.addTab(status_tab, "📊 Status")
532545

546+
def create_about_tab(self):
547+
"""Create about tab"""
548+
self.about_tab = AboutTab()
549+
self.tab_widget.addTab(self.about_tab, "ℹ️ About")
550+
533551
def create_footer(self, layout):
534552
"""Create footer with click counter"""
535553
footer_frame = QFrame()

output/main.exe

46.6 MB
Binary file not shown.

0 commit comments

Comments
 (0)