Still WIP

This commit is contained in:
Profitroll
2023-01-23 00:13:30 +01:00
parent 021dbf560f
commit cab36a0fdb
6 changed files with 343 additions and 33 deletions

View File

@@ -1,11 +1,101 @@
from tkinter import EW, NS, ttk
from datetime import datetime
from functools import partial
from tkinter import LEFT, NSEW, E, W, ttk
from tkinter.messagebox import askyesno
import requests
from ttkthemes import ThemedTk
from classes.custom.scrollable_frame import ScrollableFrame
from classes.custom.themed_frame import ThemedFrame
from modules.utils import configGet
class FrameDevices(ThemedFrame):
class FrameDevices(ScrollableFrame):
def __init__(self, master: ThemedTk, devices: list, **kwargs) -> None:
super().__init__(master, **kwargs)
master.title("Devices - Stardew Sync")
# self["borderwidth"] = 1
# self["relief"] = "solid"
self.devices = devices
# self.grid_columnconfigure(0, weight=1)
# self.grid_rowconfigure(0, weight=2)
master.columnconfigure(1, weight=1)
self.render_devices()
def render_devices(self):
i = 0
for device in self.devices:
device_frame = ThemedFrame(self, style="Card.TFrame")
device_frame.grid(column=0, row=i, pady=9, padx=9, sticky=NSEW)
# self.device_frame["borderwidth"] = 1
# self.device_frame["relief"] = "solid"
device_frame.grid_columnconfigure(0, weight=1)
device_frame.grid_columnconfigure(1, weight=3)
device_frame.grid_columnconfigure(2, weight=3)
device_title = ttk.Label(device_frame, text=device["name"], font=("SunValleyBodyFont", 12), justify=LEFT, width=46)
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
last_upload = "N/A" if device["last_save"] == 0 else datetime.utcfromtimestamp(device["last_save"]).strftime("%d.%m.%Y %H:%M")
device_description = ttk.Label(device_frame, text=f'OS: {device["os"]}\nClient: {device["client"]}\nLast upload: {last_upload}', width=46)
device_description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
buttons_frame = ThemedFrame(device_frame)
buttons_frame.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
buttons_frame.grid_columnconfigure(0, weight=1)
button_device_rename = ttk.Button(buttons_frame, text="Rename", width=11)
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
button_device_delete_action = partial(self.device_delete, device["name"])
button_device_delete = ttk.Button(buttons_frame, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
button_device_delete.grid(column=1, row=0, sticky=W)
if device["name"] == configGet("name"):
button_device_rename.state(["disabled"])
button_device_delete.state(["disabled"])
i += 1
if i+1 != len(self.devices):
divider = ttk.Separator(self, orient="horizontal")
divider.grid(column=0, row=i+1, pady=9)
i += 1
def device_delete(self, name: str):
decision = askyesno(title="Device removal", message=f"You are about to remove the device '{name}' and this will also remove all the save files uploaded by this device. Are you sure you want to continue?")
if decision is False:
return
requests.delete(f'{configGet("address")}/devices/{name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
for k in range(len(self.devices)):
print(k)
if self.devices[k]["name"] == name:
del self.devices[k]
break
for widget in self.winfo_children():
widget.destroy()
self.render_devices()
class FrameDevicesEmpty(ThemedFrame):
def __init__(self, master: ThemedTk, **kwargs) -> None:
@@ -13,11 +103,13 @@ class FrameDevices(ThemedFrame):
master.title("Devices - Stardew Sync")
self["borderwidth"] = 2
self["relief"] = "solid"
# self["borderwidth"] = 1
# 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.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=2)
self.scrollbar = ttk.Scrollbar(self, orient="vertical")
self.scrollbar.grid(column=1, row=0, sticky=NS)
master.columnconfigure(1, weight=1)
self.label = ttk.Label(self, text="No devices found")
self.label.grid(column=0, row=0, padx=9, pady=9)

View File

@@ -1,4 +1,5 @@
from os import getenv, path
import platform
from tkinter import N, NSEW, S, W, E, END, IntVar, StringVar, filedialog, messagebox, ttk
from ttkthemes import ThemedTk
@@ -7,6 +8,7 @@ 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
from urllib.parse import urlencode, quote
import requests
import sv_ttk
@@ -17,29 +19,41 @@ class FrameSettings(ThemedFrame):
super().__init__(master, **kwargs)
master.title("Configuration")
master.title("Settings - Stardew Sync")
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=3)
master.columnconfigure(1, weight=1)
# 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_entry = ttk.Entry(self)
self.name_entry.grid(column=1, row=0, sticky=N+S+E+W, padx=9, pady=9)
if configGet("name") is not None:
self.name_entry.insert(0, configGet("name"))
else:
self.name_entry.insert(0, str(platform.node()))
# ====
# 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_label.grid(column=0, row=1, 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)
self.address_entry.grid(column=1, row=1, 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_label.grid(column=0, row=2, 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)
self.apikey_entry.grid(column=1, row=2, sticky=N+S+E+W, padx=9, pady=9)
if configGet("apikey") is not None:
self.apikey_entry.insert(0, configGet("apikey"))
# =======
@@ -50,19 +64,19 @@ class FrameSettings(ThemedFrame):
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)
self.self_signed_check.grid(column=1, row=3, 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_label.grid(column=0, row=4, 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(column=1, row=4, 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 = ttk.Entry(self.saves_frame, width=30)
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"))
@@ -87,7 +101,7 @@ class FrameSettings(ThemedFrame):
# ==============
self.buttons_frame = ThemedFrame(self)
self.buttons_frame.grid(column=0, columnspan=2, sticky=NSEW, padx=9, pady=9)
self.buttons_frame.grid(column=0, columnspan=2, row=6, 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)
@@ -129,7 +143,25 @@ class FrameSettings(ThemedFrame):
else:
self.address_text = None
configSet(["address"], self.address_text)
# =========================
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()))
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()))
else:
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()))
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()))
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()))
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()}")
return
# =========================
configSet(["name"], self.name_entry.get().strip())
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())
@@ -151,6 +183,11 @@ class FrameSettings(ThemedFrame):
self.master.item_devices.state(["!disabled"])
def validate_configuration(self):
if self.name_entry.get().strip() == "":
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.")
return
if len(self.address_entry.get()) > 0:
if self.address_entry.get().endswith("/"):
@@ -185,11 +222,15 @@ 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.")
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())
# =========================
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()))
if existing_device_after == 200:
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.")
return
# =========================
self.save_button.state(["!disabled"])
messagebox.showinfo(title="Configuration completed", message="Your client is now configured and ready to use!")
# messagebox.showinfo(title="Configuration completed", message="Your client is now configured and ready to use!")