using CommunityToolkit.Maui.Views; using NotesDataAnalyst.NoteContent; using System.Text.RegularExpressions; using System.Windows.Input; namespace NotesDataAnalyst { public partial class EditorPage : ContentPage { //Вызываем эмодзи public ICommand ShowEmojiPopupCommand { get; } public ICommand ShowLinkInputCommand { get; } public ICommand InsertHeaderCommand { get; } public ICommand AddLinkCommand { get; } private int listItemCounter = 1; // Счётчик для нумерации в списке private readonly Note _note; private readonly FileSaver _fileSaver; private readonly string _filePath; public EditorPage(Note note = null) { InitializeComponent(); // Инициализация команд // Инициализация команд InsertHeaderCommand = new Command(InsertHeaderTag); // InsertBulletCommand = new Command(InsertBulletPoint); AddLinkCommand = new Command(AddLink); // InsertNumberedListCommand = new Command(InsertNumberedListItem); ShowLinkInputCommand = new Command(ShowLinkInputPopup); //Иницилизируем эмодзи ShowEmojiPopupCommand = new Command(ShowEmojiSelectionPopup); BindingContext = this; // Устанавливаем контекст привязки на текущий объект страницы _note = note ?? new Note(); // Если note не передан, создаём новую заметку _filePath = string.Empty; // Пустой путь указывает на создание новой заметки // Заполняем данные, если это существующая заметка if (_note != null) { categoryPicker.SelectedItem = _note.Category; titleEditor.Text = _note.Title; textEditor.Text = _note.Text; if (!string.IsNullOrEmpty(_note.Image)) { imageButton.Source = ImageSource.FromFile(_note.Image); } } // Настраиваем выбор категории и установку фокуса CategoryManager.LoadCategories(); categoryPicker.ItemsSource = CategoryManager.Categories; categoryPicker.SelectedItem = CategoryManager.ActiveCategory; string basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Notes"); _fileSaver = new FileSaver(basePath); } // Работаем с эмодзи private async void ShowEmojiSelectionPopup() { var emojiPopup = new EmojiSelectionPopup(); // Обработчик выбора смайлика emojiPopup.EmojiSelected += emoji => { InsertEmoji(emoji); // Используем Dispatcher для безопасного вызова Close Application.Current.Dispatcher.Dispatch(() => { if (emojiPopup.Handler != null) // Проверка, что Popup еще не закрыт { emojiPopup.Close(); } }); }; // Отображаем Popup await Application.Current.MainPage.ShowPopupAsync(emojiPopup); } private void InsertEmoji(string emoji) { int cursorPosition = textEditor.CursorPosition; textEditor.Text = textEditor.Text.Insert(cursorPosition, emoji); textEditor.CursorPosition = cursorPosition + emoji.Length; } /////////////////////// /// /// /// ////////////////////////////////////////////////////////////// /// /// // Тэги маркдаун private void InsertHeaderTag() { if (textEditor == null) { Console.WriteLine("textEditor не инициализирован."); return; } // Проверка, если текст пустой if (string.IsNullOrEmpty(textEditor.Text)) { textEditor.Text = "# "; textEditor.CursorPosition = textEditor.Text.Length; return; } int cursorPosition = textEditor.CursorPosition; string newText = cursorPosition == 0 || textEditor.Text[cursorPosition - 1] == '\n' ? "# " : "\n# "; textEditor.Text = textEditor.Text.Insert(cursorPosition, newText); textEditor.CursorPosition = cursorPosition + newText.Length; } private async void ShowLinkInputPopup() { var linkInputPopup = new LinkInputPopup(); // Подписываемся на событие, чтобы получить ссылку и вставить её в текст linkInputPopup.LinkSubmitted += url => { InsertLinkMarkdown(url); }; // Открываем модально await Application.Current.MainPage.Navigation.PushModalAsync(linkInputPopup); } private void InsertLinkMarkdown(string url) { string markdownLink = $"![]({url})"; int cursorPosition = textEditor.CursorPosition; textEditor.Text = textEditor.Text.Insert(cursorPosition, markdownLink); textEditor.CursorPosition = cursorPosition + markdownLink.Length; } /* private void InsertBulletPoint() { if (textEditor == null) { Console.WriteLine("textEditor не инициализирован."); return; } if (string.IsNullOrEmpty(textEditor.Text)) { textEditor.Text = "* "; textEditor.CursorPosition = textEditor.Text.Length; return; } int cursorPosition = textEditor.CursorPosition; string bulletText = "* "; textEditor.Text = textEditor.Text.Insert(cursorPosition, bulletText); textEditor.CursorPosition = cursorPosition + bulletText.Length; textEditor.Completed += (s, e) => { if (!HasTwoEmptyLines(cursorPosition)) { cursorPosition = textEditor.CursorPosition; textEditor.Text = textEditor.Text.Insert(cursorPosition, bulletText); textEditor.CursorPosition = cursorPosition + bulletText.Length; } }; } private void InsertNumberedListItem() { int cursorPosition = textEditor.CursorPosition; string listItemText = $"{listItemCounter}. "; textEditor.Text = textEditor.Text.Insert(cursorPosition, listItemText); textEditor.CursorPosition = cursorPosition + listItemText.Length; // Обновляем номер списка при переходе на новую строку textEditor.Completed += (s, e) => { if (!HasTwoEmptyLines(cursorPosition)) { cursorPosition = textEditor.CursorPosition; listItemCounter++; listItemText = $"{listItemCounter}. "; textEditor.Text = textEditor.Text.Insert(cursorPosition, listItemText); textEditor.CursorPosition = cursorPosition + listItemText.Length; } else { listItemCounter = 1; // Сброс счётчика при двух пустых строках } }; } // Проверка на две пустые строки после позиции курсора private bool HasTwoEmptyLines(int position) { string textAfterCursor = textEditor.Text.Substring(position); return Regex.IsMatch(textAfterCursor, @"\n\s*\n\s*\n"); }*/ //////////////////////////////////////////////////////////////////////////////////////////// private async void AddLink() { var popup = new NoteSelectionPopup(); popup.NoteSelected += OnNoteSelectedForLink; await this.ShowPopupAsync(popup); } private void OnNoteSelectedForLink(Note selectedNote) { textEditor.Text = NoteLinkManager.InsertLink(textEditor.Text, selectedNote); } private async void OnImageTapped(object sender, EventArgs e) { try { var result = await FilePicker.PickAsync(new PickOptions { FileTypes = FilePickerFileType.Images, PickerTitle = "Выберите изображение" }); if (result != null) { _note.Image = result.FullPath; imageButton.Source = ImageSource.FromFile(result.FullPath); } } catch (Exception ex) { await DisplayAlert("Ошибка", $"Не удалось загрузить изображение: {ex.Message}", "OK"); } } private async void SaveButton_Clicked(object sender, EventArgs e) { // Если у заметки нет Id, присваиваем новый Id if (string.IsNullOrEmpty(_note.Id)) { _note.Id = Guid.NewGuid().ToString(); } var note = new Note { Id = _note.Id, Category = categoryPicker.SelectedItem as string, Title = titleEditor.Text, Image = _note.Image, Text = textEditor.Text, FilePath = _filePath }; // Проверка заголовка if (string.IsNullOrEmpty(note.Title)) { // Получаем первые 4 слова из текста var words = note.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries); note.Title = string.Join(" ", words.Take(4)); } //Запись в БД пока отключена await Task.Run(() => App.Database.SaveNote(note)); // Отправляем сообщение для обновления списка заметок на главной странице MessagingCenter.Send(this, "NoteSaved", _note); await DisplayAlert("Success", "Note saved successfully.", "OK"); await Navigation.PushAsync(new MainPage()); } } }