"""Список заметок""" import tkinter as tk from tkinter import ttk from datetime import datetime from app.config import Config from app.ui.dialogs import ConfirmDialog class NotesList(tk.Frame): """Виджет списка заметок""" def __init__(self, parent, db, on_note_select=None, on_note_delete=None): super().__init__(parent, bg=Config.COLORS['list_bg']) self.db = db self.on_note_select = on_note_select self.on_note_delete = on_note_delete self.notes = [] self.selected_note_id = None self.create_widgets() def create_widgets(self): # Заголовок self.header_label = tk.Label( self, text="Заметки", bg=Config.COLORS['list_bg'], fg=Config.COLORS['fg'], font=('Arial', 12, 'bold') ) self.header_label.pack(fill='x', padx=10, pady=(10, 5)) # Разделитель separator = tk.Frame(self, height=1, bg=Config.COLORS['separator']) separator.pack(fill='x', padx=5) # Canvas и Scrollbar для списка self.canvas = tk.Canvas( self, bg=Config.COLORS['list_bg'], highlightthickness=0 ) self.scrollbar = ttk.Scrollbar( self, orient="vertical", command=self.canvas.yview ) self.notes_frame = tk.Frame(self.canvas, bg=Config.COLORS['list_bg']) self.notes_frame.bind("", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))) self.canvas_window = self.canvas.create_window( (0, 0), window=self.notes_frame, anchor="nw" ) self.canvas.configure(yscrollcommand=self.scrollbar.set) self.canvas.pack(side="left", fill="both", expand=True) self.scrollbar.pack(side="right", fill="y") # Bind для изменения размера self.canvas.bind('', self.on_canvas_configure) # Bind для колесика мыши self.canvas.bind_all("", self.on_mousewheel) def on_canvas_configure(self, event): self.canvas.itemconfig(self.canvas_window, width=event.width) def on_mousewheel(self, event): self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units") def load_notes(self, date): """Загрузить заметки для выбранной даты""" # Очищаем текущий список for widget in self.notes_frame.winfo_children(): widget.destroy() date_str = date.strftime('%Y-%m-%d') self.notes = self.db.get_notes_with_content_by_date(date_str) if not self.notes: empty_label = tk.Label( self.notes_frame, text="Нет заметок\nна этот день", bg=Config.COLORS['list_bg'], fg=Config.COLORS['fg'], font=('Arial', 10), justify='center' ) empty_label.pack(expand=True, pady=20) return for note in self.notes: self.create_note_item(note) def create_note_item(self, note): """Создать элемент списка для заметки""" item_frame = tk.Frame( self.notes_frame, bg=Config.COLORS['list_bg'], cursor='hand2' ) item_frame.pack(fill='x', padx=5, pady=2) # Рамка для элемента content_frame = tk.Frame( item_frame, bg=Config.COLORS['list_bg'], highlightbackground=Config.COLORS['separator'], highlightthickness=1 ) content_frame.pack(fill='x', padx=5, pady=2) # Левая часть с датой date_frame = tk.Frame(content_frame, bg=Config.COLORS['list_bg']) date_frame.pack(side='left', padx=(10, 5), pady=5) # Получаем дату заметки created_at = datetime.strptime( note['created_at'], '%Y-%m-%d %H:%M:%S' ) day_month = created_at.strftime('%d.%m') year = created_at.strftime('%Y') tk.Label( date_frame, text=day_month, bg=Config.COLORS['list_bg'], fg=Config.COLORS['fg'], font=('Arial', 11, 'bold') ).pack(anchor='w') tk.Label( date_frame, text=year, bg=Config.COLORS['list_bg'], fg=Config.COLORS['fg'], font=('Arial', 9) ).pack(anchor='w') # Средняя часть с заголовком title_frame = tk.Frame(content_frame, bg=Config.COLORS['list_bg']) title_frame.pack(side='left', fill='x', expand=True, padx=10, pady=5) title = note.get('title', '') if not title: # Берем первые 22 символа текста content = note.get('content', '') title = content[:22] + ('...' if len(content) > 22 else '') if not title: title = "Пустая заметка" title_label = tk.Label( title_frame, text=title, bg=Config.COLORS['list_bg'], fg=Config.COLORS['fg'], font=('Arial', 10), anchor='w', justify='left' ) title_label.pack(anchor='w') # Кнопка удаления delete_btn = tk.Button( content_frame, text="🗑", command=lambda n=note: self.delete_note(n), bg=Config.COLORS['list_bg'], fg=Config.COLORS['danger'], relief='flat', font=('Arial', 14), cursor='hand2', width=2 ) delete_btn.pack(side='right', padx=(0, 10), pady=5) # Привязываем события клика для выбора заметки for widget in [item_frame, content_frame, date_frame, title_frame, title_label]: widget.bind('', lambda e, n=note: self.select_note(n)) # Подсветка при наведении for widget in [content_frame, date_frame, title_frame]: widget.bind('', lambda e, f=content_frame: f.configure(bg=Config.COLORS['list_selected'])) widget.bind('', lambda e, f=content_frame: f.configure(bg=Config.COLORS['list_bg'])) def select_note(self, note): """Выбрать заметку""" self.selected_note_id = note['id'] # Обновляем визуальное выделение for widget in self.notes_frame.winfo_children(): if isinstance(widget, tk.Frame): for child in widget.winfo_children(): if isinstance(child, tk.Frame): child.configure(bg=Config.COLORS['list_bg']) if self.on_note_select: self.on_note_select(note) def delete_note(self, note): """Удалить заметку с подтверждением""" dialog = ConfirmDialog( self.winfo_toplevel(), "Удаление заметки", "Вы уверены, что хотите удалить эту заметку?" ) self.wait_window(dialog) if dialog.result: self.db.delete_note(note['id']) if self.on_note_delete: self.on_note_delete() # Перезагружаем список if hasattr(self, 'current_date'): self.load_notes(self.current_date) def refresh(self, date): """Обновить список заметок""" self.current_date = date self.load_notes(date)