Feat 8.frontend development #22

Merged
LazIvanS merged 7 commits from feat_8.frontend_development into develop 2021-04-26 15:37:09 +03:00
5 changed files with 271 additions and 5 deletions
Showing only changes of commit 66beba6b0d - Show all commits

68
frontend/login.py Normal file
View File

@@ -0,0 +1,68 @@
import tkinter as tk
from user import User
import message
class LoginFrame(tk.Frame):
loggedIn = False
def __init__(self, master=None, url=None) -> None:
"""
Функция инициаизации класса
AlekseyLobanov commented 2021-04-23 00:16:45 +03:00 (Migrated from github.com)
Review

Такой комментарий очень похож на очевидный. Очевидные комментари лучше не вставлять, т.к. они только затрудняют чтение

Такой комментарий очень похож на очевидный. Очевидные комментари лучше не вставлять, т.к. они только затрудняют чтение
LazIvanS commented 2021-04-26 13:11:17 +03:00 (Migrated from github.com)
Review

Осталось от кода Александра

Осталось от кода Александра
"""
super().__init__(master)
# Иницализируем параметры окна
self.master = master
self.pack(fill=tk.BOTH, expand=1)
# self.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
# tk.Grid.rowconfigure(master, 0, weight=1)
# tk.Grid.columnconfigure(master, 0, weight=1)
# Иницализируем параметры пользователя
self.user = User(url=url)
# Настраиваем размеры и включаем иницализацию
self.initAUTH()
def login_clicked(self) -> None:
"""
Функция авторизации
"""
try:
self.user.auth(self.login.get(), self.password.get())
self.loggedIn = True
except Exception as ex:
print(ex)
message.invalid_login()
def initAUTH(self) -> None:
"""
Создает окно авторизации программы
"""
# Конфигурируем сетку
for rows in range(25):
tk.Grid.rowconfigure(self, rows, weight=1)
for columns in range(25):
tk.Grid.columnconfigure(self, columns, weight=1)
# Подпись и поле ввода для логина
login_label = tk.Label(self, text="Введите логин")
login_label.grid(row=9, column=12, columnspan=3, rowspan=1, sticky="nsew")
self.login = tk.Entry(self)
self.login.grid(row=10, column=12, columnspan=3, rowspan=1, sticky="nsew")
# Подпись и поле ввода для пароля
password_label = tk.Label(self, text="Введите пароль")
password_label.grid(row=11, column=12, columnspan=3, rowspan=1, sticky="nsew")
self.password = tk.Entry(self, show="*")
self.password.grid(row=12, column=12, columnspan=3, rowspan=1, sticky="nsew")
# Кнопка авториазции
btn = tk.Button(self, text="Войти", command=self.login_clicked)
btn.grid(row=14, column=12, columnspan=3, rowspan=1, sticky="nsew")

20
frontend/message.py Normal file
View File

@@ -0,0 +1,20 @@
from tkinter import messagebox as mb
TITLE_INFO_BOX = "Сообщение!"
MESSAGE_INVALID_LOGIN = "Неправильный логин или пароль"
MESSAGE_EMPTY = "Сдесь могло быть ваше сообщение"
def infobox(msg: str = None) -> None:
"""
Показывает передаваемое сообщение в messagebox
:param msg: передаваемое сообщение
"""
if msg is None:
msg = MESSAGE_EMPTY
mb.showinfo(TITLE_INFO_BOX, msg)
def invalid_login():
infobox(MESSAGE_INVALID_LOGIN)

View File

@@ -1,14 +1,55 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
import tkinter as tk import tkinter as tk
from login import LoginFrame
from workspace import WorkSpaceFrame
if "win" in sys.platform.lower():
DEFAULT_URL = "http://localhost:8000"
else:
DEFAULT_URL = "http://0.0.0.0:8000"
BASE_W = 580
BASE_H = 400
TITLE_APP = "ToDo Application"
class Application(tk.Frame): class Application(tk.Tk):
def __init__(self, master=None): def __init__(self):
super().__init__(master) super().__init__()
self.center_window()
self.title(TITLE_APP)
def login(self):
"""Возвращает пользователя - его можно потом сериализовать"""
self.frame = LoginFrame(master=self, url=DEFAULT_URL)
while not self.frame.loggedIn:
AlekseyLobanov commented 2021-04-26 13:06:20 +03:00 (Migrated from github.com)
Review

Возможно, полезно было бы сохранять JWT токен в отдельный файл, чтобы логиниться только когда токен протухнет

Возможно, полезно было бы сохранять JWT токен в отдельный файл, чтобы логиниться только когда токен протухнет
LazIvanS commented 2021-04-26 13:10:50 +03:00 (Migrated from github.com)
Review

Я там в одном из комментов предлагал сделать юзера json-сериализуемым

Я там в одном из комментов предлагал сделать юзера json-сериализуемым
AlekseyLobanov commented 2021-04-26 13:12:15 +03:00 (Migrated from github.com)
Review

Зачем его сериализовать? Достаточно сохранить просто токен и добавить загрузку этого токена при запуске.
Логин\пароль и другие данные не нужны, их можно подгружать.

Зачем его сериализовать? Достаточно сохранить просто токен и добавить загрузку этого токена при запуске. Логин\пароль и другие данные не нужны, их можно подгружать.
LazIvanS commented 2021-04-26 13:47:59 +03:00 (Migrated from github.com)
Review

Ну пл сути все что будет в сериализации это пара токенов и GUI будет известен только юзер

Ну пл сути все что будет в сериализации это пара токенов и GUI будет известен только юзер
self.update_idletasks()
self.update()
self.frame.destroy()
return self.frame.user
def main(self, user):
self.frame = WorkSpaceFrame(master=self, user=user)
self.mainloop()
def center_window(self, width: str = BASE_W, heigh: str = BASE_H) -> None:
"""
Центрирует приложение по центру экрана
:param width: ширина окна
:param heigh: высота окна
"""
sw = self.winfo_screenwidth()
sh = self.winfo_screenheight()
x = (sw - width) / 2
y = (sh - heigh) / 2
self.geometry("%dx%d+%d+%d" % (width, heigh, x, y))
if __name__ == "__main__": if __name__ == "__main__":
app = Application() app = Application()
app.master.title("ToDo") app.main(app.login())
app.mainloop()

View File

@@ -1,3 +1,5 @@
import os
from datetime import datetime from datetime import datetime
from api import UserApi from api import UserApi
@@ -9,6 +11,10 @@ class ToDoList(object):
self.items = items self.items = items
self.created_at = created_at self.created_at = created_at
def __iter__(self):
for item in self.items:
yield item
def __getitem__(self, index): def __getitem__(self, index):
return self.items[index] return self.items[index]
@@ -18,6 +24,9 @@ class ToDoList(object):
def __str__(self): def __str__(self):
return f"[{self.id}] {self.title}" return f"[{self.id}] {self.title}"
def index(self, value):
return self.items.index(value)
# ToDo # ToDo
def remove(self, index): def remove(self, index):
self.items.remove(self.items[index]) self.items.remove(self.items[index])
@@ -64,6 +73,10 @@ class ToDoItem(object):
class User(UserApi): class User(UserApi):
def auth(self, user, passwd):
if "DEBUG" in os.environ:
return
UserApi.auth(self, user, passwd)
# ToDo # ToDo
items = [ items = [

124
frontend/workspace.py Normal file
View File

@@ -0,0 +1,124 @@
import tkinter as tk
def str_time(time):
return time.strftime("%Y-%m-%d %H:%M:%S")
class ToDoItemWidget(tk.Frame):
def __init__(self, *args, item, parent=None, **argv):
super().__init__(*args, **argv)
self.parent = parent
self.item = item
self.noteLabel = tk.Label(self, text=item.text, width=15)
self.noteLabel.pack(side="left")
self.finished = tk.IntVar(value=int(item.finished))
self.finishedButton = tk.Checkbutton(
self, variable=self.finished, command=self.finishedButton_command
)
self.finishedButton.pack(side="left")
self.createdAt = tk.Label(self, text=str_time(item.created_at), width=15)
self.createdAt.pack(side="left")
self.remove = tk.Button(self, text="Удалить", command=lambda: parent.remove(self.item))
self.remove.pack(side="left")
def finishedButton_command(self):
self.item.modify(finished=self.finished.get() > 0)
class ToDoListWidget(tk.Frame):
def __init__(self, *args, **argv):
super().__init__(*args, **argv)
def fill(self, itemList):
self.header = tk.Label(self, text="Текст | Выполнено | Время создания")
self.header.pack(side="top", fill="y")
self.itemList = itemList
for item in itemList:
item = ToDoItemWidget(self, item=item, parent=self)
item.pack(side="top", fill="y")
self.itemToAdd = tk.Text(self, width=15, height=1)
self.itemToAdd.pack(side="top")
add = tk.Button(self, text="Добавить", command=self.add_command)
add.pack(side="top")
def update(self, itemList=None):
self.clear()
if itemList is None:
self.fill(self.itemList)
else:
self.fill(itemList)
def add_command(self):
self.itemList.append(self.itemToAdd.get(1.0, "end"))
self.update()
def remove(self, item):
self.itemList.remove(self.itemList.index(item))
self.update()
def clear(self):
for widget in self.winfo_children():
widget.destroy()
class WorkSpaceFrame(tk.Frame):
def __init__(self, user, master=None, url=None) -> None:
"""
Функция инициаизации класса
"""
super().__init__(master)
self.master = master
self.user = user
self.pack(fill=tk.BOTH, expand=1)
self.initLayout(user)
def initLayout(self, user):
# data
self.lists = user.fetchUserLists()
# select list box
self.listBox = tk.Listbox(self, width=30, selectmode=tk.SINGLE)
self.listBox.pack(side="left", fill="y")
self.listBox.bind("<<ListboxSelect>>", self.listBox_selected)
# scroll bar
scrollbar = tk.Scrollbar(self, orient="vertical")
scrollbar.config(command=self.listBox.yview)
scrollbar.pack(side="left", fill="y")
# add scroll bar to list box
self.listBox.config(yscrollcommand=scrollbar.set)
# fill list box
for item in self.lists:
s = f"{str(item)}: {item.created_at.strftime('%Y-%m-%d %H:%M:%S')}"
self.listBox.insert(tk.END, s)
self.listBox.pack()
len(self.lists) > 0 and self.listBox.selection_set(first=0)
# todo lists
self.toToList = ToDoListWidget(self)
self.toToList.pack(side="left", fill="both", expand=1)
def listBox_selected(self, *args):
self.toToList.clear()
selection = self.listBox.curselection()
cur = selection[0]
self.toToList.fill(self.lists[cur])