263 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			10 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")
 | 
						|
                    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)
 | 
						|
            print(f"req.text = {req.text}")
 | 
						|
            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())
 |