Files
Projects/toolbox/codes/ui/main_ui.py
2025-09-28 18:21:48 +08:00

254 lines
9.6 KiB
Python

from pathlib import Path
from random import choice
from shutil import copy
import requests
import json
import sys
from PySide6.QtWidgets import QApplication, QWidget, QHBoxLayout, QMessageBox, QMainWindow, QStatusBar
from PySide6.QtGui import QFont, QIcon, QResizeEvent, QShortcut, QKeySequence, QAction
from PySide6.QtCore import Qt
from codes.common import clibs, db_operation
from codes.ui.components.toolbar_ui import SToolBar
from codes.ui.components.list_widget_ui import SListWidget
from codes.ui.components.stacked_widget_ui import SStackedWidget
from codes.common.signal_bus import signal_bus
from codes.common.worker import Worker
from codes.common.exception_handler import handle_exception
from codes.ui.overlay_page.overlay_ui import WidgetWithBg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.predos()
self.init_ui()
self.setup_slot()
self.setup_sc()
def predos(self):
self.m = Path(__file__).stem
self.home_overlay = None
db_operation.db_backup()
db_operation.db_conn()
def init_ui(self):
self.setMinimumSize(clibs.win_width, clibs.win_height)
self.resize(clibs.win_width, clibs.win_height)
self.setWindowTitle("Toolbox")
self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
self.setFont(QFont("Consolas", 14))
# 任务栏/主窗口/状态栏
self.toolBar = SToolBar()
self.addToolBar(self.toolBar)
self.toolBar.setMovable(False)
self.centralW = QWidget()
self.setCentralWidget(self.centralW)
self.statusBar = QStatusBar()
self.statusBar.setStyleSheet("""
QStatusBar {
background: #8B8989; /* 背景色 */
color: #000000; /* 文字色 */
border: none;
font: 14px "Consolas";
}
""")
self.setStatusBar(self.statusBar)
layout_h = QHBoxLayout()
# list widget
self.listW = SListWidget()
layout_h.addWidget(self.listW, stretch=1)
self.stackedW =SStackedWidget()
layout_h.addWidget(self.stackedW, stretch=5)
self.centralW.setLayout(layout_h)
def setup_slot(self):
signal_bus.home_overlay_trigger.connect(self.ac_hp)
signal_bus.home_overlay_close.connect(self.exit_overlay)
self.install_sc()
def setup_sc(self, enable: bool = True):
for sc_id, obj in self.sc_pool.items():
if isinstance(obj, QAction):
obj.setEnabled(enable)
elif isinstance(obj, QShortcut):
obj.setEnabled(enable)
if enable == False and (sc_id == "esc" or sc_id == "ctrl_alt_m") and self.home_overlay:
obj.setEnabled(True)
if (sc_id == "esc" or sc_id == "ctrl_alt_m") and self.home_overlay is None:
obj.setEnabled(False)
def install_sc(self):
self.sc_pool = {}
# QAction
self.toolBar.ac_switch.setShortcut(QKeySequence("Ctrl+Alt+T"))
self.sc_pool["ctrl_alt_t"] = self.toolBar.ac_switch
self.toolBar.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
self.sc_pool["ctrl_alt_h"] = self.toolBar.ac_homepage
self.toolBar.ac_setting.setShortcut(QKeySequence("Ctrl+Alt+S"))
self.sc_pool["ctrl_alt_s"] = self.toolBar.ac_setting
self.toolBar.ac_log.setShortcut(QKeySequence("Ctrl+Alt+L"))
self.sc_pool["ctrl_alt_l"] = self.toolBar.ac_log
self.toolBar.ac_about.setShortcut(QKeySequence("Ctrl+Alt+A"))
self.sc_pool["ctrl_alt_a"] = self.toolBar.ac_about
# QShortcut
self.sc_f11 = QShortcut(QKeySequence("F11"), self)
self.sc_f11.activated.connect(self.shortcut_f11)
self.sc_pool["f11"] = self.sc_f11
# Subpage
self.sc_Esc = QShortcut(QKeySequence("Esc"), self)
self.sc_Esc.activated.connect(signal_bus.home_overlay_auth.emit)
self.sc_pool["esc"] = self.sc_Esc
self.sc_caM = QShortcut(QKeySequence("Ctrl+Alt+M"), self)
self.sc_caM.activated.connect(self.toggle_full_screen)
self.sc_pool["ctrl_alt_m"] = self.sc_caM
def ac_hp(self):
def get_files(dir_path):
folder = Path(dir_path)
files = [p for p in folder.rglob("*") if p.is_file()]
if files:
rand_choice = choice(files)
else:
rand_choice = ""
return rand_choice, files
def del_repeat_proverb(proverbs: list):
_proverbs = []
for proverb in proverbs:
if proverb not in _proverbs:
_proverbs.append(proverb)
return _proverbs
@handle_exception()
def get_resources():
# background image
bing = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8"
req = requests.get(bing)
res = req.json()
_, files = get_files(f"{clibs.base_path}/assets/media/bg")
image_names = []
for file in files:
image_names.append(file.name.removesuffix(".jpg"))
for image in res["images"]:
image_name = "-".join([image["startdate"], image["title"]])
if image_name in image_names:
continue
else:
image_url = f"""https://www.bing.com{image["url"]}"""
file = Path(f"{clibs.base_path}/assets/media/bg/{image_name}.jpg")
try:
req = requests.get(image_url, stream=True, timeout=10)
with open(file, "wb") as f:
for chunk in req.iter_content(chunk_size=8192):
f.write(chunk)
except Exception as e:
pass
# proverbs
hitokoto = "https://v1.hitokoto.cn/"
proverbs = []
proverb_file = Path(f"{clibs.base_path}/assets/media/hitokoto.json")
req = requests.get(hitokoto)
if not proverb_file.exists():
proverb_file.touch()
proverb_file.write_text("[]")
with open(proverb_file, "w") as f:
f.write("[]")
with open(proverb_file, mode="rt", encoding="utf-8") as f:
proverbs = json.load(f)
proverbs.append(eval(req.text))
proverbs = del_repeat_proverb(proverbs)
with open(proverb_file, mode="wt", encoding="utf-8") as f:
json.dump(proverbs, f, ensure_ascii=False)
@handle_exception()
def change_resources():
# avatar
src, _ = get_files(f"{clibs.base_path}/assets/media/avatar")
dst = f"{clibs.base_path}/assets/media/avatar.jpg"
copy(src, dst)
# proverbs
with open(f"{clibs.base_path}/assets/media/hitokoto.json", mode="r", encoding="utf-8") as f:
proverbs = json.load(f)
res = choice(proverbs)
sentence = res["hitokoto"]
from_where = res["from"]
from_who = res["from_who"]
clibs.proverb = f"{sentence}\t\t※⌈{from_where}⌋ | {from_who}"
# bg
src, _ = get_files(f"{clibs.base_path}/assets/media/bg")
dst = f"{clibs.base_path}/assets/media/bg.jpg"
copy(src, dst)
def gen_page():
self.home_overlay = WidgetWithBg(parent=self)
self.home_overlay.show()
self.setup_sc(False)
width, height = self.width(), self.height()
if width > clibs.win_width:
self.resize(self.width()-1, self.height()-1)
else:
self.resize(clibs.win_width+1, clibs.win_height+1)
change_resources()
self.launch_get_resources(get_resources)
gen_page()
def launch_get_resources(self, func, on_anything=None, *args, **kwargs):
self.td_get_resources = Worker(func, *args, **kwargs)
self.td_get_resources.started.connect(lambda: None)
self.td_get_resources.result.connect(lambda: None)
self.td_get_resources.error.connect(lambda: None)
self.td_get_resources.finished.connect(lambda: None)
self.td_get_resources.start()
def toggle_full_screen(self):
if self.isFullScreen():
self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
self.show()
self.showMaximized()
else:
self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
self.showFullScreen()
def exit_overlay(self):
self.home_overlay = None
self.setup_sc()
if self.isFullScreen():
self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
self.show()
self.showMaximized()
def shortcut_f11(self):
if not self.home_overlay:
self.ac_hp()
self.toggle_full_screen()
def resizeEvent(self, event: QResizeEvent):
super().resizeEvent(event)
if self.home_overlay:
self.home_overlay.setGeometry(self.rect())
def closeEvent(self, event):
if self.isFullScreen():
event.ignore()
return
reply = QMessageBox.question(self, "退出", "\n程序可能在运行,确定要退出吗?")
if reply == QMessageBox.StandardButton.Yes:
db_operation.db_close()
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())