Still WIP
This commit is contained in:
@@ -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)
|
@@ -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!")
|
Reference in New Issue
Block a user