diff --git a/src/classes/app.py b/src/classes/app.py index e2a66a5..37e1128 100644 --- a/src/classes/app.py +++ b/src/classes/app.py @@ -11,7 +11,7 @@ from classes.custom.themed_frame import ThemedFrame from classes.enums import ConnectionState, Theme from classes.frames.devices import FrameDevices, FrameDevicesEmpty from classes.frames.errors import FrameErrorConnection, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured -from classes.frames.saves import FrameSaves, FrameSavesEmpty +from classes.frames.saves import FrameSaves from classes.frames.settings import FrameSettings from classes.toplevel.welcome import ToplevelWelcome from modules.theme_titlebar import theme_title_bar @@ -63,18 +63,19 @@ class App(ThemedTk): def frame_saves(self): self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) - try: - self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) - except Exception as exp: - messagebox.showerror(title="Connection error", message=f"We could not reach the server to check for save entries\n\n{exp}") - logger.error(format_exc()) - self.frame_saves_object = FrameErrorConnection(self) - self.frame_saves_object.grid(column=1, row=0, sticky=NSEW) - return - 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 = FrameSaves(self, [], vscroll=True) + # try: + # self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + # except Exception as exp: + # messagebox.showerror(title="Connection error", message=f"We could not reach the server to check for save entries\n\n{exp}") + # logger.error(format_exc()) + # self.frame_saves_object = FrameErrorConnection(self) + # self.frame_saves_object.grid(column=1, row=0, sticky=NSEW) + # return + # 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 = FrameSaves(self, [], vscroll=True) + self.frame_saves_object = FrameSaves(self, vscroll=True) self.frame_saves_object.grid(column=1, row=0, sticky=NSEW) return diff --git a/src/classes/frames/save.py b/src/classes/frames/save.py index a8c1b88..fe3d938 100644 --- a/src/classes/frames/save.py +++ b/src/classes/frames/save.py @@ -1,9 +1,15 @@ from datetime import datetime, timedelta, timezone +from functools import partial +from os import makedirs, path, remove from tkinter import LEFT, NSEW, Misc, S, W, ttk +from urllib.parse import urlencode +from zipfile import ZipFile + +import requests from classes.custom.themed_frame import ThemedFrame -from classes.enums import SaveState -from modules.utils import osname +from classes.enums import SaveState, SaveType +from modules.utils import configGet, osname class FrameSave(ThemedFrame): @@ -18,6 +24,8 @@ class FrameSave(ThemedFrame): self.grid_columnconfigure(1, weight=3) self.grid_columnconfigure(2, weight=3) + self.save_dict = save_dict + self.title = ttk.Label(self, text=f'{save_dict["data"]["farmer"]} ({save_dict["type"].value.upper()}, {save_dict["state"].value.upper()})', font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=self.widget_width) self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W) @@ -39,8 +47,25 @@ class FrameSave(ThemedFrame): # 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_synchronize = ttk.Button(self.buttons, text="Synchronize", style="Accent.TButton", width=11) #, command=self.button_device_delete_action) + self.button_synchronize_action = partial(self.nothing) + + if save_dict["type"] is SaveType.LOCAL: + if save_dict["state"] is SaveState.RECENT: + self.button_synchronize_action = partial(self.upload, save_dict["id"]) + print(f'{save_dict["id"]}, local, recent') + elif save_dict["type"] is SaveType.REMOTE: + if save_dict["state"] is SaveState.RECENT: + self.button_synchronize_action = partial(self.download, save_dict["id"], save_dict["date"]) + print(f'{save_dict["id"]}, remote, recent') + else: + if save_dict["state"] is SaveState.OUTDATED: + self.button_synchronize_action = partial(self.download, save_dict["id"], save_dict["date"]) + print(f'{save_dict["id"]}, both, outdated') + elif save_dict["state"] is SaveState.RECENT: + self.button_synchronize_action = partial(self.upload, save_dict["id"]) + print(f'{save_dict["id"]}, both, recent') + + self.button_synchronize = ttk.Button(self.buttons, text="Synchronize", style="Accent.TButton", width=11, command=self.button_synchronize_action) self.button_synchronize.grid(column=1, row=0, sticky=W) if save_dict["state"] is SaveState.CURRENT: @@ -49,21 +74,51 @@ class FrameSave(ThemedFrame): def convert_date(self, year: int, season: int, day: int) -> str: if season == 0: - season = "Spring" + season_name = "Spring" elif season == 1: - season = "Summer" + season_name = "Summer" elif season == 2: - season = "Fall" + season_name = "Fall" else: - season = "Winter" + season_name = "Winter" - return "Day {0} of {1}, Year {2}".format(day, season, year) + return "Day {0} of {1}, Year {2}".format(day, season_name, year) def convert_playtime(self, seconds: int) -> str: - pass + return "" - def upload(self): - pass + def upload(self, id: int): - def download(self): + print(f"Upload pressed for {id}") + + files = [("files", open(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}', f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}'), "rb")), ("files", open(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}', "SaveGameInfo"), "rb"))] + response = requests.post(f'{configGet("address")}/saves?{urlencode({"device": configGet("name")})}', files=files, headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + + print(response.status_code) + + self.master.render_saves() + + def download(self, id: int, date: int): + + print(f"Download pressed for {id}") + + response = requests.get(f'{configGet("address")}/saves/{id}/{date}/download', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + + makedirs("tmp", exist_ok=True) + + with open(path.join("tmp", f"{id}.svsave"), "wb") as file: + file.write(response.content) + + makedirs(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}'), exist_ok=True) + + with ZipFile(path.join("tmp", f"{id}.svsave"), "r") as file: + file.extractall(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}')) + + remove(path.join("tmp", f"{id}.svsave")) + + print(response.status_code) + + self.master.render_saves() + + def nothing(self): pass \ No newline at end of file diff --git a/src/classes/frames/saves.py b/src/classes/frames/saves.py index f50d1ff..098fe2c 100644 --- a/src/classes/frames/saves.py +++ b/src/classes/frames/saves.py @@ -2,6 +2,7 @@ from os import path, walk from tkinter import E, NSEW, W, ttk from traceback import print_exc import xmltodict +import requests from ttkthemes import ThemedTk @@ -14,18 +15,41 @@ from modules.utils import configGet class FrameSaves(ScrollableFrame): - def __init__(self, master: ThemedTk, saves: list, **kwargs) -> None: + def __init__(self, master: ThemedTk, **kwargs) -> None: super().__init__(master, **kwargs) master.title("Saves - Stardew Sync") - self.saves = saves - self.saves_local = [] + self.saves = self.fetch_saves() # self["borderwidth"] = 1 # self["relief"] = "solid" + master.columnconfigure(1, weight=1) + + if len(self.saves) == 0: + + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=2) + + master.columnconfigure(1, weight=1) + + self.label = ttk.Label(self, text="No saves found") + self.label.grid(column=0, row=0, padx=9, pady=9) + + else: + + self.render_saves(refetch=False) + + def fetch_saves_remote(self) -> list: + response = self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) + return response.json() if response.status_code == 200 else [] + + def fetch_saves(self) -> list: + + self.saves = self.fetch_saves_remote() + for index, entry in enumerate(self.saves): self.saves[index]["state"] = SaveState.RECENT @@ -107,20 +131,20 @@ class FrameSaves(ScrollableFrame): except: print_exc() - # Merge local and remote saves. - # Maybe add something that indicates availability of an - # remote update to pull or local new version to push. + return self.saves - master.columnconfigure(1, weight=1) + def render_saves(self, refetch: bool = True): - self.render_saves() + if refetch is True: + self.saves = self.fetch_saves() - def render_saves(self): + for widget in self.winfo_children(): + widget.destroy() i = 0 for save in self.saves: - print(save) + # print(save) save_frame = FrameSave(self, save_dict=save) save_frame.grid(column=0, row=i, pady=9, padx=9, sticky=W+E) @@ -132,18 +156,18 @@ class FrameSaves(ScrollableFrame): divider.grid(column=0, row=i+1, pady=9) i += 1 -class FrameSavesEmpty(ThemedFrame): +# class FrameSavesEmpty(ThemedFrame): - def __init__(self, master: ThemedTk, **kwargs) -> None: +# def __init__(self, master: ThemedTk, **kwargs) -> None: - super().__init__(master, **kwargs) +# super().__init__(master, **kwargs) - master.title("Saves - Stardew Sync") +# master.title("Saves - Stardew Sync") - self.grid_columnconfigure(0, weight=1) - self.grid_rowconfigure(0, weight=2) + # self.grid_columnconfigure(0, weight=1) + # self.grid_rowconfigure(0, weight=2) - master.columnconfigure(1, weight=1) + # master.columnconfigure(1, weight=1) - self.label = ttk.Label(self, text="No saves found") - self.label.grid(column=0, row=0, padx=9, pady=9) \ No newline at end of file + # self.label = ttk.Label(self, text="No saves found") + # self.label.grid(column=0, row=0, padx=9, pady=9) \ No newline at end of file