2023-01-23 01:13:30 +02:00
from datetime import datetime
from functools import partial
2023-01-25 15:01:13 +02:00
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
2023-01-22 18:53:55 +02:00
2023-01-23 01:13:30 +02:00
import requests
2023-01-22 18:53:55 +02:00
from ttkthemes import ThemedTk
2023-01-23 01:13:30 +02:00
from classes . custom . scrollable_frame import ScrollableFrame
2023-01-22 18:53:55 +02:00
from classes . custom . themed_frame import ThemedFrame
2023-01-25 15:01:13 +02:00
from modules . utils import configGet , configSet
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 " ] } \n Client: { device_dict [ " client " ] } \n Last 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 \n Server 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 ( )
2023-01-22 18:53:55 +02:00
2023-01-23 01:13:30 +02:00
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 :
2023-01-25 15:01:13 +02:00
device_frame = FrameDevice ( self , device_dict = device )
2023-01-23 01:13:30 +02:00
device_frame . grid ( column = 0 , row = i , pady = 9 , padx = 9 , sticky = NSEW )
# self.device_frame["borderwidth"] = 1
# self.device_frame["relief"] = "solid"
2023-01-25 15:01:13 +02:00
# device_frame.grid_columnconfigure(0, weight=1)
# device_frame.grid_columnconfigure(1, weight=3)
# device_frame.grid_columnconfigure(2, weight=3)
2023-01-23 01:13:30 +02:00
2023-01-25 15:01:13 +02:00
# 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)
2023-01-23 01:13:30 +02:00
2023-01-25 15:01:13 +02:00
# 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)
2023-01-23 01:13:30 +02:00
2023-01-25 15:01:13 +02:00
# 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)
2023-01-23 01:13:30 +02:00
2023-01-25 15:01:13 +02:00
# 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)
2023-01-23 01:13:30 +02:00
2023-01-25 15:01:13 +02:00
# 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)
2023-01-23 01:13:30 +02:00
2023-01-25 15:01:13 +02:00
# if device["name"] == configGet("name"):
# # button_device_rename.state(["disabled"])
# button_device_delete.state(["disabled"])
2023-01-23 01:13:30 +02:00
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
class FrameDevicesEmpty ( ThemedFrame ) :
2023-01-22 18:53:55 +02:00
def __init__ ( self , master : ThemedTk , * * kwargs ) - > None :
super ( ) . __init__ ( master , * * kwargs )
master . title ( " Devices - Stardew Sync " )
2023-01-23 01:13:30 +02:00
# self["borderwidth"] = 1
# self["relief"] = "solid"
self . grid_columnconfigure ( 0 , weight = 1 )
self . grid_rowconfigure ( 0 , weight = 2 )
2023-01-22 18:53:55 +02:00
2023-01-23 01:13:30 +02:00
master . columnconfigure ( 1 , weight = 1 )
2023-01-22 18:53:55 +02:00
2023-01-23 01:13:30 +02:00
self . label = ttk . Label ( self , text = " No devices found " )
self . label . grid ( column = 0 , row = 0 , padx = 9 , pady = 9 )