WIP: Saves windows
This commit is contained in:
parent
3666db25c6
commit
b1aeb06a09
@ -9,7 +9,7 @@ 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, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured
|
from classes.frames.errors import FrameErrorConnection, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured
|
||||||
from classes.frames.saves import FrameSaves
|
from classes.frames.saves import FrameSaves, FrameSavesEmpty
|
||||||
from classes.frames.settings import FrameSettings
|
from classes.frames.settings import FrameSettings
|
||||||
from classes.toplevel.welcome import ToplevelWelcome
|
from classes.toplevel.welcome import ToplevelWelcome
|
||||||
from modules.theme_titlebar import theme_title_bar
|
from modules.theme_titlebar import theme_title_bar
|
||||||
@ -25,11 +25,11 @@ class App(ThemedTk):
|
|||||||
self.__version__ = "0.1.0"
|
self.__version__ = "0.1.0"
|
||||||
|
|
||||||
resize_window(self, 610, 400)
|
resize_window(self, 610, 400)
|
||||||
|
self.resizable(False, True)
|
||||||
|
self.minsize(610, 200)
|
||||||
|
|
||||||
self.title("Stardew Sync")
|
self.title("Stardew Sync")
|
||||||
|
|
||||||
self.resizable(False, True)
|
|
||||||
|
|
||||||
sv_ttk.init_theme(self)
|
sv_ttk.init_theme(self)
|
||||||
|
|
||||||
if use_dark_mode():
|
if use_dark_mode():
|
||||||
@ -63,7 +63,11 @@ class App(ThemedTk):
|
|||||||
def frame_saves(self):
|
def frame_saves(self):
|
||||||
self.grid_rowconfigure(0, weight=1)
|
self.grid_rowconfigure(0, weight=1)
|
||||||
self.grid_columnconfigure(1, weight=1)
|
self.grid_columnconfigure(1, weight=1)
|
||||||
self.frame_saves_object = FrameSaves(self)
|
self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
||||||
|
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:
|
||||||
|
self.frame_saves_object = FrameSavesEmpty(self)
|
||||||
self.frame_saves_object.grid(column=1, row=0, sticky=NSEW)
|
self.frame_saves_object.grid(column=1, row=0, sticky=NSEW)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -73,12 +77,8 @@ class App(ThemedTk):
|
|||||||
self.frame_devices_devices = requests.get(f'{configGet("address")}/devices', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
self.frame_devices_devices = requests.get(f'{configGet("address")}/devices', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
||||||
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:
|
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)
|
self.frame_devices_object = FrameDevices(self, self.frame_devices_devices.json(), vscroll=True)
|
||||||
# self.frame_devices_object.resize(FIT_HEIGHT)
|
|
||||||
else:
|
else:
|
||||||
self.frame_devices_object = FrameDevicesEmpty(self)
|
self.frame_devices_object = FrameDevicesEmpty(self)
|
||||||
#self.frame_devices_object = FrameDevices(self, hscroll=False, vscroll=True)
|
|
||||||
#self.frame_devices_object.resize(FIT_WIDTH)
|
|
||||||
#self.frame_devices_object.resize(FIT_HEIGHT)
|
|
||||||
self.frame_devices_object.grid(column=1, row=0, sticky=NSEW)
|
self.frame_devices_object.grid(column=1, row=0, sticky=NSEW)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
148
classes/frames/device.py
Normal file
148
classes/frames/device.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import platform
|
||||||
|
from datetime import datetime
|
||||||
|
from functools import partial
|
||||||
|
from tkinter import LEFT, NSEW, E, Misc, W, messagebox, ttk
|
||||||
|
from tkinter.messagebox import askyesno
|
||||||
|
from urllib.parse import quote, urlencode
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from classes.custom.themed_frame import ThemedFrame
|
||||||
|
from modules.logger import logger
|
||||||
|
from modules.utils import configGet, configSet
|
||||||
|
|
||||||
|
|
||||||
|
class FrameDevice(ThemedFrame):
|
||||||
|
|
||||||
|
def __init__(self, master: Misc, device_dict: str, **kwargs) -> None:
|
||||||
|
|
||||||
|
super().__init__(master, style="Card.TFrame", **kwargs)
|
||||||
|
|
||||||
|
self.grid_columnconfigure(0, weight=1)
|
||||||
|
self.grid_columnconfigure(1, weight=3)
|
||||||
|
self.grid_columnconfigure(2, weight=3)
|
||||||
|
|
||||||
|
self.name = device_dict["name"]
|
||||||
|
|
||||||
|
self.title = ttk.Label(self, text=self.name, font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=46)
|
||||||
|
self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
last_upload = "N/A" if device_dict["last_save"] == 0 else datetime.utcfromtimestamp(device_dict["last_save"]).strftime("%d.%m.%Y %H:%M")
|
||||||
|
self.description = ttk.Label(self, text=f'OS: {device_dict["os"]}\nClient: {device_dict["client"]}\nLast upload: {last_upload}', width=46)
|
||||||
|
self.description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
self.buttons = ThemedFrame(self)
|
||||||
|
self.buttons.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
|
||||||
|
self.buttons.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
self.button_device_rename_action = partial(self.rename)
|
||||||
|
self.button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=self.button_device_rename_action)
|
||||||
|
self.button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
||||||
|
|
||||||
|
self.button_device_delete_action = partial(self.delete)
|
||||||
|
self.button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=self.button_device_delete_action)
|
||||||
|
self.button_device_delete.grid(column=1, row=0, sticky=W)
|
||||||
|
|
||||||
|
if self.name == configGet("name"):
|
||||||
|
self.button_device_delete.state(["disabled"])
|
||||||
|
|
||||||
|
def rename(self):
|
||||||
|
|
||||||
|
self.rename_entry = ttk.Entry(self, font=("SunValleyBodyFont", 12), justify=LEFT, width=27)
|
||||||
|
self.rename_entry.insert(0, self.name)
|
||||||
|
self.rename_entry.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
button_device_cancel_action = partial(self.rename_cancel)
|
||||||
|
button_device_cancel = ttk.Button(self.buttons, text="Cancel", width=11, command=button_device_cancel_action)
|
||||||
|
button_device_cancel.grid(column=0, row=0, padx=9, sticky=E)
|
||||||
|
|
||||||
|
button_device_save_action = partial(self.rename_verify)
|
||||||
|
button_device_save = ttk.Button(self.buttons, text="Save", style="Accent.TButton", width=11, command=button_device_save_action)
|
||||||
|
button_device_save.grid(column=1, row=0, sticky=W)
|
||||||
|
|
||||||
|
def rename_verify(self):
|
||||||
|
|
||||||
|
self.name_before = configGet("name")
|
||||||
|
|
||||||
|
if (self.rename_entry.get().strip() == "") or ("?" in self.rename_entry.get().strip()) or ("/" in self.rename_entry.get().strip()):
|
||||||
|
logger.error(f"Name {self.rename_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
|
||||||
|
|
||||||
|
try:
|
||||||
|
quote(self.rename_entry.get().strip())
|
||||||
|
except:
|
||||||
|
logger.error(f"Name {self.rename_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
|
||||||
|
|
||||||
|
existing_device_before = requests.get(f'{configGet("address")}/devices/{self.name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
||||||
|
if existing_device_before.status_code == 200:
|
||||||
|
response = requests.patch(f'{configGet("address")}/devices/{self.name}?{urlencode({"new_name": self.rename_entry.get().strip(), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.master.master.master.__version__}"})}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
||||||
|
if response.status_code != 204:
|
||||||
|
logger.error(f"Name {self.rename_entry.get().strip()} could not be set because server returned {response.status_code}")
|
||||||
|
messagebox.showerror(title="Name error", message=f"Provided device name is not valid.\n\nServer response: {response.json()}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logger.error(f"Tried to rename {self.name} into {self.rename_entry.get().strip()} but server returned {existing_device_before.status_code}")
|
||||||
|
messagebox.showerror(title="Rename error", message="It seems like this device no longer exists.")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.name = self.rename_entry.get().strip()
|
||||||
|
|
||||||
|
for widget in self.winfo_children():
|
||||||
|
if isinstance(widget, ttk.Entry):
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
|
device_title = ttk.Label(self, text=self.name, font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=46)
|
||||||
|
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
button_device_rename_action = partial(self.rename)
|
||||||
|
button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=button_device_rename_action)
|
||||||
|
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
||||||
|
|
||||||
|
button_device_delete_action = partial(self.delete)
|
||||||
|
button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
|
||||||
|
button_device_delete.grid(column=1, row=0, sticky=W)
|
||||||
|
|
||||||
|
if self.name_before == configGet("name"):
|
||||||
|
configSet(["name"], self.name)
|
||||||
|
|
||||||
|
if self.name == configGet("name"):
|
||||||
|
button_device_delete.state(["disabled"])
|
||||||
|
|
||||||
|
def rename_cancel(self):
|
||||||
|
|
||||||
|
for widget in self.winfo_children():
|
||||||
|
if isinstance(widget, ttk.Entry):
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
|
device_title = ttk.Label(self, text=self.name, font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=46)
|
||||||
|
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
button_device_rename_action = partial(self.rename)
|
||||||
|
button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=button_device_rename_action)
|
||||||
|
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
||||||
|
|
||||||
|
button_device_delete_action = partial(self.delete)
|
||||||
|
button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
|
||||||
|
button_device_delete.grid(column=1, row=0, sticky=W)
|
||||||
|
|
||||||
|
if self.name == configGet("name"):
|
||||||
|
button_device_delete.state(["disabled"])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
|
||||||
|
decision = askyesno(title="Device removal", message=f"You are about to remove the device '{self.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/{self.name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
||||||
|
|
||||||
|
for k in range(len(self.master.devices)):
|
||||||
|
if self.master.devices[k]["name"] == self.name:
|
||||||
|
del self.master.devices[k]
|
||||||
|
break
|
||||||
|
|
||||||
|
self.destroy()
|
@ -1,159 +1,10 @@
|
|||||||
from datetime import datetime
|
from tkinter import NSEW, ttk
|
||||||
from functools import partial
|
|
||||||
import platform
|
|
||||||
from tkinter import LEFT, NSEW, E, W, Misc, StringVar, ttk
|
|
||||||
from tkinter import messagebox
|
|
||||||
from tkinter.messagebox import askyesno, showinfo
|
|
||||||
from tkinter.simpledialog import askstring
|
|
||||||
from urllib.parse import quote, urlencode
|
|
||||||
|
|
||||||
import requests
|
|
||||||
from ttkthemes import ThemedTk
|
from ttkthemes import ThemedTk
|
||||||
|
|
||||||
from classes.custom.scrollable_frame import ScrollableFrame
|
from classes.custom.scrollable_frame import ScrollableFrame
|
||||||
from classes.custom.themed_frame import ThemedFrame
|
from classes.custom.themed_frame import ThemedFrame
|
||||||
from modules.utils import configGet, configSet
|
from classes.frames.device import FrameDevice
|
||||||
from modules.logger import logger
|
|
||||||
|
|
||||||
|
|
||||||
class FrameDevice(ThemedFrame):
|
|
||||||
|
|
||||||
def __init__(self, master: Misc, device_dict: str, **kwargs) -> None:
|
|
||||||
|
|
||||||
super().__init__(master, style="Card.TFrame", **kwargs)
|
|
||||||
|
|
||||||
self["borderwidth"] = 1
|
|
||||||
self["relief"] = "solid"
|
|
||||||
|
|
||||||
self.grid_columnconfigure(0, weight=1)
|
|
||||||
self.grid_columnconfigure(1, weight=3)
|
|
||||||
self.grid_columnconfigure(2, weight=3)
|
|
||||||
|
|
||||||
self.name = device_dict["name"]
|
|
||||||
|
|
||||||
self.title = ttk.Label(self, text=self.name, font=("SunValleyBodyFont", 12), justify=LEFT, width=46)
|
|
||||||
self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
|
||||||
|
|
||||||
last_upload = "N/A" if device_dict["last_save"] == 0 else datetime.utcfromtimestamp(device_dict["last_save"]).strftime("%d.%m.%Y %H:%M")
|
|
||||||
self.description = ttk.Label(self, text=f'OS: {device_dict["os"]}\nClient: {device_dict["client"]}\nLast upload: {last_upload}', width=46)
|
|
||||||
self.description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
|
|
||||||
|
|
||||||
self.buttons = ThemedFrame(self)
|
|
||||||
self.buttons.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
|
|
||||||
self.buttons.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
self.button_device_rename_action = partial(self.rename)
|
|
||||||
self.button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=self.button_device_rename_action)
|
|
||||||
self.button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
|
||||||
|
|
||||||
self.button_device_delete_action = partial(self.delete)
|
|
||||||
self.button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=self.button_device_delete_action)
|
|
||||||
self.button_device_delete.grid(column=1, row=0, sticky=W)
|
|
||||||
|
|
||||||
if self.name == configGet("name"):
|
|
||||||
# button_device_rename.state(["disabled"])
|
|
||||||
self.button_device_delete.state(["disabled"])
|
|
||||||
|
|
||||||
def rename(self):
|
|
||||||
|
|
||||||
self.rename_entry = ttk.Entry(self, font=("SunValleyBodyFont", 12), justify=LEFT, width=27)
|
|
||||||
self.rename_entry.insert(0, self.name)
|
|
||||||
self.rename_entry.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
|
||||||
|
|
||||||
button_device_cancel_action = partial(self.rename_cancel)
|
|
||||||
button_device_cancel = ttk.Button(self.buttons, text="Cancel", width=11, command=button_device_cancel_action)
|
|
||||||
button_device_cancel.grid(column=0, row=0, padx=9, sticky=E)
|
|
||||||
|
|
||||||
button_device_save_action = partial(self.rename_verify)
|
|
||||||
button_device_save = ttk.Button(self.buttons, text="Save", style="Accent.TButton", width=11, command=button_device_save_action)
|
|
||||||
button_device_save.grid(column=1, row=0, sticky=W)
|
|
||||||
|
|
||||||
def rename_verify(self):
|
|
||||||
|
|
||||||
self.name_before = configGet("name")
|
|
||||||
|
|
||||||
if (self.rename_entry.get().strip() == "") or ("?" in self.rename_entry.get().strip()) or ("/" in self.rename_entry.get().strip()):
|
|
||||||
logger.error(f"Name {self.rename_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
|
|
||||||
|
|
||||||
try:
|
|
||||||
quote(self.rename_entry.get().strip())
|
|
||||||
except:
|
|
||||||
logger.error(f"Name {self.rename_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
|
|
||||||
|
|
||||||
existing_device_before = requests.get(f'{configGet("address")}/devices/{self.name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
|
||||||
if existing_device_before.status_code == 200:
|
|
||||||
response = requests.patch(f'{configGet("address")}/devices/{self.name}?{urlencode({"new_name": self.rename_entry.get().strip(), "os": platform.system()+" "+platform.release(), "client": f"SyncTk {self.master.master.master.master.__version__}"})}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
|
||||||
if response.status_code != 204:
|
|
||||||
logger.error(f"Name {self.rename_entry.get().strip()} could not be set because server returned {response.status_code}")
|
|
||||||
messagebox.showerror(title="Name error", message=f"Provided device name is not valid.\n\nServer response: {response.json()}")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
logger.error(f"Tried to rename {self.name} into {self.rename_entry.get().strip()} but server returned {existing_device_before.status_code}")
|
|
||||||
messagebox.showerror(title="Rename error", message="It seems like this device no longer exists.")
|
|
||||||
return
|
|
||||||
|
|
||||||
self.name = self.rename_entry.get().strip()
|
|
||||||
|
|
||||||
for widget in self.winfo_children():
|
|
||||||
if isinstance(widget, ttk.Entry):
|
|
||||||
widget.destroy()
|
|
||||||
|
|
||||||
device_title = ttk.Label(self, text=self.name, font=("SunValleyBodyFont", 12), justify=LEFT, width=46)
|
|
||||||
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
|
||||||
|
|
||||||
button_device_rename_action = partial(self.rename)
|
|
||||||
button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=button_device_rename_action)
|
|
||||||
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
|
||||||
|
|
||||||
button_device_delete_action = partial(self.delete)
|
|
||||||
button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
|
|
||||||
button_device_delete.grid(column=1, row=0, sticky=W)
|
|
||||||
|
|
||||||
if self.name_before == configGet("name"):
|
|
||||||
configSet(["name"], self.name)
|
|
||||||
|
|
||||||
if self.name == configGet("name"):
|
|
||||||
button_device_delete.state(["disabled"])
|
|
||||||
|
|
||||||
def rename_cancel(self):
|
|
||||||
|
|
||||||
for widget in self.winfo_children():
|
|
||||||
if isinstance(widget, ttk.Entry):
|
|
||||||
widget.destroy()
|
|
||||||
|
|
||||||
device_title = ttk.Label(self, text=self.name, font=("SunValleyBodyFont", 12), justify=LEFT, width=46)
|
|
||||||
device_title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
|
||||||
|
|
||||||
button_device_rename_action = partial(self.rename)
|
|
||||||
button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=button_device_rename_action)
|
|
||||||
button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
|
||||||
|
|
||||||
button_device_delete_action = partial(self.delete)
|
|
||||||
button_device_delete = ttk.Button(self.buttons, text="Delete", style="Accent.TButton", width=11, command=button_device_delete_action)
|
|
||||||
button_device_delete.grid(column=1, row=0, sticky=W)
|
|
||||||
|
|
||||||
if self.name == configGet("name"):
|
|
||||||
button_device_delete.state(["disabled"])
|
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
|
|
||||||
decision = askyesno(title="Device removal", message=f"You are about to remove the device '{self.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/{self.name}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
|
|
||||||
|
|
||||||
for k in range(len(self.master.devices)):
|
|
||||||
if self.master.devices[k]["name"] == self.name:
|
|
||||||
del self.master.devices[k]
|
|
||||||
break
|
|
||||||
|
|
||||||
self.destroy()
|
|
||||||
|
|
||||||
|
|
||||||
class FrameDevices(ScrollableFrame):
|
class FrameDevices(ScrollableFrame):
|
||||||
@ -164,14 +15,8 @@ class FrameDevices(ScrollableFrame):
|
|||||||
|
|
||||||
master.title("Devices - Stardew Sync")
|
master.title("Devices - Stardew Sync")
|
||||||
|
|
||||||
# self["borderwidth"] = 1
|
|
||||||
# self["relief"] = "solid"
|
|
||||||
|
|
||||||
self.devices = devices
|
self.devices = devices
|
||||||
|
|
||||||
# self.grid_columnconfigure(0, weight=1)
|
|
||||||
# self.grid_rowconfigure(0, weight=2)
|
|
||||||
|
|
||||||
master.columnconfigure(1, weight=1)
|
master.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
self.render_devices()
|
self.render_devices()
|
||||||
@ -183,36 +28,6 @@ class FrameDevices(ScrollableFrame):
|
|||||||
|
|
||||||
device_frame = FrameDevice(self, device_dict=device)
|
device_frame = FrameDevice(self, device_dict=device)
|
||||||
device_frame.grid(column=0, row=i, pady=9, padx=9, sticky=NSEW)
|
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_action = partial(self.device_rename, device_frame, buttons_frame, device["name"])
|
|
||||||
# button_device_rename = ttk.Button(buttons_frame, text="Rename", width=11, command=button_device_rename_action)
|
|
||||||
# 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
|
i += 1
|
||||||
|
|
||||||
@ -229,9 +44,6 @@ class FrameDevicesEmpty(ThemedFrame):
|
|||||||
|
|
||||||
master.title("Devices - Stardew Sync")
|
master.title("Devices - Stardew Sync")
|
||||||
|
|
||||||
# self["borderwidth"] = 1
|
|
||||||
# self["relief"] = "solid"
|
|
||||||
|
|
||||||
self.grid_columnconfigure(0, weight=1)
|
self.grid_columnconfigure(0, weight=1)
|
||||||
self.grid_rowconfigure(0, weight=2)
|
self.grid_rowconfigure(0, weight=2)
|
||||||
|
|
||||||
|
37
classes/frames/save.py
Normal file
37
classes/frames/save.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from datetime import datetime, timezone
|
||||||
|
from tkinter import LEFT, NSEW, Misc, S, W, ttk
|
||||||
|
|
||||||
|
from classes.custom.themed_frame import ThemedFrame
|
||||||
|
|
||||||
|
|
||||||
|
class FrameSave(ThemedFrame):
|
||||||
|
|
||||||
|
def __init__(self, master: Misc, save_dict: str, **kwargs) -> None:
|
||||||
|
|
||||||
|
super().__init__(master, style="Card.TFrame", **kwargs)
|
||||||
|
|
||||||
|
self.grid_columnconfigure(0, weight=1)
|
||||||
|
self.grid_columnconfigure(1, weight=3)
|
||||||
|
self.grid_columnconfigure(2, weight=3)
|
||||||
|
|
||||||
|
self.title = ttk.Label(self, text=save_dict["data"]["farmer"], font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=46)
|
||||||
|
self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
self.description = ttk.Label(self, text=f'Money: {save_dict["data"]["money"]}\nGame version: {save_dict["data"]["game_version"]}\nID: {save_dict["id"]}', width=46)
|
||||||
|
self.description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
|
||||||
|
|
||||||
|
self.buttons = ThemedFrame(self)
|
||||||
|
self.buttons.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
|
||||||
|
self.buttons.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
upload_date = datetime.utcfromtimestamp(save_dict["date"]).replace(tzinfo=timezone.utc).astimezone(tz=None)
|
||||||
|
self.last_upload = ttk.Label(self.buttons, text=f'{upload_date.strftime("%A, %d %b %Y")}\nUploaded at {upload_date.strftime("%H:%M")} by {save_dict["device"]}', font=("SunValleyBodyFont", 8), justify=LEFT, width=46)
|
||||||
|
self.last_upload.grid(column=0, row=0, sticky=W+S)
|
||||||
|
|
||||||
|
# self.button_device_rename_action = partial(self.rename)
|
||||||
|
# self.button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=self.button_device_rename_action)
|
||||||
|
# self.button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
|
||||||
|
|
||||||
|
#self.button_device_delete_action = partial(self.delete)
|
||||||
|
self.button_device_delete = ttk.Button(self.buttons, text="Synchronize", style="Accent.TButton", width=11) #, command=self.button_device_delete_action)
|
||||||
|
self.button_device_delete.grid(column=1, row=0, sticky=W)
|
@ -1,11 +1,81 @@
|
|||||||
from tkinter import EW, NS, ttk
|
from os import path, walk
|
||||||
|
from tkinter import NSEW, ttk
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
from ttkthemes import ThemedTk
|
from ttkthemes import ThemedTk
|
||||||
|
|
||||||
|
from classes.custom.scrollable_frame import ScrollableFrame
|
||||||
from classes.custom.themed_frame import ThemedFrame
|
from classes.custom.themed_frame import ThemedFrame
|
||||||
|
from classes.frames.save import FrameSave
|
||||||
|
from modules.utils import configGet
|
||||||
|
|
||||||
|
|
||||||
class FrameSaves(ThemedFrame):
|
class FrameSaves(ScrollableFrame):
|
||||||
|
|
||||||
|
def __init__(self, master: ThemedTk, saves: list, **kwargs) -> None:
|
||||||
|
|
||||||
|
super().__init__(master, **kwargs)
|
||||||
|
|
||||||
|
master.title("Saves - Stardew Sync")
|
||||||
|
|
||||||
|
self.saves = saves
|
||||||
|
self.saves_local = []
|
||||||
|
|
||||||
|
for subdir, dirs, files in walk(configGet("saves_location")):
|
||||||
|
try:
|
||||||
|
for dir in dirs:
|
||||||
|
with open(path.join(dir, "SaveGameInfo"), "r", encoding="utf-8") as file:
|
||||||
|
save_dict = xmltodict.parse(file.read())
|
||||||
|
self.saves_local.append(
|
||||||
|
{
|
||||||
|
"id": int(save_dict["SaveGame"]["uniqueIDForThisGame"]),
|
||||||
|
"user": None,
|
||||||
|
"device": configGet("name"),
|
||||||
|
"date": None,
|
||||||
|
"data": {
|
||||||
|
"farmer": save_dict["Farmer"]["name"],
|
||||||
|
"money": int(save_dict["Farmer"]["money"]),
|
||||||
|
"played": int(save_dict["Farmer"]["millisecondsPlayed"]),
|
||||||
|
"save_time": int(save_dict["Farmer"]["saveTime"]),
|
||||||
|
"year": int(save_dict["Farmer"]["yearForSaveGame"]),
|
||||||
|
"season": int(save_dict["Farmer"]["seasonForSaveGame"]),
|
||||||
|
"day": int(save_dict["Farmer"]["dayOfMonthForSaveGame"]),
|
||||||
|
"game_version": save_dict["Farmer"]["gameVersion"]
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"name": None,
|
||||||
|
"uuid": None,
|
||||||
|
"path": None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Merge local and remote saves.
|
||||||
|
# Maybe add something that indicates availability of an
|
||||||
|
# remote update to pull or local new version to push.
|
||||||
|
|
||||||
|
master.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
self.render_saves()
|
||||||
|
|
||||||
|
def render_saves(self):
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
for save in self.saves:
|
||||||
|
|
||||||
|
save_frame = FrameSave(self, save_dict=save)
|
||||||
|
save_frame.grid(column=0, row=i, pady=9, padx=9, sticky=NSEW)
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if i+1 != len(self.saves):
|
||||||
|
divider = ttk.Separator(self, orient="horizontal")
|
||||||
|
divider.grid(column=0, row=i+1, pady=9)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
class FrameSavesEmpty(ThemedFrame):
|
||||||
|
|
||||||
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
def __init__(self, master: ThemedTk, **kwargs) -> None:
|
||||||
|
|
||||||
@ -13,13 +83,10 @@ class FrameSaves(ThemedFrame):
|
|||||||
|
|
||||||
master.title("Saves - Stardew Sync")
|
master.title("Saves - Stardew Sync")
|
||||||
|
|
||||||
self["borderwidth"] = 2
|
self.grid_columnconfigure(0, weight=1)
|
||||||
self["relief"] = "solid"
|
self.grid_rowconfigure(0, weight=2)
|
||||||
|
|
||||||
self.inside_frame = ThemedFrame(self)
|
master.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
for btn in range(0, 10):
|
self.label = ttk.Label(self, text="No saves found")
|
||||||
ttk.Button(self.inside_frame, text="SAVES "+str(btn)).grid(column=0, row=btn, padx=9, pady=9, sticky=EW)
|
self.label.grid(column=0, row=0, padx=9, pady=9)
|
||||||
|
|
||||||
self.scrollbar = ttk.Scrollbar(self.inside_frame, orient="vertical")
|
|
||||||
self.scrollbar.grid(column=1, row=0, sticky=NS)
|
|
3
main.py
3
main.py
@ -1,3 +1,4 @@
|
|||||||
|
import locale
|
||||||
from os import path
|
from os import path
|
||||||
from classes.app import App
|
from classes.app import App
|
||||||
from modules.utils import jsonSave
|
from modules.utils import jsonSave
|
||||||
@ -16,6 +17,8 @@ if not path.exists("config.json"):
|
|||||||
},
|
},
|
||||||
"config.json"
|
"config.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
darkdetect~=0.8.0
|
darkdetect~=0.8.0
|
||||||
|
xmltodict~=0.13.0
|
||||||
ttkthemes~=3.2.2
|
ttkthemes~=3.2.2
|
||||||
requests~=2.28.2
|
requests~=2.28.2
|
||||||
sv_ttk~=2.4
|
sv_ttk~=2.4
|
Loading…
Reference in New Issue
Block a user