working
This commit is contained in:
commit
a385308f38
44 changed files with 1614 additions and 0 deletions
297
app/ui/note_editor.py
Normal file
297
app/ui/note_editor.py
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
"""Редактор заметок"""
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from datetime import datetime
|
||||
from app.config import Config
|
||||
from app.ui.dialogs import ConfirmDialog
|
||||
|
||||
class NoteEditor(tk.Frame):
|
||||
"""Правая панель с редактором заметок"""
|
||||
|
||||
def __init__(self, parent, db, on_note_saved=None, on_note_deleted=None, on_new_note=None):
|
||||
super().__init__(parent, bg=Config.COLORS['editor_bg'])
|
||||
self.db = db
|
||||
self.on_note_saved = on_note_saved
|
||||
self.on_note_deleted = on_note_deleted
|
||||
self.on_new_note = on_new_note
|
||||
|
||||
self.current_note = None
|
||||
self.is_new_note = False
|
||||
self.is_editing = False
|
||||
|
||||
self.create_widgets()
|
||||
self.show_empty_state()
|
||||
|
||||
def create_widgets(self):
|
||||
# Панель инструментов
|
||||
self.toolbar = tk.Frame(self, bg=Config.COLORS['sidebar_bg'], height=40)
|
||||
self.toolbar.pack(fill='x')
|
||||
self.toolbar.pack_propagate(False)
|
||||
|
||||
# Дата и время (левый край)
|
||||
self.date_label = tk.Label(
|
||||
self.toolbar,
|
||||
text="",
|
||||
bg=Config.COLORS['sidebar_bg'],
|
||||
fg=Config.COLORS['fg'],
|
||||
font=('Arial', 11)
|
||||
)
|
||||
self.date_label.pack(side='left', padx=10)
|
||||
|
||||
# Кнопки (правый край)
|
||||
buttons_frame = tk.Frame(self.toolbar, bg=Config.COLORS['sidebar_bg'])
|
||||
buttons_frame.pack(side='right', padx=5)
|
||||
|
||||
# Кнопка сохранения
|
||||
self.save_btn = tk.Button(
|
||||
buttons_frame,
|
||||
text="💾",
|
||||
command=self.save_note,
|
||||
bg=Config.COLORS['button_bg'],
|
||||
fg=Config.COLORS['fg'],
|
||||
relief='flat',
|
||||
font=('Arial', 14),
|
||||
cursor='hand2',
|
||||
width=2
|
||||
)
|
||||
self.save_btn.pack(side='left', padx=2)
|
||||
|
||||
# Кнопка удаления
|
||||
self.delete_btn = tk.Button(
|
||||
buttons_frame,
|
||||
text="🗑",
|
||||
command=self.delete_current_note,
|
||||
bg=Config.COLORS['button_bg'],
|
||||
fg=Config.COLORS['fg'],
|
||||
relief='flat',
|
||||
font=('Arial', 14),
|
||||
cursor='hand2',
|
||||
width=2
|
||||
)
|
||||
self.delete_btn.pack(side='left', padx=2)
|
||||
|
||||
# Кнопка создания новой заметки
|
||||
self.new_btn = tk.Button(
|
||||
buttons_frame,
|
||||
text="+",
|
||||
command=self.create_new_note,
|
||||
bg=Config.COLORS['accent'],
|
||||
fg=Config.COLORS['fg'],
|
||||
relief='flat',
|
||||
font=('Arial', 14, 'bold'),
|
||||
cursor='hand2',
|
||||
width=2
|
||||
)
|
||||
self.new_btn.pack(side='left', padx=2)
|
||||
|
||||
# Скрываем кнопки сохранения и удаления по умолчанию
|
||||
self.hide_editor_buttons()
|
||||
|
||||
# Область контента
|
||||
self.content_frame = tk.Frame(self, bg=Config.COLORS['editor_bg'])
|
||||
self.content_frame.pack(fill='both', expand=True, padx=10, pady=10)
|
||||
|
||||
# Текстовое поле для редактирования
|
||||
self.text_widget = tk.Text(
|
||||
self.content_frame,
|
||||
bg=Config.COLORS['text_bg'],
|
||||
fg=Config.COLORS['text_fg'],
|
||||
font=('Arial', 12),
|
||||
wrap='word',
|
||||
relief='flat',
|
||||
padx=10,
|
||||
pady=10,
|
||||
insertbackground=Config.COLORS['fg']
|
||||
)
|
||||
|
||||
# Scrollbar для текстового поля
|
||||
self.text_scrollbar = ttk.Scrollbar(
|
||||
self.content_frame,
|
||||
orient='vertical',
|
||||
command=self.text_widget.yview
|
||||
)
|
||||
self.text_widget.configure(yscrollcommand=self.text_scrollbar.set)
|
||||
|
||||
# Метка для пустого состояния
|
||||
self.empty_label = tk.Label(
|
||||
self.content_frame,
|
||||
text="Выберите заметку из списка\nили создайте новую",
|
||||
bg=Config.COLORS['editor_bg'],
|
||||
fg=Config.COLORS['fg'],
|
||||
font=('Arial', 14),
|
||||
justify='center'
|
||||
)
|
||||
self.empty_label.pack(expand=True)
|
||||
|
||||
# Привязываем события изменения текста
|
||||
self.text_widget.bind('<<Modified>>', self.on_text_modified)
|
||||
|
||||
def show_editor_buttons(self):
|
||||
"""Показать кнопки редактора"""
|
||||
self.save_btn.pack(side='left', padx=2)
|
||||
self.delete_btn.pack(side='left', padx=2)
|
||||
|
||||
def hide_editor_buttons(self):
|
||||
"""Скрыть кнопки редактора"""
|
||||
self.save_btn.pack_forget()
|
||||
self.delete_btn.pack_forget()
|
||||
|
||||
def show_empty_state(self):
|
||||
"""Показать пустое состояние"""
|
||||
self.text_widget.pack_forget()
|
||||
self.text_scrollbar.pack_forget()
|
||||
self.empty_label.pack(expand=True)
|
||||
self.date_label.config(text="")
|
||||
self.hide_editor_buttons()
|
||||
self.current_note = None
|
||||
self.is_new_note = False
|
||||
self.is_editing = False
|
||||
|
||||
def show_note(self, note):
|
||||
"""Показать существующую заметку"""
|
||||
self.current_note = note
|
||||
self.is_new_note = False
|
||||
self.is_editing = False
|
||||
|
||||
# Скрываем пустую метку
|
||||
self.empty_label.pack_forget()
|
||||
|
||||
# Показываем текстовое поле
|
||||
self.text_widget.pack(side='left', fill='both', expand=True)
|
||||
self.text_scrollbar.pack(side='right', fill='y')
|
||||
|
||||
# Устанавливаем дату
|
||||
created_at = datetime.strptime(
|
||||
note['created_at'], '%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
self.date_label.config(
|
||||
text=created_at.strftime('%d.%m.%Y %H:%M')
|
||||
)
|
||||
|
||||
# Очищаем и вставляем текст
|
||||
self.text_widget.delete('1.0', 'end')
|
||||
self.text_widget.insert('1.0', note.get('content', ''))
|
||||
self.text_widget.edit_modified(False)
|
||||
|
||||
# Показываем кнопки
|
||||
self.show_editor_buttons()
|
||||
|
||||
# Делаем поле только для чтения
|
||||
self.text_widget.configure(state='disabled')
|
||||
|
||||
# Привязываем клик для редактирования
|
||||
self.text_widget.bind('<Button-1>', self.enable_editing)
|
||||
|
||||
def enable_editing(self, event=None):
|
||||
"""Включить режим редактирования"""
|
||||
if not self.is_editing and self.current_note:
|
||||
self.is_editing = True
|
||||
self.text_widget.configure(state='normal')
|
||||
self.text_widget.unbind('<Button-1>')
|
||||
|
||||
def create_new_note(self):
|
||||
"""Создать новую заметку"""
|
||||
self.current_note = None
|
||||
self.is_new_note = True
|
||||
self.is_editing = True
|
||||
|
||||
# Скрываем пустую метку
|
||||
self.empty_label.pack_forget()
|
||||
|
||||
# Показываем текстовое поле
|
||||
self.text_widget.pack(side='left', fill='both', expand=True)
|
||||
self.text_scrollbar.pack(side='right', fill='y')
|
||||
|
||||
# Устанавливаем текущую дату
|
||||
now = datetime.now()
|
||||
self.date_label.config(text=now.strftime('%d.%m.%Y %H:%M'))
|
||||
|
||||
# Очищаем текстовое поле
|
||||
self.text_widget.delete('1.0', 'end')
|
||||
self.text_widget.configure(state='normal')
|
||||
self.text_widget.edit_modified(False)
|
||||
|
||||
# Показываем кнопки
|
||||
self.show_editor_buttons()
|
||||
|
||||
# Убираем привязку клика
|
||||
self.text_widget.unbind('<Button-1>')
|
||||
|
||||
# Ставим фокус
|
||||
self.text_widget.focus_set()
|
||||
|
||||
if self.on_new_note:
|
||||
self.on_new_note()
|
||||
|
||||
def save_note(self):
|
||||
"""Сохранить заметку"""
|
||||
content = self.text_widget.get('1.0', 'end-1c')
|
||||
|
||||
if not content.strip() and self.is_new_note:
|
||||
messagebox.showwarning(
|
||||
"Предупреждение",
|
||||
"Нельзя сохранить пустую заметку"
|
||||
)
|
||||
return
|
||||
|
||||
if self.is_new_note:
|
||||
# Создаем новую заметку
|
||||
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
note_id = self.db.create_note(
|
||||
title=None,
|
||||
content=content,
|
||||
created_at=now
|
||||
)
|
||||
self.current_note = self.db.get_note_by_id(note_id)
|
||||
self.is_new_note = False
|
||||
self.is_editing = False
|
||||
|
||||
# Делаем поле только для чтения
|
||||
self.text_widget.configure(state='disabled')
|
||||
self.text_widget.bind('<Button-1>', self.enable_editing)
|
||||
|
||||
messagebox.showinfo("Успех", "Заметка сохранена")
|
||||
else:
|
||||
# Обновляем существующую заметку
|
||||
self.db.update_note(
|
||||
self.current_note['id'],
|
||||
content=content
|
||||
)
|
||||
self.current_note = self.db.get_note_by_id(self.current_note['id'])
|
||||
self.is_editing = False
|
||||
|
||||
# Делаем поле только для чтения
|
||||
self.text_widget.configure(state='disabled')
|
||||
self.text_widget.bind('<Button-1>', self.enable_editing)
|
||||
|
||||
messagebox.showinfo("Успех", "Заметка обновлена")
|
||||
|
||||
self.text_widget.edit_modified(False)
|
||||
|
||||
if self.on_note_saved:
|
||||
self.on_note_saved(self.current_note)
|
||||
|
||||
def delete_current_note(self):
|
||||
"""Удалить текущую заметку"""
|
||||
if not self.current_note:
|
||||
return
|
||||
|
||||
dialog = ConfirmDialog(
|
||||
self.winfo_toplevel(),
|
||||
"Удаление заметки",
|
||||
"Вы уверены, что хотите удалить эту заметку?"
|
||||
)
|
||||
self.wait_window(dialog)
|
||||
|
||||
if dialog.result:
|
||||
self.db.delete_note(self.current_note['id'])
|
||||
self.show_empty_state()
|
||||
|
||||
if self.on_note_deleted:
|
||||
self.on_note_deleted()
|
||||
|
||||
def on_text_modified(self, event=None):
|
||||
"""Обработчик изменения текста"""
|
||||
if self.text_widget.edit_modified() and self.current_note and not self.is_editing:
|
||||
# Текст был изменен программно, игнорируем
|
||||
self.text_widget.edit_modified(False)
|
||||
Loading…
Add table
Add a link
Reference in a new issue