6 Commits

14 changed files with 669 additions and 198 deletions

View File

@@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import ToDoList, ToDoItem from .models import ToDoList
class ToDoListAdmin(admin.ModelAdmin): class ToDoListAdmin(admin.ModelAdmin):
@@ -9,11 +9,4 @@ class ToDoListAdmin(admin.ModelAdmin):
list_editable = ["title"] list_editable = ["title"]
class ToDoItemAdmin(admin.ModelAdmin):
model = ToDoItem
list_display = ["parent", "finished", "text", "created_at"]
list_editable = ["finished", "text"]
admin.site.register(ToDoList, ToDoListAdmin) admin.site.register(ToDoList, ToDoListAdmin)
admin.site.register(ToDoItem, ToDoItemAdmin)

View File

@@ -1,62 +1,20 @@
from rest_framework import viewsets, serializers, permissions from rest_framework import viewsets, serializers, permissions
from rest_framework import routers from rest_framework import routers
from django_filters.rest_framework import DjangoFilterBackend
from .models import ToDoList, ToDoItem from .models import ToDoList
class ToDoListField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
user = self.context["request"].user
return ToDoList.objects.filter(user=user)
class ToDoItemSerializer(serializers.HyperlinkedModelSerializer):
parent = ToDoListField(many=False, read_only=False, help_text="ID родительского списка")
class Meta:
model = ToDoItem
fields = ["id", "text", "finished", "created_at", "parent"]
class ToDoItemViewSet(viewsets.ModelViewSet):
serializer_class = ToDoItemSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [DjangoFilterBackend]
filterset_fields = ["parent", "finished"]
def get_queryset(self):
user = self.request.user
if not user.is_authenticated:
# ветка только для генерации схемы
return ToDoItem.objects.all()
return ToDoItem.objects.filter(parent__user=user)
class ToDoListSerializer(serializers.HyperlinkedModelSerializer): class ToDoListSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = ToDoList model = ToDoList
fields = ["id", "title", "created_at"] fields = ["title", "created_at"]
def create(self, validated_data):
todo_list = ToDoList.objects.create(
user=self.context["request"].user, title=validated_data["title"]
)
return todo_list
class ToDoListViewSet(viewsets.ModelViewSet): class ToDoListViewSet(viewsets.ModelViewSet):
queryset = ToDoList.objects.all()
serializer_class = ToDoListSerializer serializer_class = ToDoListSerializer
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
if not user.is_authenticated:
# ветка только для генерации схемы
return ToDoList.objects.all()
return ToDoList.objects.filter(user=user)
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register(r"lists", ToDoListViewSet, basename="ToDoLists") router.register(r"lists", ToDoListViewSet)
router.register(r"todo_items", ToDoItemViewSet, basename="ToDoItems")

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2 on 2021-04-17 11:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("backend", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="todoitem",
name="finished",
field=models.BooleanField(default=False),
),
]

View File

@@ -1,28 +0,0 @@
# Generated by Django 3.2 on 2021-04-17 11:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("backend", "0002_todoitem_finished"),
]
operations = [
migrations.AlterField(
model_name="todoitem",
name="created_at",
field=models.DateTimeField(auto_now_add=True, db_index=True),
),
migrations.AlterField(
model_name="todoitem",
name="finished",
field=models.BooleanField(db_index=True, default=False),
),
migrations.AlterField(
model_name="todolist",
name="created_at",
field=models.DateTimeField(auto_now_add=True, db_index=True),
),
]

View File

@@ -5,11 +5,10 @@ from django.contrib.auth.models import User
class ToDoList(models.Model): class ToDoList(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, default=None) user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, default=None)
title = models.CharField(max_length=250) title = models.CharField(max_length=250)
created_at = models.DateTimeField(auto_now_add=True, db_index=True) created_at = models.DateTimeField(auto_now_add=True)
class ToDoItem(models.Model): class ToDoItem(models.Model):
parent = models.ForeignKey(ToDoList, on_delete=models.CASCADE, null=False, default=None) parent = models.ForeignKey(ToDoList, on_delete=models.CASCADE, null=False, default=None)
text = models.TextField() text = models.TextField()
finished = models.BooleanField(default=False, null=False, db_index=True) created_at = models.DateTimeField(auto_now_add=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)

View File

@@ -28,7 +28,7 @@ DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []
if DEBUG: if DEBUG:
ALLOWED_HOSTS = ["0.0.0.0", "localhost", "127.0.0.1"] ALLOWED_HOSTS = ["0.0.0.0"]
# Application definition # Application definition
@@ -45,7 +45,13 @@ INSTALLED_APPS = [
] ]
SWAGGER_SETTINGS = { SWAGGER_SETTINGS = {
"SECURITY_DEFINITIONS": {"Bearer": {"type": "apiKey", "name": "Authorization", "in": "header"}} 'SECURITY_DEFINITIONS': {
'Bearer': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
}
}
} }
MIDDLEWARE = [ MIDDLEWARE = [
@@ -124,12 +130,7 @@ SIMPLE_JWT = {
} }
REST_FRAMEWORK = { REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ( "DEFAULT_AUTHENTICATION_CLASSES": ("rest_framework_simplejwt.authentication.JWTAuthentication",)
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 100,
} }

View File

@@ -1,5 +1,4 @@
djangorestframework==3.12.4 djangorestframework==3.12.4
django-filter==2.4.0
markdown==3.3.4 markdown==3.3.4
appdirs==1.4.4 appdirs==1.4.4
asgiref==3.3.4 asgiref==3.3.4

218
frontend/api.py Normal file
View File

@@ -0,0 +1,218 @@
from types import SimpleNamespace
import urllib
import requests
DEFAULT_URL = "http://127.0.0.1:8000"
API_TODO_ITEMS_LIST = "api/todo_items/"
API_TODO_ITEMS_CREATE = "api/todo_items/"
API_TODO_ITEMS_READ = "api/todo_items/{0}/"
API_TODO_ITEMS_UPDATE = "api/todo_items/{0}/"
API_TODO_ITEMS_PARTIAL_UPDATE = "api/todo_items/{0}/"
API_TODO_ITEMS_DELETE = "api/todo_items/{0}/"
API_LISTS_LIST = "api/lists/"
API_LISTS_CREATE = "api/lists/"
API_LISTS_READ = "lists/{0}/"
API_LISTS_UPDATE = "lists/{0}/"
API_LISTS_PARTIAL_UPDATE = "lists/{0}/"
API_LISTS_DELETE = "lists/{0}/"
API_TOKEN = "api/token/"
class UserApi(object):
def __init__(self, url=DEFAULT_URL, token=None):
"""
Constructor
Parameters
----------
url : str, optional
Server url. The default is DEFAULT_URL.
token : dict, optional
Existing user tokens to bypass authorization.
The default is None.
Returns
-------
None.
"""
self.token = token
self.get_api = lambda x: urllib.parse.urljoin(url, x)
# ToDo - store tokens in config
def auth(self, user, passwd):
"""
Authosization
Parameters
----------
user : str
Login.
passwd : str
Password.
Returns
-------
dict
Generated auth token.
"""
token = UserApi._raise_or_return_(
requests.post(url=self.get_api(API_TOKEN), json={"username": user, "password": passwd})
)
self.token = SimpleNamespace(**token)
return self.token
def lists_list(self, **argv):
"""
List all the exsiting to-do lists.
Auth required
Returns
-------
list
to-do lists.
"""
return UserApi._raise_or_return_(
requests.get(
url=self.get_api(API_LISTS_LIST), headers=self._access_token_(), params=argv
)
)
def lists_create(self, title="Untitled"):
"""
Create a new to-do list
Auth required
Parameters
----------
title : str, optional
New list name. The default is "Untitled".
"""
return UserApi._raise_or_return_(
requests.post(
url=self.get_api(API_LISTS_CREATE),
json={"title": title},
headers=self._access_token_(),
)
)
def todo_items_list(self, **argv):
"""
List all the exsiting to-do items.
Auth required
Returns
-------
list
to-do items.
"""
return UserApi._raise_or_return_(
requests.get(
url=self.get_api(API_TODO_ITEMS_LIST), headers=self._access_token_(), params=argv
)
)
# def create(self, title="Untitled"):
# """
# Create a new to-do list
# Auth required
# Parameters
# ----------
# title : str, optional
# New list name. The default is "Untitled".
# """
# response = requests.post(
# url=self.get_api(API_LISTS_CREATE), json={"title": title}, headers=self._access_token_()
# url=self.get_api(API_TODO_ITEMS_CREATE), json={"title": title}, headers=self._access_token_()
# )
# response.raise_for_status()
# return response.json()
# def read(self, id):
# """
# Read a to-do list contents
# Parameters
# ----------
# id : int
# List id.
# Returns
# -------
# list
# Requested contents
# """
# response = requests.post(
# url=self.get_api(API_LISTS_READ).format(id), headers=self._access_token_()
# )
# response.raise_for_status()
# return response.json()
# def update(self, id, title="Untitled"):
# """
# Add a to-do item to the list
# Parameters
# ----------
# id : int
# List id.
# title : str, optional
# To-do item title. The default is "Untitled".
# """
# response = requests.put(
# json={"title": title},
# url=self.get_api(API_LISTS_UPDATE).format(id),
# headers=self._access_token_(),
# )
# response.raise_for_status()
# return response.json()
# def partial_update(self, id, title="Untitled"):
# """
# Update list item - untrusted
# """
# response = requests.patch(
# json={"title": title},
# url=self.get_api(API_LISTS_PARTIAL_UPDATE).format(id),
# headers=self._access_token_(),
# )
# response.raise_for_status()
# return response.json()
# def delete(self, id):
# """
# Delete list
# Parameters
# ----------
# id : int
# List id to delete.
# """
# response = requests.delete(
# url=self.get_api(API_LISTS_DELETE).format(id), headers=self._access_token_()
# )
# response.raise_for_status()
# return response.json()
def _access_token_(self):
if self.token is None:
raise RuntimeError("Authosization required for requested operation!")
return {"Authorization": f"Bearer {self.token.access}"}
@staticmethod
def _raise_or_return_(response):
response.raise_for_status()
return response.json()

48
frontend/api_demo.py Normal file
View File

@@ -0,0 +1,48 @@
from user import User
def print_lists(lists):
for item in lists:
print(f"List: '{item}'", f"Id: {item.id}", "|", "|".join([str(x) for x in item.items]))
DEFAULT_URL = "http://127.0.0.1:8000"
user = User(url=DEFAULT_URL)
user.auth("root", "root")
# Fetch existing lists:
lists = user.fetchUserLists()
print("Fecthing...")
print_lists(lists)
# Remove user list by id:
user.removeUserList(5)
lists = user.fetchUserLists()
print(f"Removing {5}...")
print_lists(lists)
# Append a new list to user:
print("Appending list...")
scroll = user.appendUserList(title="a new list!")
print_lists(lists)
# Modify list 0:
print("Modifyng list...")
lists[0].modify(title="A new title")
print_lists(lists)
# Append item to list:
print("Appending item to last list...")
item = lists[-1].append(text="this is an item")
print_lists(lists)
# Modifying item
print("Modifyng appended item...")
item.modify(finished=True, text="this is an updated item")
print_lists(lists)
# Removing item at 0
print("Removing item 0 from list 0...")
lists[0].remove(0)
print_lists(lists)

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:
"""
Функция инициаизации класса
"""
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,10 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys import sys
import tkinter as tk import tkinter as tk
from tkinter import messagebox as mb from login import LoginFrame
from user import User from workspace import WorkSpaceFrame
if 'win' in sys.platform.lower(): if "win" in sys.platform.lower():
DEFAULT_URL = "http://localhost:8000" DEFAULT_URL = "http://localhost:8000"
else: else:
DEFAULT_URL = "http://0.0.0.0:8000" DEFAULT_URL = "http://0.0.0.0:8000"
@@ -12,102 +13,43 @@ else:
BASE_W = 580 BASE_W = 580
BASE_H = 400 BASE_H = 400
TITLE_APP = "ToDo Application"
class Application(tk.Frame):
def __init__(self,
master=None
) -> None:
"""
Функция инициаизации класса
"""
super().__init__(master)
#Иницализируем параметры окна class Application(tk.Tk):
self.master = master def __init__(self):
self.pack(fill=tk.BOTH, expand=1) super().__init__()
self.center_window()
self.title(TITLE_APP)
self.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W) def login(self):
tk.Grid.rowconfigure(master, 0, weight=1) """Возвращает пользователя - его можно потом сериализовать"""
tk.Grid.columnconfigure(master, 0, weight=1) self.frame = LoginFrame(master=self, url=DEFAULT_URL)
while not self.frame.loggedIn:
self.update_idletasks()
self.update()
self.frame.destroy()
return self.frame.user
# Иницализируем параметры пользователя def main(self, user):
self.user = User(url=DEFAULT_URL) self.frame = WorkSpaceFrame(master=self, user=user)
self.mainloop()
# Настраиваем размеры и включаем иницализацию def center_window(self, width: str = BASE_W, heigh: str = BASE_H) -> None:
self.centerWindow()
self.initAUTH()
def centerWindow(self,
width: str = BASE_W,
heigh: str = BASE_H
) -> None:
""" """
Центрирует приложение по центру экрана Центрирует приложение по центру экрана
:param width: ширина окна :param width: ширина окна
:param heigh: высота окна :param heigh: высота окна
""" """
sw = self.master.winfo_screenwidth() sw = self.winfo_screenwidth()
sh = self.master.winfo_screenheight() sh = self.winfo_screenheight()
x = (sw - width) / 2 x = (sw - width) / 2
y = (sh - heigh) / 2 y = (sh - heigh) / 2
self.master.geometry('%dx%d+%d+%d' % (width, heigh, x, y)) self.geometry("%dx%d+%d+%d" % (width, heigh, x, y))
def login_clicked(self) -> None:
"""
Функция авторизации
"""
try:
self.user.auth(self.login.get(), self.password.get())
except Exception as ex:
print(ex)
self.show_info()
def show_info(selfб,
msg: str = None
) -> None:
"""
Показывает передаваемое сообщение в messagebox
:param msg: передаваемое сообщение
"""
if msg is None:
msg = "Неправильный логин или пароль"
mb.showinfo("Информация", msg)
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")
if __name__ == "__main__": if __name__ == "__main__":
master = tk.Tk() app = Application()
app = Application(master) app.main(app.login())
app.master.title("ToDo")
app.mainloop()

108
frontend/user.py Normal file
View File

@@ -0,0 +1,108 @@
import os
from datetime import datetime
from api import UserApi
class ToDoList(object):
def __init__(self, id, title, created_at=None, items=[], parent=None):
self.id = id
self.title = title
self.items = items
self.created_at = created_at
def __iter__(self):
for item in self.items:
yield item
def __getitem__(self, index):
return self.items[index]
def __len__(self):
return len(self.items)
def __str__(self):
return f"[{self.id}] {self.title}"
def index(self, value):
return self.items.index(value)
# ToDo
def remove(self, index):
self.items.remove(self.items[index])
self.sync()
# ToDo
def append(self, text):
item = ToDoItem(id=None, text=text, created_at=datetime.now())
self.items.append(item)
item.sync()
self.sync()
return item
def modify(self, **argv):
for key, value in argv.items():
setattr(self, key, value)
self.sync()
# ToDo
def sync(self):
# ToDo send request or store in form
print(f"Item '{self}' is being synchronized...")
class ToDoItem(object):
def __init__(self, id, text, finished=False, created_at=None, parent=None):
self.id = id
self.text = text
self.finished = finished
self.created_at = created_at
def __str__(self):
return f"[{self.id}] {self.text}"
def modify(self, **argv):
for key, value in argv.items():
setattr(self, key, value)
self.sync()
# ToDo
def sync(self):
# ToDo send request or store in form
print(f"Item '{self}' is being synchronized...")
class User(UserApi):
def auth(self, user, passwd):
if "DEBUG" in os.environ:
return
UserApi.auth(self, user, passwd)
# ToDo
items = [
ToDoList(
id=i,
title=f"List {i}",
created_at=datetime.now(),
items=[
ToDoItem(id=i * 10 + j, text=f"Item {i*10+j}", created_at=datetime.now())
for j in range(10)
],
)
for i in range(10)
]
# ToDo
def fetchUserLists(self):
return self.items
# ToDo
def removeUserList(self, id):
self.items = [item for item in self.items if item.id != id]
# ToDo
def appendUserList(self, title):
item = ToDoList(id=None, title=title, created_at=datetime.now())
self.items.append(item)
item.sync()
return item

163
frontend/workspace.py Normal file
View File

@@ -0,0 +1,163 @@
import tkinter as tk
def str_time(time):
return time.strftime("%Y-%m-%d %H:%M:%S")
TODO_ITEM_TABLE_TEXT_WIDTH = 15
TODO_ITEM_TABLE_FINISHED_WIDTH = 8
TODO_ITEM_TABLE_CREATED_AT_WIDTH = 15
def placeholder():
print("Не реализовано")
class ToDoItemWidget(tk.Frame):
@staticmethod
def header(parent):
body = tk.Frame(parent)
text = tk.Label(body, text="Текст", width=TODO_ITEM_TABLE_TEXT_WIDTH)
text.pack(side="left")
text = tk.Label(body, text="Выполнено", width=TODO_ITEM_TABLE_FINISHED_WIDTH)
text.pack(side="left")
text = tk.Label(body, text="Создано", width=TODO_ITEM_TABLE_CREATED_AT_WIDTH)
text.pack(side="left")
return body
def __init__(self, *args, item, **argv):
super().__init__(*args, **argv)
self.parent = self.master
self.item = item
self.noteLabel = tk.Label(self, text=item.text, width=TODO_ITEM_TABLE_TEXT_WIDTH)
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,
width=TODO_ITEM_TABLE_FINISHED_WIDTH,
)
self.finishedButton.pack(side="left")
self.createdAt = tk.Label(
self, text=str_time(item.created_at), width=TODO_ITEM_TABLE_CREATED_AT_WIDTH
)
self.createdAt.pack(side="left")
self.remove = tk.Button(self, text="Удалить", command=lambda: self.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):
header = ToDoItemWidget.header(self)
header.pack(side="left")
header.pack(side="top", fill="y")
self.itemList = itemList
for item in itemList:
item = ToDoItemWidget(self, item=item)
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")
delete = tk.Button(self, text="Удалить лист", command=placeholder)
delete.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()
text = tk.Text(self, width=15, height=1)
text.pack(anchor="sw")
add = tk.Button(self, text="Добавить лист", command=placeholder)
add.pack(anchor="sw")
# 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])