From 062a38ceec9a356d8a54000d5265129ef46407aa Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 26 Jan 2023 13:29:30 +0100 Subject: [PATCH] Improved enums and error handling --- classes/app.py | 41 +++++++++++++++++++++++++++---------- classes/enums.py | 24 ++++++++++++++++++++++ classes/frames/errors.py | 4 ++-- classes/frames/settings.py | 14 ++++++++----- classes/toplevel/welcome.py | 16 +++++++++------ modules/theme_titlebar.py | 12 ++++++----- 6 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 classes/enums.py diff --git a/classes/app.py b/classes/app.py index cea650d..712b5a1 100644 --- a/classes/app.py +++ b/classes/app.py @@ -1,5 +1,6 @@ from os import path from tkinter import NSEW, NW, E, N, S, W, PhotoImage, messagebox, ttk +from traceback import format_exc import requests import sv_ttk @@ -7,6 +8,7 @@ from ttkthemes import ThemedTk from classes.custom.scrollable_frame import FIT_HEIGHT, FIT_WIDTH from classes.custom.themed_frame import ThemedFrame +from classes.enums import ConnectionState, Theme from classes.frames.devices import FrameDevices, FrameDevicesEmpty from classes.frames.errors import FrameErrorConnection, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured from classes.frames.saves import FrameSaves, FrameSavesEmpty @@ -14,6 +16,7 @@ from classes.frames.settings import FrameSettings from classes.toplevel.welcome import ToplevelWelcome from modules.theme_titlebar import theme_title_bar from modules.utils import configGet, get_string_mode, resize_window, set_icon, use_dark_mode +from modules.logger import logger class App(ThemedTk): @@ -33,7 +36,7 @@ class App(ThemedTk): sv_ttk.init_theme(self) if use_dark_mode(): - theme_title_bar(self, mode="dark") + theme_title_bar(self, mode=Theme.DARK) self.update() set_icon(self) @@ -43,14 +46,11 @@ class App(ThemedTk): self.draw_main() - def verify_authorization(self): + def verify_authorization(self) -> ConnectionState: try: - if requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")).status_code == 200: - return True - else: - return False + return ConnectionState.UNAUTHORIZED if requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")).status_code == 403 else ConnectionState.OK except: - return False + return ConnectionState.BAD def verify_saves_dir(self): @@ -63,7 +63,14 @@ class App(ThemedTk): def frame_saves(self): self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) - self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + try: + self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + except Exception as exp: + messagebox.showerror(title="Connection error", message=f"We could not reach the server to check for save entries\n\n{exp}") + logger.error(format_exc()) + self.frame_saves_object = FrameErrorConnection(self) + self.frame_saves_object.grid(column=1, row=0, sticky=NSEW) + return if self.frame_saves_saves.status_code == 200 and isinstance(self.frame_saves_saves.json(), list) is True and len(self.frame_saves_saves.json()) > 0: self.frame_saves_object = FrameSaves(self, self.frame_saves_saves.json(), vscroll=True) else: @@ -74,7 +81,14 @@ class App(ThemedTk): def frame_devices(self): self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) - self.frame_devices_devices = requests.get(f'{configGet("address")}/devices', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + try: + self.frame_devices_devices = requests.get(f'{configGet("address")}/devices', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + except Exception as exp: + messagebox.showerror(title="Connection error", message=f"We could not reach the server to check the devices list\n\n{exp}") + logger.error(format_exc()) + self.frame_devices_object = FrameErrorConnection(self) + self.frame_devices_object.grid(column=1, row=0, sticky=NSEW) + return if self.frame_devices_devices.status_code == 200 and isinstance(self.frame_devices_devices.json(), list) is True and len(self.frame_devices_devices.json()) > 0: self.frame_devices_object = FrameDevices(self, self.frame_devices_devices.json(), vscroll=True) else: @@ -136,14 +150,19 @@ class App(ThemedTk): # messagebox.showerror(title="Configuration error", message="Your client is not properly configured.") return - if self.verify_authorization() is False: + self.verified = self.verify_authorization() + + if self.verified in [ConnectionState.BAD, ConnectionState.UNAUTHORIZED]: self.item_saves.state(["disabled"]) self.item_devices.state(["disabled"]) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) self.connection_error = FrameErrorConnection(self) self.connection_error.grid(column=1, row=0, rowspan=2, sticky=N+S+W+E) - messagebox.showerror(title="Authentication error", message="Your API key seems to be invalid.") + if self.verified == ConnectionState.UNAUTHORIZED: + messagebox.showerror(title="Authentication error", message="Your API key seems to be invalid.") + else: + messagebox.showerror(title="Connection error", message="Server is not reachable or your client configuration is incorrect. Please check your network connection and client configuration.") return if self.verify_saves_dir() is False: diff --git a/classes/enums.py b/classes/enums.py new file mode 100644 index 0000000..4c257b0 --- /dev/null +++ b/classes/enums.py @@ -0,0 +1,24 @@ +from enum import Enum + +class SavesPreference(Enum): + LATEST_UPLOAD = "latest upload" + LATEST_PROGRESS = "latest progress" + +class SavesPreferenceButton(Enum): + LATEST_UPLOAD = "Latest upload " + LATEST_PROGRESS = "Latest progress " + +class Theme(Enum): + AUTO = "auto" + LIGHT = "light" + DARK = "dark" + +class ThemeButton(Enum): + AUTO = "Auto " + LIGHT = "Light " + DARK = "Dark " + +class ConnectionState(Enum): + OK = "ok" + BAD = "bad" + UNAUTHORIZED = "unauthorized" \ No newline at end of file diff --git a/classes/frames/errors.py b/classes/frames/errors.py index 2076be1..f08ffc0 100644 --- a/classes/frames/errors.py +++ b/classes/frames/errors.py @@ -11,13 +11,13 @@ from modules.utils import configGet, get_string_mode def try_connecting(master: Any): try: - if requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")).status_code != 200: + if requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")).status_code == 403: messagebox.showerror(title="Authentication error", message="Your API key seems to be invalid.") return # messagebox.showinfo(title="Connection succeeded", message="Server is reachable, apikey is valid, so your client is now ready to be used!") master.destroy_everything() except: - messagebox.showerror(title="Configuration error", message="Your client configuration is incorrect.") + messagebox.showerror(title="Connection error", message="Server is not reachable or your client configuration is incorrect. Please check your network connection and client configuration.") # master.destroy_everything() diff --git a/classes/frames/settings.py b/classes/frames/settings.py index baff2d8..a581e04 100644 --- a/classes/frames/settings.py +++ b/classes/frames/settings.py @@ -4,6 +4,7 @@ from tkinter import N, NSEW, S, W, E, END, IntVar, StringVar, filedialog, messag from ttkthemes import ThemedTk from classes.custom.themed_frame import ThemedFrame +from classes.enums import SavesPreference, SavesPreferenceButton, Theme from modules.theme_titlebar import theme_title_bar from modules.utils import configGet, configSet, get_string_mode, use_dark_mode @@ -92,10 +93,10 @@ class FrameSettings(ThemedFrame): self.saves_preference_label = ttk.Label(self, text="Saves preference:") self.saves_preference_label.grid(column=0, row=4, sticky=W, padx=9, pady=9) - self.default_preference = "Latest upload " if configGet("prefer_saves") == "latest upload" else "Latest progress " + self.default_preference = SavesPreferenceButton.LATEST_UPLOAD.value if configGet("prefer_saves") == SavesPreference.LATEST_UPLOAD.value else SavesPreferenceButton.LATEST_PROGRESS.value self.chosen_preference = StringVar() - self.preferences = ("Latest upload ", "Latest progress ") + self.preferences = (SavesPreferenceButton.LATEST_UPLOAD.value, SavesPreferenceButton.LATEST_PROGRESS.value) self.saves_preference_button = ttk.OptionMenu(self, self.chosen_preference, self.default_preference, *self.preferences, direction="below") self.saves_preference_button.grid(column=1, row=4, sticky=W, padx=9, pady=9) # ================ @@ -127,10 +128,13 @@ class FrameSettings(ThemedFrame): def change_theme(self, *args): - if self.chosen_theme.get().strip().lower() == "auto": - self.chosen_theme_real = "dark" if use_dark_mode(no_config=True) is True else "light" + if self.chosen_theme.get().strip().lower() == Theme.AUTO.value: + self.chosen_theme_real = Theme.DARK if use_dark_mode(no_config=True) is True else Theme.LIGHT else: - self.chosen_theme_real = self.chosen_theme.get().strip().lower() + if self.chosen_theme.get().strip().lower() == Theme.LIGHT.value: + self.chosen_theme_real = Theme.LIGHT + else: + self.chosen_theme_real = Theme.DARK theme_title_bar(self.master, self.chosen_theme_real) def select_location(self, entry: ttk.Entry): diff --git a/classes/toplevel/welcome.py b/classes/toplevel/welcome.py index 3d2d752..999f19a 100644 --- a/classes/toplevel/welcome.py +++ b/classes/toplevel/welcome.py @@ -9,6 +9,7 @@ from classes.custom.image_label import ImageLabel from classes.custom.themed_frame import ThemedFrame from classes.custom.themed_toplevel import ThemedToplevel +from classes.enums import Theme from modules.logger import logger from modules.theme_titlebar import theme_title_bar from modules.utils import configGet, configSet, resize_window, set_icon, use_dark_mode @@ -31,7 +32,7 @@ class ToplevelWelcome(ThemedToplevel): sv_ttk.init_theme(self) if use_dark_mode(): - theme_title_bar(self, mode="dark") + theme_title_bar(self, mode=Theme.DARK) self.update() set_icon(self) @@ -287,20 +288,23 @@ class ToplevelWelcome(ThemedToplevel): def change_theme(self, *args): - if self.stage_option_menu_var.get().strip().lower() == "auto": - self.stage_option_menu_var_real = "dark" if use_dark_mode(no_config=True) is True else "light" + if self.stage_option_menu_var.get().strip().lower() == Theme.AUTO.value: + self.stage_option_menu_var_real = Theme.DARK if use_dark_mode(no_config=True) is True else Theme.LIGHT else: - self.stage_option_menu_var_real = self.stage_option_menu_var.get().strip().lower() + if self.stage_option_menu_var.get().strip().lower() == Theme.LIGHT.value: + self.stage_option_menu_var_real = Theme.LIGHT + else: + self.stage_option_menu_var_real = Theme.DARK theme_title_bar(self, self.stage_option_menu_var_real) theme_title_bar(self.master, self.stage_option_menu_var_real) def stage_theme_validate(self): - if self.stage_option_menu_var.get().strip().lower() == "auto": + if self.stage_option_menu_var.get().strip().lower() == Theme.AUTO.value: configSet(["dark_mode_auto"], True) else: configSet(["dark_mode_auto"], False) - if self.stage_option_menu_var.get().strip().lower() == "dark": + if self.stage_option_menu_var.get().strip().lower() == Theme.DARK.value: configSet(["dark_mode"], True) else: configSet(["dark_mode"], False) diff --git a/modules/theme_titlebar.py b/modules/theme_titlebar.py index 5a5f034..e672725 100644 --- a/modules/theme_titlebar.py +++ b/modules/theme_titlebar.py @@ -3,25 +3,27 @@ import sys import sv_ttk from distutils.version import StrictVersion as Version from os import system -from tkinter import Tcl, Toplevel +from tkinter import Misc, Tcl, Toplevel from typing import Literal, Union from ttkthemes import ThemedTk +from classes.enums import Theme + if sys.platform.startswith("win"): from ctypes import byref, c_int, sizeof, windll -def theme_title_bar(window: Union[ThemedTk, Toplevel], mode: Literal["dark", "light"]) -> None: +def theme_title_bar(window: Union[ThemedTk, Toplevel, Misc], mode: Literal[Theme.DARK, Theme.LIGHT]) -> None: """ MORE INFO: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute """ - if mode == "dark": + if mode.value == "dark": value = 1 #window.configure(background="#1c1c1c") - elif mode == "light": + elif mode.value == "light": value = 0 #window.configure(background="#ffffff") else: @@ -29,7 +31,7 @@ def theme_title_bar(window: Union[ThemedTk, Toplevel], mode: Literal["dark", "li try: - sv_ttk.set_theme(mode) + sv_ttk.set_theme(mode.value) window.update()