first stages of linking front/back
This commit is contained in:
parent
392bfae855
commit
ba7e8f24af
@ -3,6 +3,7 @@ import requests
|
||||
# from datetime import datetime
|
||||
import time
|
||||
import random
|
||||
import copy
|
||||
|
||||
class TodoDatabase:
|
||||
def __init__(self, filename="data.json"):
|
||||
@ -15,9 +16,11 @@ class TodoDatabase:
|
||||
pass
|
||||
|
||||
def save_todo(self, date, todo, save=True):
|
||||
if "recurring" not in self.database:
|
||||
self.database["recurring"] = []
|
||||
if date not in self.database:
|
||||
# if not len(self.database[date]) > 0:
|
||||
self.database[date] = []
|
||||
self.database[date] = copy.deepcopy(self.database["recurring"])
|
||||
if todo.recurring:
|
||||
self.database["recurring"].append(todo.model_dump())
|
||||
self.database[date].append(todo.model_dump())
|
||||
|
@ -18,7 +18,7 @@ app = FastAPI()
|
||||
auth = VerifyToken()
|
||||
data = TodoDatabase()
|
||||
printer = ThermalPrinter(data)
|
||||
printer.print_default() #temp debug
|
||||
# printer.print_default() #temp debug
|
||||
|
||||
|
||||
|
||||
@ -40,13 +40,14 @@ class TodoDate(BaseModel):
|
||||
class PrintAction(BaseModel):
|
||||
date: str = datetime.today().strftime('%Y-%m-%d')
|
||||
action: str #Options:
|
||||
# default (pulls current todos from date, needs date)
|
||||
# all (pulls current todos from date, needs date)
|
||||
# sudoku (prints a random sudoku)
|
||||
# todos (prints only dates todos)
|
||||
# wordsearch (prints a random wordsearch)
|
||||
# quote (prints a random quote)
|
||||
# greeting (prints a greeting)
|
||||
#
|
||||
# sentence (prints a custom message)
|
||||
sentence: str = ""
|
||||
|
||||
# @app.get("/api/public")
|
||||
# def public():
|
||||
@ -118,7 +119,7 @@ def write_todos(todos: TodoList, auth_result: str = Security(auth.verify)):
|
||||
|
||||
|
||||
@app.get("/api/todos/print")
|
||||
def print_todos(date: PrintAction, auth_result: str = Security(auth.verify)):
|
||||
def print_todos(action: PrintAction, auth_result: str = Security(auth.verify)):
|
||||
"""A valid access token is required to access this route"""
|
||||
|
||||
# result = {
|
||||
@ -127,9 +128,42 @@ def print_todos(date: PrintAction, auth_result: str = Security(auth.verify)):
|
||||
# {"time": "2:00pm to 3:00pm", "text": "Go for a walk"}
|
||||
# ]
|
||||
# } #TODO: replace with access to database if no todos provided from request, otherwise print request data
|
||||
|
||||
#Options:
|
||||
# all (pulls current todos from date, needs date)
|
||||
# sudoku (prints a random sudoku)
|
||||
# todos (prints only dates todos)
|
||||
# wordsearch (prints a random wordsearch)
|
||||
# quote (prints a random quote)
|
||||
# greeting (prints a greeting)
|
||||
# sentence (prints a custom message)
|
||||
if action.action == "all":
|
||||
printer.print_default()
|
||||
|
||||
todos = data.get_todos(date)
|
||||
printer.print_todos()
|
||||
if action.action == "sudoku":
|
||||
printer.print_sudoku()
|
||||
|
||||
if action.action == "todos":
|
||||
printer.print_todos()
|
||||
|
||||
if action.action == "wordsearch":
|
||||
printer.print_wordsearch()
|
||||
|
||||
if action.action == "quote":
|
||||
printer.print_random_quote()
|
||||
|
||||
if action.action == "greeting":
|
||||
printer.print_greeting()
|
||||
|
||||
if action.action == "sentence":
|
||||
printer.print_custom(action.sentence)
|
||||
|
||||
|
||||
printer.finished_printing()
|
||||
|
||||
|
||||
# todos = data.get_todos(action.date)
|
||||
# printer.print_todos()
|
||||
|
||||
return {"result": "success"}
|
||||
|
||||
|
@ -21,6 +21,102 @@
|
||||
<!-- <div id="testToken"></div> -->
|
||||
|
||||
|
||||
<div id="printModel" class="absolute w-full h-full overflow-y-hidden top-0 left-0 hidden">
|
||||
<div class="flex flex-row w-full justify-center items-center text-center h-screen">
|
||||
<div class="absolute w-full h-full bg-slate-800 opacity-40 top-0 left-0"></div>
|
||||
<div class="bg-white inline-block text-left rounded-lg overflow-hidden align-bottom transition-all transform shadow-2xl sm:my-8 sm:align-middle sm:max-w-xl sm:w-full">
|
||||
<div class="flex flex-col items-center pt-6 pr-6 pb-6 pl-6">
|
||||
<!-- <div class="grid grid-cols-2 items-center pt-6 pr-6 pb-6 pl-6"> -->
|
||||
<p class="text-2xl font-semibold leading-none tracking-tighter lg:text-3xl">Print?</p>
|
||||
|
||||
<!-- <div class="flex flex-col space-y-2 mt-6"> -->
|
||||
<div class="grid grid-cols-2 mt-6 gap-2">
|
||||
<a id="printGreeting" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print Greeting
|
||||
</a>
|
||||
<a id="printTodos" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print<br>To-dos
|
||||
</a>
|
||||
<a id="printSudoku" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print Sudoku
|
||||
</a>
|
||||
<a id="printWordsearch" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print Wordsearch
|
||||
</a>
|
||||
<a id="printQuote" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print Quote
|
||||
</a>
|
||||
<a id="printSentence" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print Sentence
|
||||
</a>
|
||||
<a id="printAll" class="col-span-2 cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-indigo-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Print All
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- <p class="mt-3 text-base leading-relaxed text-center">I am a fullstack software developer with ReactJS for frontend and NodeJS for backend</p> -->
|
||||
<!-- <div class="rese"> -->
|
||||
<!-- <div id="radios"> -->
|
||||
<!-- <input id="rad1" type="radio" name="radioBtn" checked>
|
||||
<label class="labels" for="rad1">
|
||||
<span class="flex flex-col">
|
||||
<span class="font-semibold">Start</span>
|
||||
<span id="startTimeLabel">12:59 am</span>
|
||||
</span>
|
||||
</label>
|
||||
<input id="rad2" type="radio" name="radioBtn">
|
||||
<label class="labels" for="rad2">
|
||||
<span class="flex flex-col">
|
||||
<span class="font-semibold">End</span>
|
||||
<span id="endTimeLabel">12:59 pm</span>
|
||||
</span>
|
||||
</label>
|
||||
<input id="rad3" type="radio" name="radioBtn">
|
||||
<label class="labels" for="rad3">Third Option</label> -->
|
||||
|
||||
<!-- <div id="bckgrnd"></div> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div class="mt-6 w-full h-full"> -->
|
||||
<!-- <div class="flex flex-row space-x-1 items-center justify-center"> -->
|
||||
<!-- <input id="timeInput" class="h-11 rounded-lg p-4" style="background-color:rgba(239,239,240,1);" type="time" name="time" value="12:59"> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div id="quickSelectButtons" class="flex flex-row space-x-1 items-center justify-center flex-wrap"> -->
|
||||
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<div class="w-full mt-6">
|
||||
<a id="printExitButton" class="cursor-pointer flex text-center items-center justify-center w-full pt-4 pr-10 pb-4 pl-10 text-base
|
||||
font-medium text-white bg-slate-600 rounded-xl transition duration-500 ease-in-out transform
|
||||
hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">Exit</a>
|
||||
<!-- <input class="bg-blue-400 z-99" type="number" inputmode="numeric"/> -->
|
||||
<!-- <input type="number" pattern="[0-9]*" /> -->
|
||||
<!-- <input class="w-full bg-slate-200 absolute top-0 left-0 z-50" type="number" name="test" inputmode="decimal"> -->
|
||||
</div>
|
||||
<div>
|
||||
<!-- <input type="number" inputmode="numeric"/> -->
|
||||
<!-- <input type="number" pattern="\d*"/> -->
|
||||
<!-- <input class="fixed bg-slate-200 top-0 left-0 z-50" type="number" name="test" inputmode="decimal"> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- nice colour: bg-gray-800 -->
|
||||
<div id="timePickerWindow" class="absolute w-full h-full overflow-y-hidden top-0 left-0 hidden">
|
||||
<div class="flex flex-row w-full justify-center items-center text-center h-screen">
|
||||
@ -142,6 +238,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
<div class="p-2 bg-white shadow-md rounded-lg border m-2 flex flex-row space-x-2">
|
||||
<button id="prevDayButton" class="bg-slate-200 p-2 w-1/4 rounded-md font-semibold"><- Prev</button>
|
||||
<button id="nextDayButton" class="bg-slate-200 p-2 w-3/4 rounded-md font-semibold">Next -></button>
|
||||
</div>
|
||||
|
||||
<!-- jsDelivr :: Sortable :: Latest (https://www.jsdelivr.com/package/npm/sortablejs) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
@ -226,33 +327,34 @@
|
||||
}
|
||||
});
|
||||
token.then(t => {
|
||||
document.getElementById("loginPanel").classList.add("hidden")
|
||||
console.log(t)
|
||||
// document.getElementById("loginPanel").classList.add("hidden")
|
||||
// console.log(t)
|
||||
jToken = t
|
||||
getTodosFromAPI()
|
||||
|
||||
// document.getElementById("testToken").innerHTML = t
|
||||
|
||||
fetch('/api/todos/get?' + new URLSearchParams({
|
||||
date: dayjs().format("YYYY-MM-DD"),
|
||||
}), {
|
||||
method: 'GET',
|
||||
withCredentials: true,
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Authorization': "Bearer " + t,
|
||||
}
|
||||
}).then(re => {
|
||||
re.json().then(jso => {
|
||||
console.log(jso)
|
||||
for (let todo of jso.todos) {
|
||||
console.log(todo)
|
||||
// function addTask(defaultTimeRange="", defaultTaskText="New Task", editable=true) {
|
||||
addTask(defaultTimeRange=todo.time, defaultTaskText=todo.text, editable=false)
|
||||
}
|
||||
})
|
||||
// var items = JSON.parse(re.json())
|
||||
// console.log(items.json)
|
||||
})
|
||||
// fetch('/api/todos/get?' + new URLSearchParams({
|
||||
// date: dayjs().format("YYYY-MM-DD"),
|
||||
// }), {
|
||||
// method: 'GET',
|
||||
// withCredentials: true,
|
||||
// credentials: 'include',
|
||||
// headers: {
|
||||
// 'Authorization': "Bearer " + t,
|
||||
// }
|
||||
// }).then(re => {
|
||||
// re.json().then(jso => {
|
||||
// console.log(jso)
|
||||
// for (let todo of jso.todos) {
|
||||
// console.log(todo)
|
||||
// // function addTask(defaultTimeRange="", defaultTaskText="New Task", editable=true) {
|
||||
// addTask(defaultTimeRange=todo.time, defaultTaskText=todo.text, editable=false)
|
||||
// }
|
||||
// })
|
||||
// // var items = JSON.parse(re.json())
|
||||
// // console.log(items.json)
|
||||
// })
|
||||
|
||||
//TODO: Make call with token to backend to load all current todos
|
||||
})
|
||||
@ -261,6 +363,39 @@
|
||||
|
||||
};
|
||||
|
||||
|
||||
function getTodosFromAPI() {
|
||||
document.getElementById("loginPanel").classList.add("hidden")
|
||||
console.log(t)
|
||||
// jToken = t
|
||||
|
||||
// document.getElementById("testToken").innerHTML = t
|
||||
|
||||
fetch('/api/todos/get?' + new URLSearchParams({
|
||||
date: dayjs().format("YYYY-MM-DD"),
|
||||
}), {
|
||||
method: 'GET',
|
||||
withCredentials: true,
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Authorization': "Bearer " + t,
|
||||
}
|
||||
}).then(re => {
|
||||
re.json().then(jso => {
|
||||
console.log(jso)
|
||||
for (let todo of jso.todos) {
|
||||
console.log(todo)
|
||||
// function addTask(defaultTimeRange="", defaultTaskText="New Task", editable=true) {
|
||||
addTask(defaultTimeRange=todo.time, defaultTaskText=todo.text, editable=false)
|
||||
}
|
||||
})
|
||||
// var items = JSON.parse(re.json())
|
||||
// console.log(items.json)
|
||||
})
|
||||
|
||||
//TODO: Make call with token to backend to load all current todos
|
||||
}
|
||||
|
||||
document.getElementById("loginButton").addEventListener('click', loginAction)
|
||||
// document.getElementById("loginButton").addEventListener('click', (e) => {
|
||||
// auth0.createAuth0Client({
|
||||
|
@ -118,6 +118,8 @@ function blurOrKeypress(e) {
|
||||
e.target.parentElement.parentElement.parentElement.removeChild(e.target.parentElement.parentElement)
|
||||
// return
|
||||
}
|
||||
|
||||
setsavePrintButton(save=true)
|
||||
// }
|
||||
|
||||
|
||||
@ -301,6 +303,7 @@ function addTask(defaultTimeRange="", defaultTaskText="New Task", editable=true)
|
||||
timePickerWindowButton.addEventListener("click", showTimePickerWindow)
|
||||
timeslotSpan.addEventListener("mousedown", timeSlotShowTimePickerButton)
|
||||
row.addEventListener('click', singleClickListener);
|
||||
setsavePrintButton(save=true)
|
||||
|
||||
// ed.firstChild.focus()
|
||||
|
||||
@ -406,6 +409,7 @@ function quickButtonListener(e) {
|
||||
|
||||
|
||||
function saveButtonListener(e) {
|
||||
setsavePrintButton(save=true)
|
||||
let startTime = dayjs(document.getElementById("startTimeLabel").innerHTML, 'h:mm a')
|
||||
let endTime = dayjs(document.getElementById("endTimeLabel").innerHTML, 'h:mm a')
|
||||
console.log('??')
|
||||
@ -465,6 +469,7 @@ function showTimePickerWindow(e) {
|
||||
console.log(e.target.dataset.timepickershown)
|
||||
if (this.dataset.timepickershown === 'true') return;
|
||||
|
||||
setsavePrintButton(save=true)
|
||||
this.dataset.timepickershown = true
|
||||
|
||||
// document.getElementById("")
|
||||
@ -490,6 +495,7 @@ function timeSlotShowTimePickerButton(e) {
|
||||
console.log('yay!')
|
||||
if (this.parentElement.parentElement.querySelector(".timePickerWindowButton").dataset.timepickershown === 'true') return;
|
||||
console.log('woohoo')
|
||||
setsavePrintButton(save=true)
|
||||
this.parentElement.parentElement.querySelector(".timePickerWindowButton").dataset.timepickershown = true
|
||||
|
||||
let times = this.parentElement.parentElement.querySelector(".timePickerWindowButton").querySelector("#timeButtonDisplay").innerHTML.split(" to ")
|
||||
@ -514,6 +520,7 @@ function recurringButtonListener(e) {
|
||||
|
||||
// TODO: change colour to green
|
||||
//
|
||||
setsavePrintButton(save=true)
|
||||
|
||||
if (this.parentElement.parentElement.dataset.recurring === "true") {
|
||||
this.querySelector("svg").classList.add("text-black")
|
||||
@ -528,31 +535,106 @@ function recurringButtonListener(e) {
|
||||
}
|
||||
|
||||
|
||||
function setsavePrintButton(save=true) {
|
||||
let spb = document.getElementById("savePrintButton")
|
||||
let spbt = document.getElementById("savePrintButtonText")
|
||||
|
||||
if (!save) {
|
||||
spbt.innerHTML = "Print"
|
||||
spb.classList.add("bg-indigo-200")
|
||||
spb.classList.add("border-indigo-300")
|
||||
spb.classList.remove("bg-green-200")
|
||||
spb.classList.remove("border-green-300")
|
||||
//bg-indigo-200 border-indigo-300
|
||||
} else {
|
||||
spbt.innerHTML = "Save"
|
||||
spb.classList.remove("bg-indigo-200")
|
||||
spb.classList.remove("border-indigo-300")
|
||||
spb.classList.add("bg-green-200")
|
||||
spb.classList.add("border-green-300")
|
||||
//bg-green-200 border-green-300
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function savePrintButtonListener(e) {
|
||||
|
||||
|
||||
let spbt = document.getElementById("savePrintButtonText")
|
||||
|
||||
if (spbt.innerHTML === "Save") {
|
||||
spbt.innerHTML = "Print"
|
||||
this.classList.add("bg-indigo-200")
|
||||
this.classList.add("border-indigo-300")
|
||||
this.classList.remove("bg-green-200")
|
||||
this.classList.remove("border-green-300")
|
||||
//bg-indigo-200 border-indigo-300
|
||||
setsavePrintButton(save=false)
|
||||
//TODO: send api request to save todos to database
|
||||
|
||||
} else if (spbt.innerHTML === "Print") {
|
||||
spbt.innerHTML = "Save"
|
||||
this.classList.remove("bg-indigo-200")
|
||||
this.classList.remove("border-indigo-300")
|
||||
this.classList.add("bg-green-200")
|
||||
this.classList.add("border-green-300")
|
||||
document.getElementById("printModel").classList.remove("hidden")
|
||||
// setsavePrintButton(save=true)
|
||||
//bg-green-200 border-green-300
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function printButtonListener(e) {
|
||||
let action = ""
|
||||
switch(this.id) {
|
||||
case "printGreeting":
|
||||
action = "greeting"
|
||||
break;
|
||||
case "printTodos":
|
||||
action = "todos"
|
||||
break;
|
||||
case "printSudoku":
|
||||
action = "sudoku"
|
||||
break;
|
||||
case "printWordsearch":
|
||||
action = "wordsearch"
|
||||
break;
|
||||
case "printQuote":
|
||||
action = "quote"
|
||||
break;
|
||||
case "printSentence":
|
||||
action = "sentence"
|
||||
let sentence = prompt("What would you like to print?")
|
||||
break;
|
||||
case "printAll":
|
||||
action = "all"
|
||||
break;
|
||||
case "printExitButton":
|
||||
document.getElementById("printModel").classList.add("hidden")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function switchDayListener(e) {
|
||||
console.log(document.getElementById("date-view").innerHTML)
|
||||
console.log(dayjs(document.getElementById("date-view").innerHTML, "ddd MMM D, YYYY"))
|
||||
let dateView = document.getElementById("date-view")
|
||||
switch (this.id) {
|
||||
case "nextDayButton":
|
||||
dateView.innerHTML = dayjs(dateView.innerHTML.slice(4), "MMM D, YYYY").add(1, 'day').format("ddd MMM D, YYYY")
|
||||
break;
|
||||
case "prevDayButton":
|
||||
dateView.innerHTML = dayjs(dateView.innerHTML.slice(4), "MMM D, YYYY").subtract(1, 'day').format("ddd MMM D, YYYY")
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("nextDayButton").addEventListener("click", switchDayListener)
|
||||
document.getElementById("prevDayButton").addEventListener("click", switchDayListener)
|
||||
|
||||
document.getElementById("printGreeting").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printTodos").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printSudoku").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printWordsearch").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printQuote").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printSentence").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printAll").addEventListener("click", printButtonListener)
|
||||
document.getElementById("printExitButton").addEventListener("click", printButtonListener)
|
||||
|
||||
|
||||
document.getElementById("savePrintButton").addEventListener("click", savePrintButtonListener)
|
||||
|
||||
|
||||
|
@ -56,6 +56,12 @@ class ThermalPrinter():
|
||||
print("Try running `export DYLD_LIBRARY_PATH=/opt/homebrew/lib` if on m1 mac. source: https://github.com/pyusb/pyusb/issues/355#issuecomment-1062798576")
|
||||
raise
|
||||
|
||||
def print_custom(self, text=""):
|
||||
self.p.set(align="left")
|
||||
for l in textwrap.wrap(text, 32):
|
||||
self.p.text(l + "\n")
|
||||
# self.p.text(text)
|
||||
|
||||
def print_greeting(self):
|
||||
self.p.set(align="center")
|
||||
self.p.text(datetime.today().strftime('%Y-%m-%d'))
|
||||
@ -148,8 +154,8 @@ class ThermalPrinter():
|
||||
self.p.set(align="left")
|
||||
# self.p.text(q[0])
|
||||
for l in textwrap.wrap(q[0], 32):
|
||||
self.p.text(l)
|
||||
self.p.text("\n")
|
||||
self.p.text(l + "\n")
|
||||
# self.p.text("\n")
|
||||
self.p.set(align="right")
|
||||
self.p.text(q[1])
|
||||
self.p.text("\n")
|
||||
|
Loading…
Reference in New Issue
Block a user