Still WIP
This commit is contained in:
parent
67f87e0830
commit
1be317898f
159
classes/app.py
159
classes/app.py
@ -4,11 +4,14 @@ from tkinter import NW, E, N, S, W, messagebox, ttk
|
||||
import requests
|
||||
import sv_ttk
|
||||
from ttkthemes import ThemedTk
|
||||
from classes.custom.themed_frame import ThemedFrame
|
||||
|
||||
from classes.frames import FrameDevices, FrameSaves, FrameSettings
|
||||
from classes.window_config import WindowConfig
|
||||
from classes.frames.devices import FrameDevices
|
||||
from classes.frames.saves import FrameSaves
|
||||
from classes.frames.settings import FrameSettings
|
||||
from classes.frames.errors import FrameErrorConnection, FrameErrorSavesFolder, FrameErrorUnconfigured
|
||||
from modules.theme_titlebar import theme_title_bar
|
||||
from modules.utils import configGet, use_dark_mode
|
||||
from modules.utils import configGet, get_string_mode, use_dark_mode
|
||||
|
||||
|
||||
class App(ThemedTk):
|
||||
@ -28,82 +31,37 @@ class App(ThemedTk):
|
||||
|
||||
self.title("Stardew Sync")
|
||||
self.geometry(f'{self.window_width}x{self.window_height}+{self.center_x}+{self.center_y}')
|
||||
self.iconbitmap(path.join("assets", "favicon.ico"))
|
||||
self.focus_set()
|
||||
|
||||
self.resizable(False, True)
|
||||
|
||||
sv_ttk.init_theme(self)
|
||||
|
||||
if use_dark_mode():
|
||||
self.configure(background="#1c1c1c")
|
||||
theme_title_bar(self, mode="dark")
|
||||
sv_ttk.set_theme("dark")
|
||||
else:
|
||||
sv_ttk.set_theme("light")
|
||||
self.update()
|
||||
|
||||
|
||||
self.iconbitmap(path.join("assets", "favicon.ico"))
|
||||
self.focus_set()
|
||||
|
||||
self.draw_main()
|
||||
|
||||
|
||||
def try_connecting(self):
|
||||
try:
|
||||
requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")})
|
||||
# messagebox.showinfo(title="Connection succeeded", message="Server is reachable, apikey is valid, so your client is now ready to be used!")
|
||||
self.destroy_everything()
|
||||
except:
|
||||
messagebox.showerror(title="Configuration error", message="Your client configuration is incorrect. Set it up and try again.")
|
||||
self.destroy_everything()
|
||||
|
||||
|
||||
def verify_connecting(self):
|
||||
try:
|
||||
if requests.get(configGet("address")+"/check").status_code == 200:
|
||||
return
|
||||
else:
|
||||
raise requests.exceptions.HTTPError()
|
||||
except:
|
||||
self.verify_answer = messagebox.askyesno(title="Connection failed", message="You might have no connection to the server or your api key could expire. Reconfigure the client?\n\nYes to reconfigure and No to retry connecting")
|
||||
if self.verify_answer is True:
|
||||
window = WindowConfig(self)
|
||||
window.grab_set()
|
||||
if hasattr(self, "setup_button"):
|
||||
self.setup_button.destroy()
|
||||
if hasattr(self, "setup_label"):
|
||||
self.setup_label.destroy()
|
||||
ttk.Label(self, text="Client configured, try to connect").pack(expand=True)
|
||||
ttk.Button(self, text="Connect", style="Accent.TButton", width=10, command=self.try_connecting).pack(expand=True)
|
||||
return False
|
||||
else:
|
||||
self.destroy_everything()
|
||||
return True
|
||||
|
||||
|
||||
def verify_authorization(self):
|
||||
try:
|
||||
if requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")}).status_code == 200:
|
||||
return
|
||||
if requests.get(configGet("address")+"/apikey", headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")).status_code == 200:
|
||||
return True
|
||||
else:
|
||||
self.verify_answer = messagebox.askyesno(title="Authorization failed", message="Your apikey could have expired or is invalid. Reconfigure the client?\n\nYes to reconfigure and No to retry connecting")
|
||||
if self.verify_answer is True:
|
||||
window = WindowConfig(self)
|
||||
window.grab_set()
|
||||
if hasattr(self, "setup_button"):
|
||||
self.setup_button.destroy()
|
||||
if hasattr(self, "setup_label"):
|
||||
self.setup_label.destroy()
|
||||
ttk.Label(self, text="Client configured, try to connect").pack(expand=True)
|
||||
ttk.Button(self, text="Connect", style="Accent.TButton", width=10, command=self.try_connecting).pack(expand=True)
|
||||
return False
|
||||
else:
|
||||
self.destroy_everything()
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
self.verify_answer = messagebox.askyesno(title="Connection failed", message="You might have no connection to the server or your api key could expire. Reconfigure the client?\n\nYes to reconfigure and No to retry connecting")
|
||||
if self.verify_answer is True:
|
||||
window = WindowConfig(self)
|
||||
window.grab_set()
|
||||
ttk.Label(self, text="Client configured, try to connect").pack(expand=True)
|
||||
ttk.Button(self, text="Connect", style="Accent.TButton", width=10, command=self.try_connecting).pack(expand=True)
|
||||
else:
|
||||
self.destroy_everything()
|
||||
return False
|
||||
|
||||
def verify_saves_dir(self):
|
||||
|
||||
if configGet("saves_location") is None or path.exists(configGet("saves_location")) is False:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def frame_saves(self):
|
||||
@ -124,20 +82,19 @@ class App(ThemedTk):
|
||||
|
||||
def draw_main(self):
|
||||
|
||||
if configGet("address") is None or configGet("apikey") is None:
|
||||
self.setup_label = ttk.Label(self, text="Your client seems to be unconfigured")
|
||||
self.setup_label.pack(expand=True)
|
||||
self.setup_button = ttk.Button(self, text="Set up", style="Accent.TButton", width=10, command=self.open_window_config)
|
||||
self.setup_button.pack(expand=True)
|
||||
sv_ttk.set_theme(get_string_mode())
|
||||
|
||||
if self.verify_connecting() is False:
|
||||
return
|
||||
# self.grid_rowconfigure(1, weight=2)
|
||||
# self.grid_rowconfigure(0, weight=2)
|
||||
# self.grid_columnconfigure(1, weight=1)
|
||||
# self.setup_label = ttk.Label(self, text="Your client seems to be unconfigured")
|
||||
# self.setup_label.grid(column=1, row=0, padx=9, pady=9, sticky=S)
|
||||
# self.setup_button = ttk.Button(self, text="Set up", style="Accent.TButton", width=10, command=self.open_window_config)
|
||||
# self.setup_button.grid(column=1, row=1, padx=9, pady=9, sticky=N)
|
||||
# return
|
||||
|
||||
if self.verify_authorization() is False:
|
||||
return
|
||||
|
||||
self.frame_sidebar = ttk.Frame(self)
|
||||
self.frame_sidebar.grid(column=0, row=0, sticky=NW)
|
||||
self.frame_sidebar = ThemedFrame(self)
|
||||
self.frame_sidebar.grid(column=0, row=0, columnspan=1, sticky=N+S+W+E)
|
||||
|
||||
self.item_saves = ttk.Button(self.frame_sidebar, text="Saves", width=10, command=self.frame_saves)
|
||||
self.item_saves.grid(column=0, row=0, sticky=W, padx=9, pady=9)
|
||||
@ -148,22 +105,46 @@ class App(ThemedTk):
|
||||
self.item_settings = ttk.Button(self.frame_sidebar, text="Settings", width=10, command=self.frame_settings)
|
||||
self.item_settings.grid(column=0, row=2, sticky=W+S, padx=9, pady=9)
|
||||
|
||||
self.item_test = ttk.Button(self.frame_sidebar, text="Test", width=10, command=lambda:sv_ttk.set_theme("light"))
|
||||
self.item_test.grid(column=0, row=3, sticky=W+S, padx=9, pady=9)
|
||||
if configGet("address") in ["", None] or configGet("apikey") in ["", None]:
|
||||
self.item_saves.state(["disabled"])
|
||||
self.item_devices.state(["disabled"])
|
||||
self.connection_error = FrameErrorUnconfigured(self)
|
||||
self.connection_error.grid(column=1, row=0, rowspan=2, sticky=N+S+W+E)
|
||||
# messagebox.showerror(title="Configuration error", message="Your client is not properly configured.")
|
||||
return
|
||||
|
||||
if self.verify_authorization() is False:
|
||||
self.item_saves.state(["disabled"])
|
||||
self.item_devices.state(["disabled"])
|
||||
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.")
|
||||
return
|
||||
|
||||
if self.verify_saves_dir() is False:
|
||||
self.item_saves.state(["disabled"])
|
||||
self.connection_error = FrameErrorSavesFolder(self)
|
||||
self.connection_error.grid(column=1, row=0, rowspan=2, sticky=N+S+W+E)
|
||||
messagebox.showerror(title="Configuration error", message="Saves folder seems to be invalid.")
|
||||
return
|
||||
|
||||
self.frame_saves()
|
||||
|
||||
|
||||
def destroy_everything(self):
|
||||
def destroy_everything(self, draw=True):
|
||||
for widget in self.winfo_children():
|
||||
widget.destroy()
|
||||
self.draw_main()
|
||||
if draw is True:
|
||||
self.draw_main()
|
||||
|
||||
|
||||
def open_window_config(self):
|
||||
window = WindowConfig(self)
|
||||
window.grab_set()
|
||||
self.setup_button.destroy()
|
||||
self.setup_label.destroy()
|
||||
ttk.Label(self, text="Client configured, try to connect").pack(expand=True)
|
||||
ttk.Button(self, text="Connect", style="Accent.TButton", width=10, command=self.try_connecting).pack(expand=True)
|
||||
# def open_window_config(self):
|
||||
# window = WindowConfig(self)
|
||||
# window.grab_set()
|
||||
# self.setup_button.destroy()
|
||||
# self.setup_label.destroy()
|
||||
# self.grid_rowconfigure(1, weight=2)
|
||||
# self.grid_rowconfigure(0, weight=2)
|
||||
# self.grid_columnconfigure(1, weight=1)
|
||||
# ttk.Label(self, text="Client configured, try to connect").grid(column=1, row=0, padx=9, pady=9, sticky=S)
|
||||
# ttk.Button(self, text="Connect", style="Accent.TButton", width=10, command=self.try_connecting).grid(column=1, row=1, padx=9, pady=9, sticky=N)
|
14
classes/custom/themed_frame.py
Normal file
14
classes/custom/themed_frame.py
Normal file
@ -0,0 +1,14 @@
|
||||
from ttkthemes import ThemedTk
|
||||
from typing import Union
|
||||
import sv_ttk
|
||||
from tkinter.ttk import Frame
|
||||
|
||||
from modules.utils import get_string_mode
|
||||
|
||||
class ThemedFrame(Frame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
sv_ttk.set_theme(get_string_mode())
|
@ -1,57 +0,0 @@
|
||||
from tkinter import EW, NS, ttk
|
||||
|
||||
from ttkthemes import ThemedTk
|
||||
|
||||
|
||||
class FrameSaves(ttk.Frame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
master.title("Saves - Stardew Sync")
|
||||
|
||||
self["borderwidth"] = 2
|
||||
self["relief"] = "solid"
|
||||
|
||||
for btn in range(0, 10):
|
||||
ttk.Button(self, text="SAVES "+str(btn)).grid(column=0, row=btn, padx=9, pady=9, sticky=EW)
|
||||
|
||||
self.scrollbar = ttk.Scrollbar(self, orient="vertical")
|
||||
self.scrollbar.grid(column=1, row=0, sticky=NS)
|
||||
|
||||
|
||||
class FrameDevices(ttk.Frame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
master.title("Devices - Stardew Sync")
|
||||
|
||||
self["borderwidth"] = 2
|
||||
self["relief"] = "solid"
|
||||
|
||||
for btn in range(0, 10):
|
||||
ttk.Button(self, text="DEVICES "+str(btn)).grid(column=0, row=btn, padx=9, pady=9, sticky=EW)
|
||||
|
||||
self.scrollbar = ttk.Scrollbar(self, orient="vertical")
|
||||
self.scrollbar.grid(column=1, row=0, sticky=NS)
|
||||
|
||||
|
||||
class FrameSettings(ttk.Frame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
master.title("Settings - Stardew Sync")
|
||||
|
||||
self["borderwidth"] = 2
|
||||
self["relief"] = "solid"
|
||||
|
||||
for btn in range(0, 10):
|
||||
ttk.Button(self, text="SETTINGS "+str(btn)).grid(column=0, row=btn, padx=9, pady=9, sticky=EW)
|
||||
|
||||
self.scrollbar = ttk.Scrollbar(self, orient="vertical")
|
||||
self.scrollbar.grid(column=1, row=0, sticky=NS)
|
23
classes/frames/devices.py
Normal file
23
classes/frames/devices.py
Normal file
@ -0,0 +1,23 @@
|
||||
from tkinter import EW, NS, ttk
|
||||
|
||||
from ttkthemes import ThemedTk
|
||||
|
||||
from classes.custom.themed_frame import ThemedFrame
|
||||
|
||||
|
||||
class FrameDevices(ThemedFrame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
master.title("Devices - Stardew Sync")
|
||||
|
||||
self["borderwidth"] = 2
|
||||
self["relief"] = "solid"
|
||||
|
||||
for btn in range(0, 10):
|
||||
ttk.Button(self, text="DEVICES "+str(btn)).grid(column=0, row=btn, padx=9, pady=9, sticky=EW)
|
||||
|
||||
self.scrollbar = ttk.Scrollbar(self, orient="vertical")
|
||||
self.scrollbar.grid(column=1, row=0, sticky=NS)
|
85
classes/frames/errors.py
Normal file
85
classes/frames/errors.py
Normal file
@ -0,0 +1,85 @@
|
||||
from tkinter import N, S, messagebox, ttk
|
||||
from typing import Any
|
||||
|
||||
import sv_ttk
|
||||
import requests
|
||||
from ttkthemes import ThemedTk
|
||||
from classes.custom.themed_frame import ThemedFrame
|
||||
|
||||
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:
|
||||
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.")
|
||||
# master.destroy_everything()
|
||||
|
||||
|
||||
class FrameErrorConnection(ThemedFrame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.grid_rowconfigure(0, weight=2)
|
||||
self.grid_rowconfigure(1, weight=2)
|
||||
|
||||
master.columnconfigure(1, weight=1)
|
||||
|
||||
self.label = ttk.Label(self, text="Connection failed")
|
||||
self.label.grid(column=0, row=0, padx=9, pady=9, sticky=S)
|
||||
|
||||
self.frame_buttons = ThemedFrame(self)
|
||||
self.frame_buttons.grid(column=0, row=1, sticky=N)
|
||||
|
||||
self.button_retry = ttk.Button(self.frame_buttons, text="Retry", style="Accent.TButton", width=10, command=lambda:try_connecting(master))
|
||||
self.button_settings = ttk.Button(self.frame_buttons, text="Settings", width=10, command=master.frame_settings)
|
||||
self.button_retry.grid(column=0, row=0, padx=9, pady=9)
|
||||
self.button_settings.grid(column=1, row=0, padx=9, pady=9)
|
||||
|
||||
|
||||
class FrameErrorSavesFolder(ThemedFrame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.grid_rowconfigure(0, weight=2)
|
||||
self.grid_rowconfigure(1, weight=2)
|
||||
|
||||
master.columnconfigure(1, weight=1)
|
||||
|
||||
self.label = ttk.Label(self, text="Invalid saves folder")
|
||||
self.label.grid(column=0, row=0, padx=9, pady=9, sticky=S)
|
||||
|
||||
self.button_settings = ttk.Button(self, text="Settings", style="Accent.TButton", width=10, command=master.frame_settings)
|
||||
self.button_settings.grid(column=0, row=1, sticky=N)
|
||||
|
||||
class FrameErrorUnconfigured(ThemedFrame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.grid_rowconfigure(0, weight=2)
|
||||
self.grid_rowconfigure(1, weight=2)
|
||||
|
||||
master.columnconfigure(1, weight=1)
|
||||
|
||||
self.label = ttk.Label(self, text="Client uncofigured")
|
||||
self.label.grid(column=0, row=0, padx=9, pady=9, sticky=S)
|
||||
|
||||
self.button_settings = ttk.Button(self, text="Settings", style="Accent.TButton", width=10, command=master.frame_settings)
|
||||
self.button_settings.grid(column=0, row=1, sticky=N)
|
25
classes/frames/saves.py
Normal file
25
classes/frames/saves.py
Normal file
@ -0,0 +1,25 @@
|
||||
from tkinter import EW, NS, ttk
|
||||
|
||||
from ttkthemes import ThemedTk
|
||||
|
||||
from classes.custom.themed_frame import ThemedFrame
|
||||
|
||||
|
||||
class FrameSaves(ThemedFrame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
master.title("Saves - Stardew Sync")
|
||||
|
||||
self["borderwidth"] = 2
|
||||
self["relief"] = "solid"
|
||||
|
||||
self.inside_frame = ThemedFrame(self)
|
||||
|
||||
for btn in range(0, 10):
|
||||
ttk.Button(self.inside_frame, text="SAVES "+str(btn)).grid(column=0, row=btn, padx=9, pady=9, sticky=EW)
|
||||
|
||||
self.scrollbar = ttk.Scrollbar(self.inside_frame, orient="vertical")
|
||||
self.scrollbar.grid(column=1, row=0, sticky=NS)
|
195
classes/frames/settings.py
Normal file
195
classes/frames/settings.py
Normal file
@ -0,0 +1,195 @@
|
||||
from os import getenv, path
|
||||
from tkinter import N, NSEW, S, W, E, END, IntVar, StringVar, filedialog, messagebox, ttk
|
||||
|
||||
from ttkthemes import ThemedTk
|
||||
from classes.custom.themed_frame import ThemedFrame
|
||||
from modules.theme_titlebar import theme_title_bar
|
||||
|
||||
from modules.utils import configGet, configSet, get_string_mode, use_dark_mode
|
||||
from modules.logger import logger
|
||||
import requests
|
||||
import sv_ttk
|
||||
|
||||
|
||||
class FrameSettings(ThemedFrame):
|
||||
|
||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||
|
||||
super().__init__(master, **kwargs)
|
||||
|
||||
master.title("Configuration")
|
||||
|
||||
self.columnconfigure(0, weight=1)
|
||||
self.columnconfigure(1, weight=3)
|
||||
|
||||
master.columnconfigure(1, weight=1)
|
||||
|
||||
# Address
|
||||
self.address_label = ttk.Label(self, text="Address:")
|
||||
self.address_label.grid(column=0, row=0, sticky=W, padx=9, pady=9)
|
||||
|
||||
self.address_entry = ttk.Entry(self)
|
||||
self.address_entry.grid(column=1, row=0, sticky=N+S+E+W, padx=9, pady=9)
|
||||
if configGet("address") is not None:
|
||||
self.address_entry.insert(0, configGet("address"))
|
||||
# =======
|
||||
|
||||
# API Key
|
||||
self.apikey_label = ttk.Label(self, text="API key:")
|
||||
self.apikey_label.grid(column=0, row=1, sticky=W, padx=9, pady=9)
|
||||
|
||||
self.apikey_entry = ttk.Entry(self)
|
||||
self.apikey_entry.grid(column=1, row=1, sticky=N+S+E+W, padx=9, pady=9)
|
||||
if configGet("apikey") is not None:
|
||||
self.apikey_entry.insert(0, configGet("apikey"))
|
||||
# =======
|
||||
|
||||
# Self-signed
|
||||
if configGet("allow_self_signed") is not None:
|
||||
self.self_signed_check_bool = IntVar(value=int(configGet("allow_self_signed")))
|
||||
else:
|
||||
self.self_signed_check_bool = IntVar()
|
||||
self.self_signed_check = ttk.Checkbutton(self, text="Allow self-signed certificates", variable=self.self_signed_check_bool)
|
||||
self.self_signed_check.grid(column=1, row=2, sticky=W, padx=9, pady=9)
|
||||
# ===========
|
||||
|
||||
# Saves location
|
||||
self.saves_location_label = ttk.Label(self, text="Saves location:")
|
||||
self.saves_location_label.grid(column=0, row=3, sticky=W, padx=9, pady=9)
|
||||
|
||||
self.saves_frame = ThemedFrame(self)
|
||||
self.saves_frame.grid(column=1, row=3, sticky=N+S+E+W, padx=9, pady=9)
|
||||
self.saves_frame.grid_columnconfigure(0, weight=1)
|
||||
self.saves_frame.grid_columnconfigure(1, weight=3)
|
||||
|
||||
self.saves_location_entry = ttk.Entry(self.saves_frame, width=36)
|
||||
self.saves_location_entry.grid(column=0, row=0, sticky=NSEW)
|
||||
if configGet("saves_location") is not None:
|
||||
self.saves_location_entry.insert(0, configGet("saves_location"))
|
||||
|
||||
self.saves_location_button = ttk.Button(self.saves_frame, text="Browse", width=6, command=lambda:self.select_location(self.saves_location_entry))
|
||||
self.saves_location_button.grid(column=1, row=0, sticky=E)
|
||||
# ==============
|
||||
|
||||
# Saves location
|
||||
self.saves_location_label = ttk.Label(self, text="Color theme:")
|
||||
self.saves_location_label.grid(column=0, row=5, sticky=W, padx=9, pady=9)
|
||||
|
||||
if configGet("dark_mode_auto") is True:
|
||||
self.default_theme = "Auto "
|
||||
else:
|
||||
self.default_theme = "Dark " if configGet("dark_mode") is True else "Light "
|
||||
|
||||
self.chosen_theme = StringVar()
|
||||
self.themes = ("Auto ", "Light ", "Dark ")
|
||||
self.saves_location_button = ttk.OptionMenu(self, self.chosen_theme, self.default_theme, *self.themes, direction="below", command=self.change_theme)
|
||||
self.saves_location_button.grid(column=1, row=5, sticky=W, padx=9, pady=9)
|
||||
# ==============
|
||||
|
||||
self.buttons_frame = ThemedFrame(self)
|
||||
self.buttons_frame.grid(column=0, columnspan=2, sticky=NSEW, padx=9, pady=9)
|
||||
self.buttons_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.validate_button = ttk.Button(self.buttons_frame, text="Validate", width=11, command=self.validate_configuration)
|
||||
self.validate_button.grid(column=0, row=0, sticky=E, padx=9)
|
||||
|
||||
self.save_button = ttk.Button(self.buttons_frame, text="Save", style="Accent.TButton", width=11, state="disabled", command=self.save_configuration)
|
||||
self.save_button.grid(column=1, row=0, sticky=E)
|
||||
|
||||
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"
|
||||
else:
|
||||
self.chosen_theme_real = self.chosen_theme.get().strip().lower()
|
||||
theme_title_bar(self.master, self.chosen_theme_real)
|
||||
|
||||
def select_location(self, entry: ttk.Entry):
|
||||
|
||||
if path.exists(path.join(str(getenv("APPDATA")), "Stardew Valley")):
|
||||
self.path_start = path.join(str(getenv("APPDATA")), "Stardew Valley")
|
||||
elif path.exists(path.join(path.expanduser("~"), ".config", "Stardew Valley")):
|
||||
self.path_start = path.join(path.expanduser("~"), ".config", "Stardew Valley")
|
||||
else:
|
||||
self.path_start = None
|
||||
|
||||
self.path_dir = filedialog.askdirectory(initialdir=self.path_start, title="Select Stardew Valley Saves folder")
|
||||
|
||||
if self.path_dir != "":
|
||||
entry.delete(0, END)
|
||||
entry.insert(0, self.path_dir)
|
||||
|
||||
def save_configuration(self):
|
||||
|
||||
if len(self.address_entry.get()) > 0:
|
||||
if self.address_entry.get().endswith("/"):
|
||||
self.address_text = self.address_entry.get()[:-1]
|
||||
else:
|
||||
self.address_text = self.address_entry.get()
|
||||
else:
|
||||
self.address_text = None
|
||||
|
||||
configSet(["address"], self.address_text)
|
||||
configSet(["apikey"], self.apikey_entry.get())
|
||||
configSet(["allow_self_signed"], bool(self.self_signed_check_bool.get()))
|
||||
configSet(["saves_location"], self.saves_location_entry.get())
|
||||
|
||||
if self.chosen_theme.get().strip().lower() == "auto":
|
||||
configSet(["dark_mode_auto"], True)
|
||||
else:
|
||||
configSet(["dark_mode_auto"], False)
|
||||
if self.chosen_theme.get().strip().lower() == "dark":
|
||||
configSet(["dark_mode"], True)
|
||||
else:
|
||||
configSet(["dark_mode"], False)
|
||||
|
||||
# messagebox.showinfo(title="Configuration saved", message="Your client's configuration has been saved")
|
||||
|
||||
self.save_button.state(["disabled"])
|
||||
|
||||
self.master.item_saves.state(["!disabled"])
|
||||
self.master.item_devices.state(["!disabled"])
|
||||
|
||||
def validate_configuration(self):
|
||||
|
||||
if len(self.address_entry.get()) > 0:
|
||||
if self.address_entry.get().endswith("/"):
|
||||
self.address_text = self.address_entry.get()
|
||||
self.address_entry.delete(0, END)
|
||||
self.address_entry.insert(0, self.address_text[:-1])
|
||||
|
||||
try:
|
||||
requests.get(self.address_entry.get()+"/check", verify=not bool(self.self_signed_check_bool.get()))
|
||||
except (requests.exceptions.InvalidURL, requests.exceptions.InvalidSchema, requests.exceptions.MissingSchema) as exp:
|
||||
logger.error(f"Could not validate '{self.address_entry.get()}' due to {exp}")
|
||||
messagebox.showerror(title="Invalid address", message="Address entered does not seem to be correct one. Please provide API address starting with http:// or https:// \n\nFor example:\n- https://your-api.com:8043\n- https://your-api.com")
|
||||
return
|
||||
except (requests.exceptions.SSLError):
|
||||
logger.error(f"SSL certificate of '{self.address_entry.get()}' does not seem to be valid or is self-signed")
|
||||
messagebox.showerror(title="Invalid SSL", message="SSL certificate seems to be invalid or self-signed and thus won't be trusted. You can overwrite this by checking 'Allow self-signed certificates'.")
|
||||
return
|
||||
except Exception as exp:
|
||||
logger.error(f"Could not reach '{self.address_entry.get()}' due to {exp}")
|
||||
messagebox.showerror(title="Connection error", message="Address entered does not seem to be reachable. Please make sure you've entered the correct API address.")
|
||||
return
|
||||
|
||||
response_apikey = requests.get(self.address_entry.get()+"/apikey", headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
|
||||
|
||||
if response_apikey.status_code != 200:
|
||||
logger.error(f"API key seems to be invalid. API returned {response_apikey.status_code} as a status code")
|
||||
messagebox.showerror(title="Invalid apikey", message="API key provided does not seem to be valid. Please check for any mistakes and if none found - take a look at the docs to learn how to generate one.")
|
||||
return
|
||||
|
||||
if not path.exists(self.saves_location_entry.get()):
|
||||
logger.error(f"Path {self.saves_location_entry.get()} does not seem to exist")
|
||||
messagebox.showerror(title="Location error", message="Saves folder seems to be invalid. Please provide a valid directory path where Stardew Valley's save files (and folders) are stored.")
|
||||
return
|
||||
|
||||
configSet(["address"], self.address_entry.get())
|
||||
configSet(["apikey"], self.apikey_entry.get())
|
||||
configSet(["allow_self_signed"], bool(self.self_signed_check_bool.get()))
|
||||
configSet(["saves_location"], self.saves_location_entry.get())
|
||||
|
||||
self.save_button.state(["!disabled"])
|
||||
|
||||
messagebox.showinfo(title="Configuration completed", message="Your client is now configured and ready to use!")
|
@ -1,112 +0,0 @@
|
||||
from os import path
|
||||
from tkinter import END, E, IntVar, N, S, Toplevel, W, messagebox, ttk
|
||||
|
||||
import requests
|
||||
|
||||
from modules.theme_titlebar import theme_title_bar
|
||||
from modules.logger import logger
|
||||
from modules.utils import configGet, configSet, use_dark_mode
|
||||
|
||||
|
||||
class WindowConfig(Toplevel):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
||||
super().__init__(parent)
|
||||
|
||||
self.window_width = 430
|
||||
self.window_height = 247
|
||||
|
||||
self.screen_width = self.winfo_screenwidth()
|
||||
self.screen_height = self.winfo_screenheight()
|
||||
|
||||
self.center_x = int(self.screen_width/2 - self.window_width / 2)
|
||||
self.center_y = int(self.screen_height/2 - self.window_height / 2)
|
||||
|
||||
self.title("Configuration")
|
||||
self.geometry(f'{self.window_width}x{self.window_height}+{self.center_x}+{self.center_y}')
|
||||
self.resizable(False, False)
|
||||
self.iconbitmap(path.join("assets", "favicon.ico"))
|
||||
self.focus_set()
|
||||
|
||||
if use_dark_mode() is True:
|
||||
theme_title_bar(self, "dark")
|
||||
|
||||
self.columnconfigure(0, weight=1)
|
||||
self.columnconfigure(1, weight=3)
|
||||
|
||||
# Address
|
||||
self.address_label = ttk.Label(self, text="Address:")
|
||||
self.address_label.grid(column=0, row=0, sticky=W, padx=9, pady=9)
|
||||
|
||||
self.address_entry = ttk.Entry(self)
|
||||
self.address_entry.grid(column=1, row=0, sticky=N+S+E+W, padx=9, pady=9)
|
||||
if configGet("address") is not None:
|
||||
self.address_entry.insert(0, configGet("address"))
|
||||
# =======
|
||||
|
||||
# API Key
|
||||
self.apikey_label = ttk.Label(self, text="API key:")
|
||||
self.apikey_label.grid(column=0, row=1, sticky=W, padx=9, pady=9)
|
||||
|
||||
self.apikey_entry = ttk.Entry(self)
|
||||
self.apikey_entry.grid(column=1, row=1, sticky=N+S+E+W, padx=9, pady=9)
|
||||
if configGet("apikey") is not None:
|
||||
self.apikey_entry.insert(0, configGet("apikey"))
|
||||
# =======
|
||||
|
||||
# Self-signed
|
||||
if configGet("allow_self_signed") is not None:
|
||||
self.self_signed_check_bool = IntVar(value=int(configGet("allow_self_signed")))
|
||||
else:
|
||||
self.self_signed_check_bool = IntVar()
|
||||
self.self_signed_check = ttk.Checkbutton(self, text="Allow self-signed certificates", variable=self.self_signed_check_bool)
|
||||
self.self_signed_check.grid(column=1, row=2, sticky=W, padx=9, pady=9)
|
||||
# ===========
|
||||
|
||||
# Saves location
|
||||
self.saves_location_label = ttk.Label(self, text="Saves location:")
|
||||
self.saves_location_label.grid(column=0, row=3, sticky=W, padx=9, pady=9)
|
||||
|
||||
self.saves_location_button = ttk.Button(self, text="Browse", width=6)
|
||||
self.saves_location_button.grid(column=1, row=3, sticky=W, padx=9, pady=9)
|
||||
# ==============
|
||||
self.login_button = ttk.Button(self, text="Log in", style="Accent.TButton", width=10, command=self.validate_configuration)
|
||||
self.login_button.grid(column=1, row=4, sticky=E, padx=9, pady=9)
|
||||
|
||||
def validate_configuration(self):
|
||||
|
||||
if len(self.address_entry.get()) > 0:
|
||||
if self.address_entry.get().endswith("/"):
|
||||
self.address_text = self.address_entry.get()
|
||||
self.address_entry.delete(0, END)
|
||||
self.address_entry.insert(0, self.address_text[:-1])
|
||||
|
||||
try:
|
||||
requests.get(self.address_entry.get()+"/check", verify=not bool(self.self_signed_check_bool.get()))
|
||||
except (requests.exceptions.InvalidURL, requests.exceptions.InvalidSchema, requests.exceptions.MissingSchema) as exp:
|
||||
logger.error(f"Could not validate '{self.address_entry.get()}' due to {exp}")
|
||||
messagebox.showerror(title="Invalid address", message="Address entered does not seem to be correct one. Please provide API address starting with http:// or https:// \n\nFor example:\n- https://your-api.com:8043\n- https://your-api.com")
|
||||
return
|
||||
except (requests.exceptions.SSLError):
|
||||
logger.error(f"SSL certificate of '{self.address_entry.get()}' does not seem to be valid or is self-signed")
|
||||
messagebox.showerror(title="Invalid SSL", message="SSL certificate seems to be invalid or self-signed and thus won't be trusted. You can overwrite this by checking 'Allow self-signed certificates'.")
|
||||
return
|
||||
except Exception as exp:
|
||||
logger.error(f"Could not reach '{self.address_entry.get()}' due to {exp}")
|
||||
messagebox.showerror(title="Connection error", message="Address entered does not seem to be reachable. Please make sure you've entered the correct API address.")
|
||||
return
|
||||
|
||||
response_apikey = requests.get(self.address_entry.get()+"/apikey", headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
|
||||
|
||||
if response_apikey.status_code != 200:
|
||||
logger.error(f"API key seems to be invalid. API returned {response_apikey.status_code} as a status code")
|
||||
messagebox.showerror(title="Invalid apikey", message="API key provided does not seem to be valid. Please check for any mistakes and if none found - take a look at the docs to learn how to generate one.")
|
||||
return
|
||||
|
||||
configSet(["address"], self.address_entry.get())
|
||||
configSet(["apikey"], self.apikey_entry.get())
|
||||
configSet(["allow_self_signed"], bool(self.self_signed_check_bool.get()))
|
||||
|
||||
messagebox.showinfo(title="Configuration completed", message="Your client is now configured and ready to use!")
|
||||
self.destroy()
|
@ -1,5 +1,6 @@
|
||||
import platform
|
||||
import sys
|
||||
import sv_ttk
|
||||
from ctypes import byref, c_int, sizeof, windll
|
||||
from distutils.version import StrictVersion as Version
|
||||
from os import system
|
||||
@ -17,13 +18,17 @@ def theme_title_bar(window: Union[ThemedTk, Toplevel], mode: Literal["dark", "li
|
||||
|
||||
if mode == "dark":
|
||||
value = 1
|
||||
#window.configure(background="#1c1c1c")
|
||||
elif mode == "light":
|
||||
value = 0
|
||||
#window.configure(background="#ffffff")
|
||||
else:
|
||||
raise ValueError()
|
||||
|
||||
try:
|
||||
|
||||
sv_ttk.set_theme(mode)
|
||||
|
||||
window.update()
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
|
@ -1,5 +1,5 @@
|
||||
from json import JSONDecodeError, dumps, loads
|
||||
from typing import Any
|
||||
from typing import Any, Literal
|
||||
|
||||
import darkdetect
|
||||
|
||||
@ -69,14 +69,26 @@ def configGet(key: str, *args: str) -> Any:
|
||||
this_key = this_key[dict_key]
|
||||
return this_key[key]
|
||||
|
||||
def use_dark_mode() -> bool:
|
||||
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"
|
Loading…
Reference in New Issue
Block a user