diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29bf417 --- /dev/null +++ b/.gitignore @@ -0,0 +1,107 @@ +# download files +debug_utils +software + +################# python config ################## +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version +.idea/ +# celery beat schedule file +celerybeat-schedule +workspace.xml +# SageMath parsed files +*.sage.py +.idea/workspace.xml +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6646939 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python 调试", + "type": "debugpy", + "request": "launch", + "program": "main.py", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..242c7c8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.analysis.typeCheckingMode": "off", + "python.analysis.autoImportCompletions": true +} \ No newline at end of file diff --git a/lang/zh_cn.toml b/lang/zh_cn.toml new file mode 100644 index 0000000..aba61bd --- /dev/null +++ b/lang/zh_cn.toml @@ -0,0 +1,21 @@ +UnsupportedSystem = "当前操作系统不受支持" +PermissionDeniedLinux = "在 linux 操作系统系统下,请使用 root 权限进行安装" +PermissionDeniedWin = "权限不足,请以管理员身份运行此程序" +InstallWelcome = "欢迎安装 PEInjector" +InstallInfo = "PEinjector 是增强 WindowsPE 的一个工具和平台" +DownloadInstallTitle = "下载必要文件" +DownloadInstall = "在开始之前,我们需要下载一些依赖文件\n如果您的网络状况不佳,请手动下载 peinjector 和 ventoy 并解压到 software 文件夹" +StartInstall = "开始安装" +InstallVtoy = "安装 Ventoy" +InstallVtoyTitle = "安装 Ventoy" +InstallVtoyInfo = "请在打开的 ventoy 安装程序手动完成安装\n若安装完毕,请点击 “扫描” 按钮并选择您安装完毕的U盘\n若您找不到您的U盘,请尝试点击 “显示所有设备”\n如果你在使用 arm 架构的设备或软件无法打开,请手动运行以下程序:\n Windows: software\\ventoy\\altexe\\你的架构对应程序.exe\n Linux: software/ventoy/altexe/你的架构对应程序\n注:请确保磁盘已经挂载。本版本ventoy已精简,与原版兼容" +ScanVtoy = "扫描" +RestartVtoy = "重启安装程序" +ChooseVtoyDevice = "选择设备" +ShowAllDevices = "显示所有设备" +InstallIjTitle = "安装 PEinjector" +InstallIjInfo = "PEinjector主程序正在安装中,请稍等" +FinishInstall = "完成安装" +InstallFinishTitle = "安装已完成" +InstallFinishInfo = "PEinjector已经安装到您的设备\n点击下方按钮关闭程序并重新启动以管理 PEinjector" +InstallFinishBtn = "关闭" diff --git a/lib/downloader.py b/lib/downloader.py new file mode 100644 index 0000000..653607b --- /dev/null +++ b/lib/downloader.py @@ -0,0 +1,64 @@ +import time +import os +import shutil +import requests +import py7zr +from threading import Thread +from logger.logger import * + +CHUNKSIZE = 1024 + + +class Download_Theard(Thread): + def __init__(self, url, to, progress_callback, onfinish): + self.url = url + self.to = to + self.progress_callback = progress_callback + self.onfinish = onfinish + Thread.__init__(self, daemon=True) + + def run(self): + while 1: + try: + info("[downloader]download "+self.url) + self.progress_callback(0) + r = requests.get(self.url, stream=True) + if (r.status_code >= 300): + raise Exception + total = int(r.headers.get('content-length', 0)) + now_file = 0 + with open(self.to, 'wb') as fp: + for item in r.iter_content(CHUNKSIZE): + fp.write(item) + now_file += len(item) + self.progress_callback(now_file/total*0.9) + self.progress_callback(0.9) + info("[downloader]unzip "+self.url) + with py7zr.SevenZipFile(self.to, mode='r') as z: + z.extractall(path="software") + self.progress_callback(1) + self.onfinish() + return + except: + pass + + +def download_files(files, onfisish, anim_list): + threads = [] + finishnum = 0 + finishmax = len(files) + + def anim_check(*args): + onfisish() # run in main thread + return -1 + + def progfinish(): + nonlocal finishnum, finishmax + finishnum += 1 + if (finishnum == finishmax): + anim_list.anim.append(anim_check) + + for i in files: + threads.append(Download_Theard( + i["from"], i["to"], i["progbar"], progfinish)) + threads[-1].start() diff --git a/lib/get_disk.py b/lib/get_disk.py new file mode 100644 index 0000000..bc8dab0 --- /dev/null +++ b/lib/get_disk.py @@ -0,0 +1,112 @@ +import platform +import os +import subprocess +import sys + +from ui.lang import l +from logger.logger import * + +if platform.system() == 'Linux': + def find_hub_disk(): + info("[getdisk]get hub disk") + output = subprocess.check_output( + ['mount', '-v']).decode(sys.getdefaultencoding()) + for line in output.split('\n'): + if not line: + continue + mount_point_l = line.split(" ") + disk_id = mount_point_l[0] + mount_to = mount_point_l[2] + if len(disk_id) <= len("/dev/sd") or (disk_id[:len("/dev/sd")] != "/dev/sd" and (disk_id[:len("/dev/sd")] != "/dev/lo") and (disk_id[:len("/dev/sd")] != "/dev/nv")): + continue + if (mount_to == "/" or mount_to == "/boot"): + continue + if (os.path.exists(mount_to + "/PEinjector")): + return (0, mount_to, disk_id) + return (2, "") + + def find_vtoy_disk(): + vtoylist = [] + info("[getdisk]get vtoy disk") + output = subprocess.check_output( + ['mount', '-v']).decode(sys.getdefaultencoding()) + for line in output.split('\n'): + if not line: + continue + mount_point_l = line.split(" ") + disk_id = mount_point_l[0] + mount_to = mount_point_l[2] + if len(disk_id) <= len("/dev/sd") or (disk_id[:len("/dev/sd")] != "/dev/sd" and (disk_id[:len("/dev/sd")] != "/dev/lo") and (disk_id[:len("/dev/sd")] != "/dev/nv")): + continue + if (mount_to == "/" or mount_to == "/boot"): + continue + if os.path.exists(mount_to + "/ventoy"): + vtoylist.append((disk_id, mount_to)) + continue + output2 = subprocess.check_output( + ['blkid', '-o', 'value', '-s', 'LABEL', disk_id]).decode(sys.getdefaultencoding()) + output2 = output2.replace('\n', "") + if (output2 == ""): + continue + if (output2 == "Ventoy" or output2 == "ventoy"): + vtoylist.append((disk_id, mount_to)) + return vtoylist + + def find_all_disk(): + vtoylist = [] + info("[getdisk]get all disk") + output = subprocess.check_output( + ['mount', '-v']).decode(sys.getdefaultencoding()) + for line in output.split('\n'): + if not line: + continue + mount_point_l = line.split(" ") + disk_id = mount_point_l[0] + mount_to = mount_point_l[2] + if len(disk_id) <= len("/dev/sd") or (disk_id[:len("/dev/sd")] != "/dev/sd" and (disk_id[:len("/dev/sd")] != "/dev/lo") and (disk_id[:len("/dev/sd")] != "/dev/nv")): + continue + if (mount_to == "/" or mount_to == "/boot"): + continue + vtoylist.append((disk_id, mount_to)) + return vtoylist +elif platform.system() == 'Windows': + def find_hub_disk(): + info("[getdisk]get hub disk") + for i in "CDEFGHIJKABLMNOPQRSTUVWYZ": + this_disk = i+":" + if os.path.exists(this_disk + "/PEinjector"): + return (0, this_disk, this_disk) + return (2, "") + + def find_vtoy_disk(): + vtoylist = [] + info("[getdisk]get vtoy disk") + for i in "CDEFGHIJKABLMNOPQRSTUVWYZ": + this_disk = i+":" + if not os.path.exists(this_disk): + continue + if os.path.exists(this_disk + "/ventoy"): + vtoylist.append((this_disk, this_disk)) + with os.popen("wmic logicaldisk" + + f" where name=\"{this_disk}\" get volumename", 'r', 1) as file: + output2 = file.read() + output2 = (output2.replace("\n", "") + .replace("VolumeName", "") + .lstrip() + .rstrip()) + if (output2 == "Ventoy"): + vtoylist.append((this_disk, this_disk)) + return vtoylist + + def find_all_disk(): + vtoylist = [] + info("[getdisk]get all disk") + for i in "CDEFGHIJKABLMNOPQRSTUVWYZ": + this_disk = i+":" + if (os.path.exists(this_disk)): + vtoylist.append((this_disk, this_disk)) + return vtoylist +else: + def find_hub_disk(): + info("[getdisk]get hub disk") + return (1, l("UnsupportedSystem")) diff --git a/lib/install_pkg.py b/lib/install_pkg.py new file mode 100644 index 0000000..c785497 --- /dev/null +++ b/lib/install_pkg.py @@ -0,0 +1,60 @@ +import time +import os +import shutil +from threading import Thread +from logger.logger import * + + +class PKG_Theard(Thread): + def __init__(self, disks, barcallback, donecallback): + self.disks = disks + self.barcallback = barcallback + self.donecallback = donecallback + Thread.__init__(self, daemon=True) + + def run(self): + DISK = self.disks + info(f"[install]install to {DISK}") + self.barcallback(0) + if not os.path.exists(DISK+"/PEinjector"): + os.mkdir(DISK+"/PEinjector") + time.sleep(0.1) + self.barcallback(0.1) + info("[install]install main file") + if os.path.exists(DISK+"/PEinjector/PEinjector.7z"): + os.remove(DISK+"/PEinjector/PEinjector.7z") + time.sleep(0.1) + self.barcallback(0.2) + shutil.copyfile("software/peinjector/dist/PEinjector.7z", + DISK+"/PEinjector/PEinjector.7z") + time.sleep(0.1) + self.barcallback(0.4) + time.sleep(0.1) + info("[install]write info") + if not os.path.exists(DISK+"/PEinjector/disable.txt"): + with open(DISK+"/PEinjector/disable.txt", "w") as file: + pass + self.barcallback(0.5) + time.sleep(0.1) + shutil.copyfile("software/peinjector/version", + DISK+"/PEinjector/VERSION") + if not os.path.exists(DISK+"/PEinjector/install"): + os.mkdir(DISK+"/PEinjector/install") + self.barcallback(0.6) + if not os.path.exists(DISK+"/PEinjector/package"): + os.mkdir(DISK+"/PEinjector/package") + ns = 0 + for i in os.listdir("software/peinjector/package"): + if os.path.exists(DISK+"/PEinjector/package/"+i): + shutil.rmtree(DISK+"/PEinjector/package/"+i) + shutil.copytree("software/peinjector/package/" + + i, DISK+"/PEinjector/package/"+i) + ns += 1 + info( + f"[install]install pkg {ns}/{len(os.listdir('software/peinjector/package'))}") + self.barcallback( + 0.6+ns/len(os.listdir("software/peinjector/package"))*0.4) + time.sleep(0.1) + info("[install]install finish") + self.barcallback(1) + self.donecallback() diff --git a/lib/open_ventoy.py b/lib/open_ventoy.py new file mode 100644 index 0000000..8af4db2 --- /dev/null +++ b/lib/open_ventoy.py @@ -0,0 +1,11 @@ +import os +import platform + + +def run(): + if (platform.system() == 'Linux'): + os.system("chmod +x ./software/ventoy/VentoyGUI.x86_64") + os.system( + "cd software/ventoy;./VentoyGUI.x86_64 2> ../../logger/vtoylog.log&") + if (platform.system() == 'Windows'): + os.system("cd software\\ventoy && start Ventoy2Disk.exe") diff --git a/logger/config.py b/logger/config.py new file mode 100644 index 0000000..b3f19c3 --- /dev/null +++ b/logger/config.py @@ -0,0 +1,3 @@ +LOGPATH = "logger/log.log" +LOGLEVEL = "debug" +OUTPUT_COLORFUL = True diff --git a/logger/logger.py b/logger/logger.py new file mode 100644 index 0000000..6ed14ba --- /dev/null +++ b/logger/logger.py @@ -0,0 +1,55 @@ +# ------ cxykevin log moudle ------ +# This moudle is not a part of this project. +# This file is CopyNone. + + +import logging +from logger import config +import sys +levels = { + "debug": logging.DEBUG, + 'info': logging.INFO, + 'warning': logging.WARN, + 'err': logging.ERROR +} + + +def init() -> None: + logging.basicConfig(filename=config.LOGPATH, + format='[%(asctime)s][%(levelname)s] %(message)s', + level=levels[config.LOGLEVEL]) + + +def info(msg: str) -> None: + if (20 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[34mINFO\033[0m]" if config.OUTPUT_COLORFUL else "[INFO]") + msg + "\n") + logging.info(msg) + + +def warn(msg: str) -> None: + if (30 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[33mWARNING\033[0m]" if config.OUTPUT_COLORFUL else "[WARNING]") + msg + "\n") + logging.warn(msg) + + +def err(msg: str) -> None: + if (40 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[31mERROR\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + "\n") + logging.error(msg) + + +def break_err(msg: str) -> None: + if (40 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[31mERROR\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + "\n") + logging.error(msg) + + +def print(*args, end="\n") -> None: + msg = ' '.join(map(str, args)) + if (10 >= levels[config.LOGLEVEL]): + sys.stdout.write(msg + end) + logging.debug(msg) diff --git a/main.py b/main.py new file mode 100644 index 0000000..99a10d6 --- /dev/null +++ b/main.py @@ -0,0 +1,3 @@ +from ui import win +if __name__ == "__main__": + win.main() diff --git a/res/icon.pack b/res/icon.pack new file mode 100644 index 0000000..bd01ce1 Binary files /dev/null and b/res/icon.pack differ diff --git a/res/installer_file.json b/res/installer_file.json new file mode 100644 index 0000000..80ed0a5 --- /dev/null +++ b/res/installer_file.json @@ -0,0 +1,10 @@ +[ + { + "name": "peinjector", + "source": "http://git.hmtsai.cn/cxykevin/PEinjector_Hub_Files/raw/branch/master/peinjector.7z" + }, + { + "name": "ventoy", + "source": "http://git.hmtsai.cn/cxykevin/PEinjector_Hub_Files/raw/branch/master/ventoy.7z" + } +] \ No newline at end of file diff --git a/ui/installer.py b/ui/installer.py new file mode 100644 index 0000000..ff378dd --- /dev/null +++ b/ui/installer.py @@ -0,0 +1,299 @@ +import json +import os +from turtle import bgcolor +from magictk import mtk, color_tmpl +from magictk import fontconfig +from ui.lang import l +from lib import open_ventoy +from lib import get_disk +from lib import install_pkg +from lib import downloader +from logger.logger import * + +now_frame = None +master: mtk.Frame = None + + +def show_first_page(): + global now_frame, master + first_page = mtk.Frame(master,) + mtk.Frame(first_page, w=10000).pack(fill="both", expand=True) + mtk.Label(first_page, text=l("InstallWelcome"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(first_page, text="\n"+l("InstallInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(first_page, height=30).pack() + buttonlist = mtk.Frame(first_page) + + def install_callback(*args): + change_page_download() + + mtk.ButtonFill(buttonlist, text=l("StartInstall"), + w=110, color_type="primary", func=install_callback).pack(side="left") + mtk.Frame(buttonlist, height=10).pack(side="left") + buttonlist.pack() + mtk.Frame(first_page, w=10000).pack(fill="both", expand=True) + first_page.pack(fill="both", expand=True) + now_frame = first_page + + +def change_page_download(): + global now_frame, master + now_frame.pack_forget() + instvtoy_page = mtk.Frame(master,) + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + mtk.Label(instvtoy_page, text="0/3 "+l("DownloadInstallTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(instvtoy_page, text="\n"+l("DownloadInstall"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(instvtoy_page, height=30).pack() + + prog_frame = mtk.Frame(instvtoy_page) + with open("res/installer_file.json", 'r') as file: + files = json.load(file) + download_l = [] + if not (os.path.exists("software")): + os.mkdir("software") + if not (os.path.exists("software"+os.sep+"cache")): + os.mkdir("software"+os.sep+"cache") + funclst = [] + for i in files: + def runf(): + sframe = mtk.Frame(prog_frame, height=10) + progps = mtk.Label( + sframe, background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"], text=" 0%", width=6, font=(fontconfig.getfont(), 10)) + progps.pack(side="left") + progbar = mtk.ProgressBar(sframe, w=300) + progbar.pack(side="left", anchor='w') + proglabel = mtk.Label( + sframe, background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"], text=" "+i["name"], width=18, font=(fontconfig.getfont(), 10)) + proglabel.pack(side="left") + sframe.pack(side="top") + + def progcallback(prog): + progbar.set_progress(prog) + progstr = str(int(prog*100)) + outstr = " "*(3-len(progstr))+progstr+"%" + + def setproganim(*args): + progps.configure(text=outstr) + return -1 + prog_frame.root.anim.append(setproganim) + + funclst.append(progcallback) + download_l.append({ + "from": i["source"], + "to": "software"+os.sep+"cache"+os.sep+i["name"]+".7z", + "progbar": funclst[-1] + }) + runf() + + def nextpage_callback(*args): + change_page_installvtoy() + open_ventoy.run() + + buttonlist = mtk.Frame(instvtoy_page, height=30) + btns = mtk.ButtonFill(buttonlist, text=l("InstallVtoy"), + w=120, color_type="primary", func=nextpage_callback) + + def callbacks(): + btns.pack(side="left") + + downloader.download_files(download_l, callbacks, prog_frame.root) + prog_frame.pack(fill='x', anchor="center") + mtk.Frame(instvtoy_page, height=30).pack() + + buttonlist.pack() + + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + instvtoy_page.pack(fill="both", expand=True) + now_frame = instvtoy_page + + +def change_page_installvtoy(): + global now_frame, master + now_frame.pack_forget() + instvtoy_page = mtk.Frame(master,) + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + mtk.Label(instvtoy_page, text="1/3 "+l("InstallVtoyTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(instvtoy_page, text="\n"+l("InstallVtoyInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(instvtoy_page, height=30).pack() + buttonlist = mtk.Frame(instvtoy_page) + scan_obj_list = mtk.Frame(instvtoy_page, height=30) + added_list = False + selects = mtk.Select(scan_obj_list, text=l( + "ChooseVtoyDevice"), items=[], w=380) + devmenu = [] + + def finishvtoy_callback(*args): + if (selects.get() == -1): + return + info(f"[installer]choose disk info:{str(devmenu[selects.get()])}") + global devinfo + devinfo = devmenu[selects.get()] + change_page_installing() + + def install_callback(*args): + nonlocal added_list, selects, devmenu + + def show_all_dev(*args): + nonlocal devmenu + devmenu = get_disk.find_all_disk() + selects.change_menu([f"{i[0]} [{i[1]}]" for i in devmenu]) + + if (added_list == False): + mtk.ButtonLight(scan_obj_list, func=show_all_dev, text=l("ShowAllDevices"), w=100, color_type="info").pack( + side="left") + selects.pack(side="left") + mtk.Button(scan_obj_list, func=finishvtoy_callback, iconname="circle-check", iconsize=16, w=32).pack( + side="left") + added_list = True + devmenu = get_disk.find_vtoy_disk() + selects.change_menu([f"{i[0]} [{i[1]}]" for i in devmenu]) + + def restart_callback(*args): + open_ventoy.run() + + mtk.ButtonFill(buttonlist, text=l("ScanVtoy"), + w=80, color_type="primary", func=install_callback).pack(side="left") + mtk.ButtonLight(buttonlist, text=l("RestartVtoy"), + w=120, color_type="primary", func=restart_callback).pack(side="left") + mtk.Frame(buttonlist, height=10).pack(side="left") + buttonlist.pack() + scan_obj_list.pack() + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + instvtoy_page.pack(fill="both", expand=True) + now_frame = instvtoy_page + + +def change_page_installing(): + global now_frame, master, devinfo + devpath = devinfo[1] + now_frame.pack_forget() + installinjector_page = mtk.Frame(master,) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + mtk.Label(installinjector_page, text="2/3 "+l("InstallIjTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(installinjector_page, text="\n"+l("InstallIjInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(installinjector_page, height=30).pack() + + prog_frame = mtk.Frame(installinjector_page, height=10) + progbar = mtk.ProgressBar(prog_frame, w=300) + progbar.pack() + prog_frame.pack(fill='x') + + def barcallback(prog): + progbar.set_progress(prog) + + finishbutton_frame = mtk.Frame(installinjector_page, height=30) + + def finishbtncallback(*args): + change_page_finish() + finishbtn = mtk.ButtonFill(finishbutton_frame, text=l( + "FinishInstall"), w=120, color_type="success", func=finishbtncallback) + + closeid = False + + def anim_pick(*args): + nonlocal closeid + if (closeid == True): + closeid = False + finishbtn.pack() + return -1 + prog_frame.root.anim.append(anim_pick) + + def finishcallback(): + nonlocal closeid + closeid = True + + finishbutton_frame.pack(fill="both", expand=True) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + installinjector_page.pack(fill="both", expand=True) + theards = install_pkg.PKG_Theard(devpath, barcallback, finishcallback) + theards.start() + now_frame = installinjector_page + + +def change_page_installing(): + global now_frame, master, devinfo + devpath = devinfo[1] + now_frame.pack_forget() + installinjector_page = mtk.Frame(master,) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + mtk.Label(installinjector_page, text="2/3 "+l("InstallIjTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(installinjector_page, text="\n"+l("InstallIjInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(installinjector_page, height=30).pack() + + prog_frame = mtk.Frame(installinjector_page, height=10) + progbar = mtk.ProgressBar(prog_frame, w=300) + progbar.pack() + prog_frame.pack(fill='x') + + def barcallback(prog): + progbar.set_progress(prog) + + finishbutton_frame = mtk.Frame(installinjector_page, height=30) + + def finishbtncallback(*args): + change_page_finish() + finishbtn = mtk.ButtonFill(finishbutton_frame, text=l( + "FinishInstall"), w=120, color_type="success", func=finishbtncallback) + + closeid = False + + def anim_pick(*args): + nonlocal closeid + if (closeid == True): + closeid = False + finishbtn.pack() + return -1 + prog_frame.root.anim.append(anim_pick) + + def finishcallback(): + nonlocal closeid + closeid = True + + mtk.Frame(installinjector_page, height=30).pack() + finishbutton_frame.pack(fill="both", expand=True) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + installinjector_page.pack(fill="both", expand=True) + theards = install_pkg.PKG_Theard(devpath, barcallback, finishcallback) + theards.start() + now_frame = installinjector_page + + +def change_page_finish(): + global now_frame, master + now_frame.pack_forget() + finish_page = mtk.Frame(master,) + mtk.Frame(finish_page, w=10000).pack(fill="both", expand=True) + mtk.Label(finish_page, text="3/3 "+l("InstallFinishTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(finish_page, text="\n"+l("InstallFinishInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + + def closecallback(*args): + info("close from installer") + finish_page.root.quit() + + btnframe = mtk.Frame(finish_page, height=30) + mtk.ButtonFill(finish_page, text=l( + "InstallFinishBtn"), func=closecallback, color_type="danger").pack() + btnframe.pack() + mtk.Frame(finish_page, height=30).pack() + mtk.Frame(finish_page, w=10000).pack(fill="both", expand=True) + finish_page.pack(fill="both", expand=True) + now_frame = finish_page + + +def installer_ui(root: mtk.Frame): + global master + install_root_frame = mtk.Frame(root) + master = install_root_frame + show_first_page() + install_root_frame.pack(fill="both", expand=True) diff --git a/ui/lang.py b/ui/lang.py new file mode 100644 index 0000000..b844a84 --- /dev/null +++ b/ui/lang.py @@ -0,0 +1,15 @@ +from logger.logger import * +import tomllib + +l_obj = {} + + +def load_lang(lang: str): + info(f"[lang]load lang: {lang}") + global l_obj + with open("lang/"+lang+".toml", "rb") as file: + l_obj = tomllib.load(file) + + +def l(strs): + return l_obj.get(strs, f"__{strs}__") diff --git a/ui/nav.py b/ui/nav.py new file mode 100644 index 0000000..d752ab8 --- /dev/null +++ b/ui/nav.py @@ -0,0 +1,61 @@ +from magictk import mtk, color_tmpl +from logger.logger import * + + +choose_id = 0 + + +def nav_callback(obj): + ids = obj.ids + side = navlists[ids]["side"] + global choose_id + if (choose_id == ids): + return + choose_id = ids + if (side == "top"): + nav_frame_now.place_forget() + nav_frame_now.place(x=0, y=50*ids, width=3, height=50, anchor='nw') + else: + nav_frame_now.place_forget() + nav_frame_now.place(x=0, rely=1, width=3, height=50, anchor='sw') + + +def pack_nav(master: mtk.Frame, root: mtk.Frame, navlist: list): + global nav_frame_now, btn_list, navlists, nav_main, btn_frame_list + navlists = navlist + nav_frame = mtk.Frame(master) + nav_frame_show = mtk.Frame(nav_frame, w=3) + nav_frame_now = mtk.Frame( + nav_frame_show, w=3, bg=color_tmpl.default_color["primary"]) + nav_frame_now.place(x=0, y=0, width=3, height=50) + nav_frame_show.pack(side="left", fill='y') + mtk.Frame(nav_frame, w=1).pack( + side="left", expand=True, fill='y') + nav_frame_main = mtk.Frame(nav_frame, w=50) + + btn_list = [] + btn_frame_list = [] + ids = 0 + for i in navlist: + icon = i["icon"] + frame = i["frame"] + side = i["side"] + btn_list.append(mtk.ButtonLight( + master=nav_frame_main, color_type="plain", iconname=icon, iconsize=32, w=50, h=50, func=nav_callback)) + btn_list[-1].ids = ids + btn_list[-1].pack(side=side) + btn_frame_list.append(frame) + ids += 1 + + nav_frame_main.pack(side="left", fill='both') + mtk.Frame(nav_frame, w=2).pack( + side="left", expand=True, fill='y') + mtk.Frame(nav_frame, w=1, bg=color_tmpl.default_color["border_light"]).pack( + side="left", expand=True, fill='y') + nav_frame.pack(side="left", expand=True, fill='y') + + nav_main = mtk.Frame( + master, w=1000) + btn_frame_list[0](nav_main) + + nav_main.pack(side="right", fill='both') diff --git a/ui/win.py b/ui/win.py new file mode 100644 index 0000000..72ddb0b --- /dev/null +++ b/ui/win.py @@ -0,0 +1,53 @@ +from tkinter import messagebox +from magictk import mtk +from logger.logger import * +from ui import nav +from ui import installer +from lib import get_disk +from ui.lang import load_lang, l +import sys +import getpass +import platform +import ctypes + +init() + +load_lang("zh_cn") # TODO:读取设置 + +disk_res = get_disk.find_hub_disk() +errno = disk_res[0] +root_disk = disk_res[1] +if (errno == 1): + messagebox.showerror("Injector Hub Error", root_disk) + sys.exit(1) +elif (errno == 2): + info("[win]cannot find installed disk") + if (platform.system() == "Linux" and getpass.getuser() != "root"): + messagebox.showerror("Injector Hub Error", l("PermissionDeniedLinux")) + sys.exit(1) + if (platform.system() == "Windows" and ctypes.windll.shell32.IsUserAnAdmin() == False): + messagebox.showerror("Injector Hub Error", l("PermissionDeniedWin")) + nav_list = [ + {"icon": "lightning", "frame": installer.installer_ui, "side": "top"} + ] +else: + info(f"[win]found installed disk \"{root_disk}\"") + nav_list = [ + {"icon": "home-filled", "frame": None, "side": "top"}, + {"icon": "dvd", "frame": None, "side": "top"}, + {"icon": "plugin", "frame": None, "side": "top"}, + {"icon": "setting", "frame": None, "side": "bottom"} + ] + +info("[win]init window") +mtk.load_icon_pack("res/icon.pack") +main_win = mtk.Tk(title="Injector Hub", w=1000, h=800) + +main_frame = mtk.Frame(main_win, w=10000) +nav.pack_nav(main_win, main_frame, nav_list) +main_frame.pack(side="left", fill="both", expand=True) + + +def main(): + info("[win]mainloop") + main_win.mainloop()