Compare commits
3 commits
430e7e37be
...
288edab17c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
288edab17c | ||
|
|
c4fd87008c | ||
|
|
dfa122cf73 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
data/*
|
||||
__pycache__/*
|
||||
31
api.py
Normal file
31
api.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import requests
|
||||
|
||||
BASE_URL = "https://api.spacetraders.io/v2"
|
||||
|
||||
def handleResponse(res:requests.Response):
|
||||
code = res.status_code
|
||||
try:
|
||||
data = res.json()
|
||||
except:
|
||||
data = None
|
||||
return code, data
|
||||
|
||||
def newAgent(accToken, callsign, faction='COSMIC'):
|
||||
header = {
|
||||
"Authorization": f"Bearer {accToken}",
|
||||
"Content-Type" : "application/json"
|
||||
}
|
||||
params = {
|
||||
"symbol" : callsign,
|
||||
"faction" : faction
|
||||
}
|
||||
url = f"{BASE_URL}/register"
|
||||
return handleResponse(requests.post(url, json=params, headers=header))
|
||||
|
||||
def viewAgent(agentToken):
|
||||
header = {
|
||||
"Authorization": f"Bearer {agentToken}",
|
||||
"Content-Type" : "application/json"
|
||||
}
|
||||
url = f"{BASE_URL}/my/agent"
|
||||
return handleResponse(requests.get(url, headers=header))
|
||||
BIN
assets/babynet.png
Normal file
BIN
assets/babynet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
127
mainwindow.py
Normal file
127
mainwindow.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#builtins
|
||||
import tkinter as Tk
|
||||
from tkinter import ttk as Ttk
|
||||
from tkinter import font
|
||||
from os import path
|
||||
|
||||
#packages
|
||||
from PIL import ImageTk, Image
|
||||
|
||||
#custom stuff
|
||||
from storage import readSave, save
|
||||
import api, ui
|
||||
|
||||
#load icon
|
||||
icoPng = Image.open(path.join("assets","babynet.png"))
|
||||
|
||||
#initialize root
|
||||
root = Tk.Tk()
|
||||
root.title("SPASESHUPS")
|
||||
ico = ImageTk.PhotoImage(icoPng)
|
||||
root.wm_iconphoto(False, ico)
|
||||
|
||||
#add the three main sections
|
||||
#header contains auth keys and such
|
||||
headerFrame = ui.Container(root, freezeCols=1)
|
||||
headerFrame.widget.grid(row=0, column=0, sticky='new')
|
||||
|
||||
#requestFrame is the main body where the request buttons will be
|
||||
requestFrame = ui.Container(root)
|
||||
requestFrame.widget.grid(row=1, column=0, sticky='nesw')
|
||||
|
||||
#response frame is where the output lives
|
||||
responseFrame = ui.Container(root)
|
||||
responseFrame.widget.grid(row=2, column=0, sticky="snew")
|
||||
|
||||
#populate the header
|
||||
accToken = Tk.StringVar()
|
||||
accAuthBox = ui.SavedEntryBox(headerFrame.widget, 'acc_token', accToken)
|
||||
Ttk.Label(headerFrame.widget, text="ACCOUNT TOKEN:").grid(row=0, column=0, sticky='e')
|
||||
accAuthBox.widget.grid(row=0, column=1, columnspan=5, sticky='ew')
|
||||
|
||||
agentToken = Tk.StringVar()
|
||||
agentAuthBox = ui.SavedEntryBox(headerFrame.widget, 'active_agent_token', agentToken)
|
||||
Ttk.Label(headerFrame.widget, text="AGENT TOKEN:").grid(row=1, column=0, sticky='e')
|
||||
agentAuthBox.widget.grid(row=1, column=1, columnspan=5, sticky='ew')
|
||||
#freeze the label column
|
||||
headerFrame.widget.columnconfigure(0, weight=0)
|
||||
|
||||
#populate and style the response frame
|
||||
resLabel = Tk.Text(responseFrame.widget, background='grey17', foreground='white')
|
||||
resLabel.grid(row=0, column=0, sticky='news')
|
||||
resLabel.insert('1.0', "Awaiting call...")
|
||||
resLabel['state'] = 'disabled'
|
||||
resScrollbarV = Ttk.Scrollbar(responseFrame.widget, orient='vertical', command=resLabel.yview)
|
||||
resLabel.configure(yscrollcommand=resScrollbarV.set)
|
||||
resScrollbarV.grid(row=0, column=1, rowspan=2, sticky='ns')
|
||||
|
||||
def updateResponse(newText):
|
||||
resLabel['state'] = 'normal'
|
||||
resLabel.delete('1.0', 'end')
|
||||
resLabel.insert('1.0', newText)
|
||||
resLabel['state'] = 'disabled'
|
||||
|
||||
Ttk.Style().configure('Shaded.TFrame', background='grey17')
|
||||
responseFrame.widget.configure(borderwidth=2, relief='groove', style='Shaded.TFrame')
|
||||
|
||||
#populate the request frame
|
||||
makeFrame = ui.RequesterFrame(requestFrame.widget, 'CREATE')
|
||||
makeFrame.widget.grid(row=0, column=0, sticky='nsew')
|
||||
|
||||
#new agent
|
||||
callsignVar = Tk.StringVar()
|
||||
factionVar = Tk.StringVar()
|
||||
ui.FieldLabel(makeFrame.widget, 'Callsign:', 1)
|
||||
ui.EntryBox(makeFrame.widget, callsignVar).widget.grid(row=1, column=2, sticky='ew')
|
||||
ui.FieldLabel(makeFrame.widget, 'Faction Name:', 2)
|
||||
ui.EntryBox(makeFrame.widget, factionVar).widget.grid(row=2, column=2, sticky='ew')
|
||||
def newAgent(args):
|
||||
resCode, resData = api.newAgent(*args)
|
||||
updateResponse(ui.formatResponse(resCode, resData))
|
||||
try:
|
||||
agentToken.set(resData['token'])
|
||||
if int(resCode) < 300:
|
||||
agentAuthBox.saveValue()
|
||||
except:
|
||||
pass
|
||||
return resCode, resData
|
||||
newAgentButton = ui.ApiButton(makeFrame.widget, 'NEW AGENT', 3, newAgent, (accToken, callsignVar, factionVar))
|
||||
|
||||
viewFrame = ui.RequesterFrame(requestFrame.widget, 'VIEW')
|
||||
viewFrame.widget.grid(row=0, column=1, sticky='nesw')
|
||||
|
||||
#view agent
|
||||
def viewAgent(args):
|
||||
resCode, resData = api.viewAgent(*args)
|
||||
updateResponse(ui.formatResponse(resCode, resData))
|
||||
return resCode, resData
|
||||
viewAgentButton = ui.ApiButton(viewFrame.widget, 'VIEW AGENT', 2, viewAgent, (agentToken))
|
||||
|
||||
useFrame = ui.RequesterFrame(requestFrame.widget, 'USE')
|
||||
useFrame.widget.grid(row=0, column=2, sticky='nsew')
|
||||
|
||||
|
||||
#finalize the layout
|
||||
makeFrame.finalize()
|
||||
useFrame.finalize()
|
||||
viewFrame.finalize()
|
||||
|
||||
headerFrame.finalize()
|
||||
requestFrame.finalize()
|
||||
|
||||
#response frame finalize doesnt help much so do it manually
|
||||
responseFrame.widget.grid_rowconfigure(0, weight=1)
|
||||
responseFrame.widget.grid_columnconfigure(0, weight=1)
|
||||
responseFrame.widget.grid_columnconfigure(1, weight=0)
|
||||
|
||||
for child in root.winfo_children():
|
||||
child.grid_configure(padx = 5, pady = 5)
|
||||
|
||||
#sort out scaling for the top 3 frames
|
||||
root.columnconfigure(0, weight=1)
|
||||
root.rowconfigure(0, weight=0)
|
||||
root.rowconfigure(1, weight=1)
|
||||
root.rowconfigure(2, weight=1, minsize=300)
|
||||
|
||||
#aaaand go
|
||||
root.mainloop()
|
||||
35
storage.py
Normal file
35
storage.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
from os import path
|
||||
import json
|
||||
|
||||
SAVE_FILE = path.join("data", "save.dat")
|
||||
|
||||
def readSave(*fields):
|
||||
try:
|
||||
with open(SAVE_FILE, 'r') as f:
|
||||
out = {}
|
||||
obj = json.load(f)
|
||||
for field in fields:
|
||||
try:
|
||||
out[field] = obj[field]
|
||||
except KeyError:
|
||||
out[field] = None
|
||||
return out
|
||||
except FileNotFoundError:
|
||||
with open(SAVE_FILE, 'w') as f:
|
||||
json.dump({'acc_token': 0}, f, indent=4)
|
||||
return readSave(*fields)
|
||||
|
||||
def save(fieldsDic):
|
||||
try:
|
||||
obj = None
|
||||
with open(SAVE_FILE, 'r') as f:
|
||||
out = {}
|
||||
obj = json.load(f)
|
||||
obj.update(fieldsDic)
|
||||
with open(SAVE_FILE, 'w') as f:
|
||||
json.dump(obj, f, indent=4)
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
with open(SAVE_FILE, 'w') as f:
|
||||
json.dump(fieldsDic, f, indent=4)
|
||||
return True
|
||||
128
ui.py
Normal file
128
ui.py
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
import tkinter as Tk
|
||||
from tkinter import ttk as Ttk
|
||||
from tkinter import font
|
||||
from pprint import pformat
|
||||
import threading
|
||||
|
||||
from storage import readSave, save
|
||||
|
||||
class FieldLabel():
|
||||
"""
|
||||
Label to set alongside a text box.
|
||||
"""
|
||||
def __init__(self, parent, text, rowNum):
|
||||
self.widget = Ttk.Label(parent, text=text)
|
||||
self.widget.grid(row=rowNum, column=1, sticky='e')
|
||||
|
||||
class EntryBox():
|
||||
"""
|
||||
Basic entry box class.
|
||||
"""
|
||||
def __init__(self, parent, textVar=None):
|
||||
if textVar is None:
|
||||
self.textVar = Tk.StringVar()
|
||||
else:
|
||||
self.textVar = textVar
|
||||
self.widget = Ttk.Entry(parent, width=12, textvariable=self.textVar)
|
||||
|
||||
class SavedEntryBox(EntryBox):
|
||||
"""
|
||||
Entry box that saves values to file with a given field name. Reads from that field on launch.
|
||||
"""
|
||||
def __init__(self, parent, fieldName, textVar, saveOnEnter=True, saveOnChange=False):
|
||||
self.textVar = textVar
|
||||
super().__init__(parent, self.textVar)
|
||||
self.fieldName = fieldName
|
||||
|
||||
value = readSave(fieldName)[fieldName]
|
||||
if value is not None:
|
||||
self.textVar.set(value)
|
||||
else:
|
||||
self.textVar.set(fieldName)
|
||||
|
||||
if saveOnEnter:
|
||||
self.widget.bind("<Return>", self.saveValue)
|
||||
|
||||
if saveOnChange:
|
||||
self.textVar.trace_add("write", self.saveValue)
|
||||
|
||||
def saveValue(self, *args):
|
||||
save({self.fieldName: self.textVar.get()})
|
||||
|
||||
|
||||
class Container():
|
||||
def __init__(self, parent, freezeCols=0):
|
||||
self.widget = Ttk.Frame(parent, padding=(3))
|
||||
self.freezeCols = freezeCols
|
||||
|
||||
def finalize(self):
|
||||
cols, rows = self.widget.grid_size()
|
||||
if self.freezeCols > 0:
|
||||
for i in range(self.freezeCols):
|
||||
self.widget.grid_columnconfigure(i, weight=0)
|
||||
for i in range(self.freezeCols, cols):
|
||||
self.widget.grid_columnconfigure(i, weight=1, uniform='column')
|
||||
|
||||
for i in range(rows):
|
||||
self.widget.grid_rowconfigure(i, weight=0)
|
||||
|
||||
|
||||
class RequesterFrame(Container):
|
||||
"""
|
||||
Top-level frame for classes of manipulations.
|
||||
"""
|
||||
def __init__(self, parent, label):
|
||||
super().__init__(parent)
|
||||
self.widget.configure(height=480, width=330, borderwidth=3, relief="raised")
|
||||
self.widget.bind('<Enter>', lambda e: self.widget.configure(relief="sunken"))
|
||||
self.widget.bind('<Leave>', lambda e: self.widget.configure(relief="raised"))
|
||||
|
||||
self.label = Ttk.Label(self.widget, text=label, font=font.nametofont('TkHeadingFont'))
|
||||
self.label.grid(row=0, column=0, sticky='nw')
|
||||
|
||||
def finalize(self):
|
||||
cols, rows = self.widget.grid_size()
|
||||
self.widget.grid_columnconfigure(0, weight=0)
|
||||
self.widget.grid_columnconfigure(1, weight=0)
|
||||
self.widget.grid_columnconfigure(2, weight=1, minsize=150)
|
||||
|
||||
for i in range(rows):
|
||||
self.widget.grid_rowconfigure(i, weight=1, minsize=5)
|
||||
|
||||
|
||||
class ApiButton():
|
||||
"""
|
||||
Button which triggers an API call when clicked.
|
||||
"""
|
||||
def __init__(self, parent, label, rowNum, apiFunc, args):
|
||||
self.call = apiFunc
|
||||
self.args = args
|
||||
self.row = rowNum
|
||||
self.parent = parent
|
||||
self.widget = Ttk.Button(parent, command=self.pressed, text=label)
|
||||
self.widget.grid(row=rowNum, column=1, columnspan=2, sticky='nsew')
|
||||
|
||||
def pressed(self, *args):
|
||||
progbar = Ttk.Progressbar(self.parent, orient='horizontal', mode='indeterminate', length=10)
|
||||
progbar.grid(row=self.row, column=0)
|
||||
threading.Thread(target=self.thread, args=(progbar,)).start()
|
||||
|
||||
def thread(self, progbar):
|
||||
toPass = []
|
||||
if isinstance(self.args, (list, tuple)):
|
||||
for arg in self.args:
|
||||
if type(arg) is Tk.StringVar:
|
||||
toPass.append(arg.get())
|
||||
else:
|
||||
toPass.append(arg)
|
||||
else:
|
||||
if type(self.args) is Tk.StringVar:
|
||||
toPass.append(self.args.get())
|
||||
else:
|
||||
toPass.append(self.args)
|
||||
self.resCode, self.resData = self.call(toPass)
|
||||
progbar.grid_forget()
|
||||
|
||||
def formatResponse(resCode, resData):
|
||||
return f"""Response {resCode}:
|
||||
{pformat(resData)}"""
|
||||
Loading…
Reference in a new issue