from json import JSONDecodeError, dumps, loads from os import path from os import name as osname from tkinter import Misc, PhotoImage from typing import Any, Literal import darkdetect def jsonLoad(filename): """Loads arg1 as json and returns its contents""" with open(filename, "r", encoding='utf8') as file: try: output = loads(file.read()) except JSONDecodeError: raise except FileNotFoundError: raise return output def jsonSave(contents, filename): """Dumps dict/list arg1 to file arg2""" try: with open(filename, "w", encoding='utf8') as file: file.write(dumps(contents, ensure_ascii=False, indent=4)) except Exception as exp: raise return def nested_set(dic, keys, value, create_missing=True): d = dic for key in keys[:-1]: if key in d: d = d[key] elif create_missing: d = d.setdefault(key, {}) else: return dic if keys[-1] in d or create_missing: d[keys[-1]] = value return dic def configSet(keys: list, value: Any, create_missing=True) -> None: """Set config's value to provided one ### Args: * keys (`list`): List of keys from the highest one to target. * value (`Any`): Needed value. * create_missing (`bool`, optional): Create missing items on the way. Defaults to True. """ this_dict = jsonLoad("config.json") this_dict = nested_set(this_dict, keys, value, create_missing=create_missing) jsonSave(this_dict, "config.json") return def configGet(key: str, *args: str) -> Any: """Get value of the config key ### Args: * key (`str`): The last key of the keys path. * *args (`str`): Path to key like: dict[args][key]. ### Returns: * any: Value of provided key """ try: this_dict = jsonLoad("config.json") except FileNotFoundError: print("Config file not found!", flush=True) exit() this_key = this_dict for dict_key in args: this_key = this_key[dict_key] return this_key[key] def use_dark_mode(no_config=False) -> bool: """Return whether dark mode should be used ### Returns: * `bool`: True if yes and False if no """ if no_config is True: return bool(darkdetect.isDark()) if configGet("dark_mode_auto") is True: return bool(darkdetect.isDark()) else: return configGet("dark_mode") def get_string_mode() -> Literal["dark", "light"]: """Return whether dark mode is used ### Returns: * `Literal["dark", "light"]` """ return "dark" if use_dark_mode() is True else "light" def resize_window(me: Misc, width: int, height: int) -> None: me.window_width = width me.window_height = height me.screen_width = me.winfo_screenwidth() me.screen_height = me.winfo_screenheight() me.center_x = int(me.screen_width/2 - me.window_width / 2) me.center_y = int(me.screen_height/2 - me.window_height / 2) me.geometry(f'{me.window_width}x{me.window_height}+{me.center_x}+{me.center_y}') def set_icon(me: Misc) -> None: if osname == "nt": me.iconbitmap(path.join("assets", "favicon.ico")) else: me.iconphoto(True, PhotoImage(file=path.join("assets", "favicon.png")))