258 lines
9.8 KiB
Python
258 lines
9.8 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 QIcon, QResizeEvent, QShortcut, QKeySequence, QAction
|
|
from PySide6.QtCore import Qt, QFileSystemWatcher
|
|
|
|
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.ui.components.statusbar_ui import SStatusBar
|
|
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.pre_do()
|
|
self.init_ui()
|
|
self.post_do()
|
|
|
|
def pre_do(self):
|
|
self.m = Path(__file__).stem
|
|
self.home_overlay = None
|
|
db_operation.db_backup()
|
|
db_operation.db_conn()
|
|
|
|
def init_ui(self):
|
|
self.setObjectName("MainWindow")
|
|
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.toolBar = SToolBar()
|
|
self.addToolBar(self.toolBar)
|
|
self.toolBar.setMovable(False)
|
|
self.centralW = QWidget()
|
|
self.setCentralWidget(self.centralW)
|
|
self.statusBar = SStatusBar()
|
|
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 post_do(self):
|
|
self.setup_slot()
|
|
self.setup_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["hsh"]])
|
|
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")
|
|
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)
|
|
# 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)
|
|
proverb = json.loads(req.text)
|
|
if None in proverb.values():
|
|
for k, v in proverb.items():
|
|
if v is None:
|
|
if v == "from_who":
|
|
proverb.update({k: "佚名"})
|
|
elif v == "from":
|
|
proverb.update({k: "不知道"})
|
|
else:
|
|
proverb.update({k: "-"})
|
|
|
|
proverbs.append(proverb)
|
|
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())
|