WIP: Welcome dialog added

This commit is contained in:
Profitroll 2023-01-24 15:27:07 +01:00
parent 67270252d2
commit 6add3ac976
4 changed files with 329 additions and 61 deletions

View File

@ -8,7 +8,7 @@ from ttkthemes import ThemedTk
from classes.custom.scrollable_frame import FIT_HEIGHT, FIT_WIDTH from classes.custom.scrollable_frame import FIT_HEIGHT, FIT_WIDTH
from classes.custom.themed_frame import ThemedFrame from classes.custom.themed_frame import ThemedFrame
from classes.frames.devices import FrameDevices, FrameDevicesEmpty from classes.frames.devices import FrameDevices, FrameDevicesEmpty
from classes.frames.errors import FrameErrorConnection, FrameErrorSavesFolder, FrameErrorUnconfigured from classes.frames.errors import FrameErrorConnection, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured
from classes.frames.saves import FrameSaves from classes.frames.saves import FrameSaves
from classes.frames.settings import FrameSettings from classes.frames.settings import FrameSettings
from classes.toplevel.welcome import ToplevelWelcome from classes.toplevel.welcome import ToplevelWelcome
@ -119,6 +119,13 @@ class App(ThemedTk):
self.item_settings = ttk.Button(self.frame_sidebar, text="Settings", width=10, command=self.frame_settings) 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_settings.grid(column=0, row=2, sticky=W+S, padx=9, pady=9)
if configGet("first_run") is True:
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)
self.connection_error = FrameErrorFirstStart(self)
self.connection_error.grid(column=1, row=0, rowspan=2, sticky=N+S+W+E)
return
if configGet("address") in ["", None] or configGet("apikey") in ["", None]: if configGet("address") in ["", None] or configGet("apikey") in ["", None]:
self.item_saves.state(["disabled"]) self.item_saves.state(["disabled"])
self.item_devices.state(["disabled"]) self.item_devices.state(["disabled"])

View File

@ -46,6 +46,26 @@ class FrameErrorConnection(ThemedFrame):
self.button_settings.grid(column=1, row=0, padx=9, pady=9) self.button_settings.grid(column=1, row=0, padx=9, pady=9)
class FrameErrorFirstStart(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="Setup completed")
self.label.grid(column=0, row=0, padx=9, pady=9, sticky=S)
self.button_settings = ttk.Button(self, text="Refresh", style="Accent.TButton", width=10, command=lambda:try_connecting(master))
self.button_settings.grid(column=0, row=1, sticky=N)
class FrameErrorSavesFolder(ThemedFrame): class FrameErrorSavesFolder(ThemedFrame):
def __init__(self, master: ThemedTk, **kwargs) -> None: def __init__(self, master: ThemedTk, **kwargs) -> None:

View File

@ -27,33 +27,33 @@ class FrameSettings(ThemedFrame):
master.columnconfigure(1, weight=1) master.columnconfigure(1, weight=1)
# Name # Name
self.name_label = ttk.Label(self, text="Name:") # self.name_label = ttk.Label(self, text="Name:")
self.name_label.grid(column=0, row=0, sticky=W, padx=9, pady=9) # self.name_label.grid(column=0, row=0, sticky=W, padx=9, pady=9)
self.name_entry = ttk.Entry(self) # self.name_entry = ttk.Entry(self)
self.name_entry.grid(column=1, row=0, sticky=N+S+E+W, padx=9, pady=9) # self.name_entry.grid(column=1, row=0, sticky=N+S+E+W, padx=9, pady=9)
if configGet("name") is not None: # if configGet("name") is not None:
self.name_entry.insert(0, configGet("name")) # self.name_entry.insert(0, configGet("name"))
else: # else:
self.name_entry.insert(0, str(platform.node())) # self.name_entry.insert(0, str(platform.node()))
# ==== # ====
# Address # Address
self.address_label = ttk.Label(self, text="Address:") self.address_label = ttk.Label(self, text="Address:")
self.address_label.grid(column=0, row=1, sticky=W, padx=9, pady=9) self.address_label.grid(column=0, row=0, sticky=W, padx=9, pady=9)
self.address_entry = ttk.Entry(self) self.address_entry = ttk.Entry(self)
self.address_entry.grid(column=1, row=1, sticky=N+S+E+W, padx=9, pady=9) self.address_entry.grid(column=1, row=0, sticky=N+S+E+W, padx=9, pady=9)
if configGet("address") is not None: if configGet("address") is not None:
self.address_entry.insert(0, configGet("address")) self.address_entry.insert(0, configGet("address"))
# ======= # =======
# API Key # API Key
self.apikey_label = ttk.Label(self, text="API key:") self.apikey_label = ttk.Label(self, text="API key:")
self.apikey_label.grid(column=0, row=2, sticky=W, padx=9, pady=9) self.apikey_label.grid(column=0, row=1, sticky=W, padx=9, pady=9)
self.apikey_entry = ttk.Entry(self) self.apikey_entry = ttk.Entry(self)
self.apikey_entry.grid(column=1, row=2, sticky=N+S+E+W, padx=9, pady=9) self.apikey_entry.grid(column=1, row=1, sticky=N+S+E+W, padx=9, pady=9)
if configGet("apikey") is not None: if configGet("apikey") is not None:
self.apikey_entry.insert(0, configGet("apikey")) self.apikey_entry.insert(0, configGet("apikey"))
# ======= # =======
@ -64,15 +64,15 @@ class FrameSettings(ThemedFrame):
else: else:
self.self_signed_check_bool = IntVar() 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 = ttk.Checkbutton(self, text="Allow self-signed certificates", variable=self.self_signed_check_bool)
self.self_signed_check.grid(column=1, row=3, sticky=W, padx=9, pady=9) self.self_signed_check.grid(column=1, row=2, sticky=W, padx=9, pady=9)
# =========== # ===========
# Saves location # Saves location
self.saves_location_label = ttk.Label(self, text="Saves location:") self.saves_location_label = ttk.Label(self, text="Saves location:")
self.saves_location_label.grid(column=0, row=4, sticky=W, padx=9, pady=9) self.saves_location_label.grid(column=0, row=3, sticky=W, padx=9, pady=9)
self.saves_frame = ThemedFrame(self) self.saves_frame = ThemedFrame(self)
self.saves_frame.grid(column=1, row=4, sticky=N+S+E+W, padx=9, pady=9) 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(0, weight=1)
self.saves_frame.grid_columnconfigure(1, weight=3) self.saves_frame.grid_columnconfigure(1, weight=3)
@ -85,9 +85,9 @@ class FrameSettings(ThemedFrame):
self.saves_location_button.grid(column=1, row=0, sticky=E) self.saves_location_button.grid(column=1, row=0, sticky=E)
# ============== # ==============
# Saves location # Software theme
self.saves_location_label = ttk.Label(self, text="Color theme:") 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) self.saves_location_label.grid(column=0, row=4, sticky=W, padx=9, pady=9)
if configGet("dark_mode_auto") is True: if configGet("dark_mode_auto") is True:
self.default_theme = "Auto " self.default_theme = "Auto "
@ -97,11 +97,11 @@ class FrameSettings(ThemedFrame):
self.chosen_theme = StringVar() self.chosen_theme = StringVar()
self.themes = ("Auto ", "Light ", "Dark ") 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 = 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.saves_location_button.grid(column=1, row=4, sticky=W, padx=9, pady=9)
# ============== # ==============
self.buttons_frame = ThemedFrame(self) self.buttons_frame = ThemedFrame(self)
self.buttons_frame.grid(column=0, columnspan=2, row=6, sticky=NSEW, padx=9, pady=9) self.buttons_frame.grid(column=0, columnspan=2, row=5, sticky=NSEW, padx=9, pady=9)
self.buttons_frame.grid_columnconfigure(0, weight=1) 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 = ttk.Button(self.buttons_frame, text="Validate", width=11, command=self.validate_configuration)
@ -143,24 +143,24 @@ class FrameSettings(ThemedFrame):
else: else:
self.address_text = None self.address_text = None
# ========================= # # =========================
if self.name_entry.get().strip() == configGet("name"): # if self.name_entry.get().strip() == configGet("name"):
existing_device = requests.get(f'{self.address_entry.get()}/devices/{quote(configGet("name").encode("utf-8"))}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get())) # existing_device = requests.get(f'{self.address_entry.get()}/devices/{quote(configGet("name").encode("utf-8"))}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
if existing_device.status_code != 200: # if existing_device.status_code != 200:
requests.post(f'{self.address_entry.get()}/devices?{urlencode({"name": quote(configGet("name").encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get())) # requests.post(f'{self.address_entry.get()}/devices?{urlencode({"name": quote(configGet("name").encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
else: # else:
if configGet("name") is not None: # if configGet("name") is not None:
existing_device_before = requests.get(f'{self.address_entry.get()}/devices/{quote(configGet("name").encode("utf-8"))}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get())) # existing_device_before = requests.get(f'{self.address_entry.get()}/devices/{quote(configGet("name").encode("utf-8"))}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
if existing_device_before.status_code == 200: # if existing_device_before.status_code == 200:
requests.patch(f'{self.address_entry.get()}/devices/{quote(configGet("name").encode("utf-8"))}?{urlencode({"new_name": quote(self.name_entry.get().strip().encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get())) # requests.patch(f'{self.address_entry.get()}/devices/{quote(configGet("name").encode("utf-8"))}?{urlencode({"new_name": quote(self.name_entry.get().strip().encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
else: # else:
device_created = requests.post(f'{self.address_entry.get()}/devices?{urlencode({"name": quote(self.name_entry.get().strip().encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get())) # device_created = requests.post(f'{self.address_entry.get()}/devices?{urlencode({"name": quote(self.name_entry.get().strip().encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
if device_created.status_code != 204: # if device_created.status_code != 204:
messagebox.showerror(title="Name error", message=f"Could not register device in database using name '{self.name_entry.get().strip()}' with error:\n\n{device_created.json()}") # messagebox.showerror(title="Name error", message=f"Could not register device in database using name '{self.name_entry.get().strip()}' with error:\n\n{device_created.json()}")
return # return
# ========================= # # =========================
configSet(["name"], self.name_entry.get().strip()) # configSet(["name"], self.name_entry.get().strip())
configSet(["address"], self.address_entry.get()) configSet(["address"], self.address_entry.get())
configSet(["apikey"], self.apikey_entry.get()) configSet(["apikey"], self.apikey_entry.get())
configSet(["allow_self_signed"], bool(self.self_signed_check_bool.get())) configSet(["allow_self_signed"], bool(self.self_signed_check_bool.get()))
@ -184,10 +184,10 @@ class FrameSettings(ThemedFrame):
def validate_configuration(self): def validate_configuration(self):
if self.name_entry.get().strip() == "": # if self.name_entry.get().strip() == "":
logger.error(f"Name {self.name_entry.get().strip()} is not a valid name") # logger.error(f"Name {self.name_entry.get().strip()} is not a valid name")
messagebox.showerror(title="Name error", message="Provided device name is not valid. Please provide a valid one.") # messagebox.showerror(title="Name error", message="Provided device name is not valid. Please provide a valid one.")
return # return
if len(self.address_entry.get()) > 0: if len(self.address_entry.get()) > 0:
if self.address_entry.get().endswith("/"): if self.address_entry.get().endswith("/"):
@ -222,14 +222,14 @@ class FrameSettings(ThemedFrame):
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.") 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 return
# ========================= # # =========================
if self.name_entry.get().strip() != configGet("name"): # if self.name_entry.get().strip() != configGet("name"):
existing_device_after = requests.get(f'{self.address_entry.get()}/devices/{self.name_entry.get().strip()}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get())) # existing_device_after = requests.get(f'{self.address_entry.get()}/devices/{self.name_entry.get().strip()}', headers={"apikey": self.apikey_entry.get()}, verify=not bool(self.self_signed_check_bool.get()))
if existing_device_after == 200: # if existing_device_after == 200:
logger.error(f"Device with name {self.name_entry.get().strip()} already exists") # logger.error(f"Device with name {self.name_entry.get().strip()} already exists")
messagebox.showerror(title="Name error", message=f"Device with name '{self.name_entry.get().strip()}' already exists on the server. Please choose another name or rename that device first.") # messagebox.showerror(title="Name error", message=f"Device with name '{self.name_entry.get().strip()}' already exists on the server. Please choose another name or rename that device first.")
return # return
# ========================= # # =========================
self.save_button.state(["!disabled"]) self.save_button.state(["!disabled"])

View File

@ -1,5 +1,7 @@
from os import path from os import getenv, path
from tkinter import CENTER, END, E, LEFT, NSEW, Image, IntVar, N, S, PhotoImage, Toplevel, W, messagebox, ttk import platform
from tkinter import CENTER, END, E, LEFT, NSEW, Image, IntVar, N, S, PhotoImage, StringVar, Toplevel, W, filedialog, messagebox, ttk
from urllib.parse import quote, urlencode
import requests import requests
import sv_ttk import sv_ttk
@ -41,8 +43,8 @@ class ToplevelWelcome(ThemedToplevel):
self.window_frame = ThemedFrame(self) self.window_frame = ThemedFrame(self)
self.window_frame.grid(column=0, row=0, sticky=NSEW) self.window_frame.grid(column=0, row=0, sticky=NSEW)
self.window_frame["borderwidth"] = 1 # self.window_frame["borderwidth"] = 1
self.window_frame["relief"] = "solid" # self.window_frame["relief"] = "solid"
self.window_frame.grid_columnconfigure(0, weight=1) self.window_frame.grid_columnconfigure(0, weight=1)
@ -69,22 +71,261 @@ class ToplevelWelcome(ThemedToplevel):
#self.window_frame.grid_rowconfigure(2, weight=3) #self.window_frame.grid_rowconfigure(2, weight=3)
self.stage_label = ttk.Label(self.window_frame, text="Connection", font=("SunValleyBodyFont", 14)) self.stage_label = ttk.Label(self.window_frame, text="Connection", font=("SunValleyBodyFont", 14))
self.stage_label.grid(column=0, row=0, pady=40) self.stage_label.grid(column=0, row=0, pady=29)
self.stage_label_1 = ttk.Label(self.window_frame, text="Server address", justify=LEFT) self.stage_label_1 = ttk.Label(self.window_frame, text="Server address", justify=LEFT)
self.stage_label_1.grid(column=0, row=1, pady=5, padx=35, sticky=W) self.stage_label_1.grid(column=0, row=1, padx=35, pady=5, sticky=W)
self.stage_entry_1 = ttk.Entry(self.window_frame) self.stage_entry_1 = ttk.Entry(self.window_frame)
self.stage_entry_1.grid(column=0, row=2, pady=5, padx=35, sticky=W+E) self.stage_entry_1.grid(column=0, row=2, padx=35, pady=5, sticky=W+E)
self.stage_label_1 = ttk.Label(self.window_frame, text="Personal API key", justify=LEFT) self.stage_label_2 = ttk.Label(self.window_frame, text="Personal API key", justify=LEFT)
self.stage_label_1.grid(column=0, row=3, pady=5, padx=35, sticky=W) self.stage_label_2.grid(column=0, row=3, padx=35, pady=5, sticky=W)
self.stage_entry_2 = ttk.Entry(self.window_frame)
self.stage_entry_2.grid(column=0, row=4, padx=35, pady=5, sticky=W+E)
self.stage_checkbox_var = IntVar()
self.stage_checkbox = ttk.Checkbutton(self.window_frame, text="Allow self-signed certificates", variable=self.stage_checkbox_var)
self.stage_checkbox.grid(column=0, row=5, sticky=W, padx=35, pady=9)
self.stage_button = ttk.Button(self.window_frame, text="Continue", style="Accent.TButton", width=10, command=self.stage_address_validate)
self.stage_button.grid(column=0, row=6, pady=28)
def stage_address_validate(self):
if len(self.stage_entry_1.get()) > 0:
if self.stage_entry_1.get().endswith("/"):
self.address_text = self.stage_entry_1.get()
self.stage_entry_1.delete(0, END)
self.stage_entry_1.insert(0, self.address_text[:-1])
try:
requests.get(self.stage_entry_1.get()+"/check", verify=not bool(self.stage_checkbox_var.get()))
except (requests.exceptions.InvalidURL, requests.exceptions.InvalidSchema, requests.exceptions.MissingSchema) as exp:
logger.error(f"Could not validate '{self.stage_entry_1.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.stage_entry_1.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.stage_entry_1.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.stage_entry_1.get()+"/apikey", headers={"apikey": self.stage_entry_2.get()}, verify=not bool(self.stage_checkbox_var.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.stage_entry_1.get())
configSet(["apikey"], self.stage_entry_2.get())
configSet(["allow_self_signed"], bool(self.stage_checkbox_var.get()))
self.stage_name()
def stage_name(self):
for widget in self.window_frame.winfo_children():
widget.destroy()
self.window_frame.grid_rowconfigure(0, weight=2)
self.window_frame.grid_rowconfigure(1, weight=2)
self.stage_label = ttk.Label(self.window_frame, text="Connection", font=("SunValleyBodyFont", 14))
self.stage_label.grid(column=0, row=0, pady=29)
self.divider_1 = ttk.Separator(self.window_frame)
self.divider_1.grid(column=0, row=1, pady=15)
self.stage_label_1 = ttk.Label(self.window_frame, text="Device name", justify=LEFT)
self.stage_label_1.grid(column=0, row=2, padx=35, pady=5, sticky=W)
self.stage_entry_1 = ttk.Entry(self.window_frame) self.stage_entry_1 = ttk.Entry(self.window_frame)
self.stage_entry_1.grid(column=0, row=4, pady=5, padx=35, sticky=W+E) self.stage_entry_1.grid(column=0, row=3, padx=35, pady=5, sticky=W+E)
self.stage_entry_1.insert(0, str(platform.node()))
self.stage_button = ttk.Button(self.window_frame, text="Continue", style="Accent.TButton", width=10) self.divider_2 = ttk.Separator(self.window_frame)
self.stage_button.grid(column=0, row=5, pady=40) self.divider_2.grid(column=0, row=4, pady=40)
self.stage_button = ttk.Button(self.window_frame, text="Continue", style="Accent.TButton", width=10, command=self.stage_name_validate)
self.stage_button.grid(column=0, row=5, pady=28)
def stage_name_validate(self):
if self.stage_entry_1.get().strip() == "":
logger.error(f"Name {self.stage_entry_1.get().strip()} is not a valid name")
messagebox.showerror(title="Name error", message="Provided device name is not valid. Please provide a valid one.")
return
try:
quote(self.stage_entry_1.get().strip())
except:
logger.error(f"Name {self.stage_entry_1.get().strip()} is not a valid name")
messagebox.showerror(title="Name error", message="Provided device name is not valid. Please provide a valid one.")
return
if self.stage_entry_1.get().strip() == configGet("name"):
existing_device = requests.get(f'{configGet("address")}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
if existing_device.status_code != 200:
requests.post(f'{configGet("address")}/devices?{urlencode({"name": quote(configGet("name").encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
else:
if configGet("name") is not None:
existing_device_before = requests.get(f'{configGet("address")}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
if existing_device_before.status_code == 200:
requests.patch(f'{configGet("address")}?{urlencode({"new_name": quote(self.stage_entry_1.get().strip().encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
else:
device_created = requests.post(f'{configGet("address")}/devices?{urlencode({"name": quote(self.stage_entry_1.get().strip().encode("utf-8")), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.__version__}"})}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
if device_created.status_code != 204:
messagebox.showerror(title="Name error", message=f"Could not register device in database using name '{self.stage_entry_1.get().strip()}' with error:\n\n{device_created.json()}")
return
configSet(["name"], self.stage_entry_1.get().strip())
self.stage_location()
def stage_location(self):
for widget in self.window_frame.winfo_children():
widget.destroy()
self.window_frame.grid_rowconfigure(0, weight=2)
self.window_frame.grid_rowconfigure(1, weight=2)
self.stage_label = ttk.Label(self.window_frame, text="Local saves", font=("SunValleyBodyFont", 14))
self.stage_label.grid(column=0, row=0, pady=29)
self.divider_1 = ttk.Separator(self.window_frame)
self.divider_1.grid(column=0, row=1, pady=15)
self.stage_label_1 = ttk.Label(self.window_frame, text="Save files location", justify=LEFT)
self.stage_label_1.grid(column=0, row=2, padx=35, pady=5, sticky=W)
self.stage_frame = ThemedFrame(self.window_frame)
self.stage_frame.grid(column=0, row=3, padx=35, pady=5, sticky=W+E)
self.stage_frame.grid_columnconfigure(0, weight=2)
# self.saves_frame.grid_columnconfigure(1, weight=3)
self.stage_entry_1 = ttk.Entry(self.stage_frame)
self.stage_entry_1.grid(column=0, row=0, sticky=W+E)
self.divider_2 = ttk.Separator(self.stage_frame, orient="vertical")
self.divider_2.grid(column=1, row=0, padx=3)
self.saves_location_button = ttk.Button(self.stage_frame, text="Browse", width=6, command=lambda:self.stage_location_select_location(self.stage_entry_1))
self.saves_location_button.grid(column=2, row=0, sticky=E)
self.divider_3 = ttk.Separator(self.window_frame)
self.divider_3.grid(column=0, row=4, pady=40)
self.stage_button = ttk.Button(self.window_frame, text="Continue", style="Accent.TButton", width=10, command=self.stage_location_validate)
self.stage_button.grid(column=0, row=5, pady=26)
def stage_location_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 stage_location_validate(self):
if not path.exists(self.stage_entry_1.get()):
logger.error(f"Path {self.stage_entry_1.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(["saves_location"], self.stage_entry_1.get())
self.stage_theme()
def stage_theme(self):
for widget in self.window_frame.winfo_children():
widget.destroy()
self.window_frame.grid_rowconfigure(0, weight=2)
self.window_frame.grid_rowconfigure(1, weight=2)
self.stage_label = ttk.Label(self.window_frame, text="Almost there", font=("SunValleyBodyFont", 14))
self.stage_label.grid(column=0, row=0, pady=29)
self.divider_1 = ttk.Separator(self.window_frame)
self.divider_1.grid(column=0, row=1, pady=15)
self.stage_label_1 = ttk.Label(self.window_frame, text="Theme", justify=CENTER)
self.stage_label_1.grid(column=0, row=2, padx=35, pady=5)
self.stage_option_menu_var = StringVar()
self.themes = ("Auto ", "Light ", "Dark ")
self.stage_option_menu = ttk.OptionMenu(self.window_frame, self.stage_option_menu_var, "Auto ", *self.themes, direction="below", command=self.change_theme)
self.stage_option_menu.grid(column=0, row=3, padx=35, pady=5)
self.divider_2 = ttk.Separator(self.window_frame)
self.divider_2.grid(column=0, row=4, pady=40)
self.stage_button = ttk.Button(self.window_frame, text="Continue", style="Accent.TButton", width=10, command=self.stage_theme_validate)
self.stage_button.grid(column=0, row=5, pady=28)
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"
else:
self.stage_option_menu_var_real = self.stage_option_menu_var.get().strip().lower()
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":
configSet(["dark_mode_auto"], True)
else:
configSet(["dark_mode_auto"], False)
if self.stage_option_menu_var.get().strip().lower() == "dark":
configSet(["dark_mode"], True)
else:
configSet(["dark_mode"], False)
self.stage_mobile_app()
def stage_mobile_app(self):
# To Do
self.stage_completed()
def stage_completed(self):
for widget in self.window_frame.winfo_children():
widget.destroy()
self.window_frame.grid_columnconfigure(0, weight=1)
self.welcome_pic = ImageLabel(self.window_frame)
self.welcome_pic.grid(column=0, row=0, pady=20)
self.welcome_pic.load(path.join("assets", "welcome.gif"))
self.welcome_text = ttk.Label(self.window_frame, text="You're all set!", font=("SunValleyBodyFont", 14))
self.welcome_text.grid(column=0, row=1, pady=10)
self.welcome_subtext = ttk.Label(self.window_frame, text="Configuration step is completed.\nYou can now jump into app and enjoy your\nsave files synchronization", justify=CENTER)
self.welcome_subtext.grid(column=0, row=2)
self.welcome_button = ttk.Button(self.window_frame, text="Finish", style="Accent.TButton", width=10, command=self.acknowledged)
self.welcome_button.grid(column=0, row=3, pady=20)
def acknowledged(self): def acknowledged(self):
configSet(["first_run"], False) configSet(["first_run"], False)