feat: integrate Flutter Quill for rich text editing and update note handling
- Added Flutter Quill package for rich text editing capabilities. - Refactored note body handling to support Quill's Document format. - Updated note editor screen to use QuillEditor and QuillController. - Enhanced note search functionality to convert note body to plain text. - Modified note card display to show plain text from note body. - Updated localization support for Quill in the app. - Registered necessary plugins for URL launching and file selection on all platforms. - Updated app icons and other assets for consistency across platforms. - Updated pubspec.yaml and pubspec.lock to include new dependencies and versions.
This commit is contained in:
@@ -2,8 +2,10 @@ import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_quill/flutter_quill.dart' hide Text;
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:notas/data/note_body.dart';
|
||||
import 'package:notas/models/category.dart';
|
||||
import 'package:notas/models/note.dart';
|
||||
import 'package:notas/platform/app_platform.dart';
|
||||
@@ -110,7 +112,9 @@ class NoteEditorScreen extends StatefulWidget {
|
||||
|
||||
class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||
late TextEditingController _titleController;
|
||||
late TextEditingController _bodyController;
|
||||
late QuillController _bodyController;
|
||||
late FocusNode _bodyFocusNode;
|
||||
late ScrollController _bodyScrollController;
|
||||
late Note _currentNote;
|
||||
late bool _isNewNote;
|
||||
String? _selectedCategoryId;
|
||||
@@ -147,13 +151,20 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||
_selectedCategoryId = _currentNote.categoryId ?? widget.categoryId;
|
||||
|
||||
_titleController = TextEditingController(text: _currentNote.title);
|
||||
_bodyController = TextEditingController(text: _currentNote.body);
|
||||
_bodyController = QuillController(
|
||||
document: noteBodyToDocument(_currentNote.body),
|
||||
selection: const TextSelection.collapsed(offset: 0),
|
||||
);
|
||||
_bodyFocusNode = FocusNode();
|
||||
_bodyScrollController = ScrollController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_closeCategoryMenu();
|
||||
_titleController.dispose();
|
||||
_bodyFocusNode.dispose();
|
||||
_bodyScrollController.dispose();
|
||||
_bodyController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -182,17 +193,17 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||
|
||||
void _saveNote() {
|
||||
final String title = _titleController.text.trim();
|
||||
final String body = _bodyController.text.trim();
|
||||
final String bodyPlainText = _bodyController.document.toPlainText().trim();
|
||||
final bool categoryChanged = _selectedCategoryId != _currentNote.categoryId;
|
||||
|
||||
if (title.isEmpty && body.isEmpty && !categoryChanged) {
|
||||
if (title.isEmpty && bodyPlainText.isEmpty && !categoryChanged) {
|
||||
_complete(null);
|
||||
return;
|
||||
}
|
||||
|
||||
final Note updatedNote = _currentNote.copyWith(
|
||||
title: title.isEmpty ? 'Sin título' : title,
|
||||
body: body,
|
||||
body: noteDocumentToStorageJson(_bodyController.document),
|
||||
categoryId: _selectedCategoryId,
|
||||
updatedAt: DateTime.now(),
|
||||
isDirty: true,
|
||||
@@ -646,21 +657,20 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||
),
|
||||
SizedBox(height: titleSpacing),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _bodyController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
expands: true,
|
||||
style: TextStyle(
|
||||
color: palette.textPrimary,
|
||||
fontSize: 16,
|
||||
height: 1.6,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Escribe tu nota...',
|
||||
hintStyle: TextStyle(color: palette.textHint),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: QuillEditor.basic(
|
||||
controller: _bodyController,
|
||||
focusNode: _bodyFocusNode,
|
||||
scrollController: _bodyScrollController,
|
||||
config: QuillEditorConfig(
|
||||
scrollable: true,
|
||||
padding: EdgeInsets.zero,
|
||||
autoFocus: false,
|
||||
expands: true,
|
||||
placeholder: 'Escribe tu nota...',
|
||||
keyboardAppearance: Theme.of(context).brightness,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -673,21 +683,67 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||
decoration: BoxDecoration(
|
||||
border: Border(top: BorderSide(color: palette.border, width: 1)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!_isNewNote)
|
||||
IconButton(
|
||||
onPressed: _deleteNote,
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: palette.destructiveAccent,
|
||||
QuillSimpleToolbar(
|
||||
controller: _bodyController,
|
||||
config: const QuillSimpleToolbarConfig(
|
||||
color: Colors.transparent,
|
||||
showBoldButton: true,
|
||||
showItalicButton: true,
|
||||
showUnderLineButton: true,
|
||||
showStrikeThrough: false,
|
||||
showInlineCode: false,
|
||||
showColorButton: false,
|
||||
showBackgroundColorButton: false,
|
||||
showClearFormat: false,
|
||||
showAlignmentButtons: false,
|
||||
showHeaderStyle: false,
|
||||
showListNumbers: true,
|
||||
showListBullets: true,
|
||||
showListCheck: true,
|
||||
showCodeBlock: false,
|
||||
showQuote: false,
|
||||
showIndent: false,
|
||||
showLink: false,
|
||||
showUndo: false,
|
||||
showRedo: false,
|
||||
showDividers: false,
|
||||
showFontFamily: false,
|
||||
showFontSize: false,
|
||||
showDirection: false,
|
||||
showSearchButton: false,
|
||||
showSubscript: false,
|
||||
showSuperscript: false,
|
||||
multiRowsDisplay: false,
|
||||
showClipboardCut: false,
|
||||
showClipboardCopy: false,
|
||||
showClipboardPaste: false,
|
||||
axis: Axis.horizontal,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (!_isNewNote)
|
||||
IconButton(
|
||||
onPressed: _deleteNote,
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: palette.destructiveAccent,
|
||||
),
|
||||
tooltip: 'Eliminar nota',
|
||||
)
|
||||
else
|
||||
const SizedBox(width: 48),
|
||||
FilledButton(
|
||||
onPressed: _saveNote,
|
||||
child: const Text('Guardar'),
|
||||
),
|
||||
tooltip: 'Eliminar nota',
|
||||
)
|
||||
else
|
||||
const SizedBox(width: 48),
|
||||
FilledButton(onPressed: _saveNote, child: const Text('Guardar')),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user