feat(notes): Improve note editor change detection and UI refinements

This commit is contained in:
cogwheel0
2025-12-06 19:48:33 +05:30
parent df2a921ffd
commit a13a2de7d6

View File

@@ -117,11 +117,22 @@ class _NoteEditorPageState extends ConsumerState<NoteEditorPage> {
} }
void _onContentChanged() { void _onContentChanged() {
if (!_hasChanges && mounted) { if (!mounted || _isLoading) return;
setState(() => _hasChanges = true);
// Check if content actually changed from the saved note
final titleChanged = _note != null && _titleController.text != _note!.title;
final contentChanged =
_note != null && _contentController.text != _note!.markdownContent;
final hasRealChanges = titleChanged || contentChanged;
if (hasRealChanges != _hasChanges) {
setState(() => _hasChanges = hasRealChanges);
} }
if (hasRealChanges) {
_debounceSave(); _debounceSave();
} }
}
void _debounceSave() { void _debounceSave() {
_saveDebounce?.cancel(); _saveDebounce?.cancel();
@@ -378,9 +389,7 @@ class _NoteEditorPageState extends ConsumerState<NoteEditorPage> {
} }
Future<void> _startDictation() async { Future<void> _startDictation() async {
_voiceService ??= VoiceInputService( _voiceService ??= VoiceInputService(api: ref.read(apiServiceProvider));
api: ref.read(apiServiceProvider),
);
try { try {
final ok = await _voiceService!.initialize(); final ok = await _voiceService!.initialize();
@@ -474,10 +483,12 @@ class _NoteEditorPageState extends ConsumerState<NoteEditorPage> {
canPop: !_hasChanges, canPop: !_hasChanges,
onPopInvokedWithResult: (didPop, result) async { onPopInvokedWithResult: (didPop, result) async {
if (didPop) return; // Already popped, nothing to do if (didPop) return; // Already popped, nothing to do
// Capture navigator before async gap
final navigator = Navigator.of(context);
// Save changes before allowing pop // Save changes before allowing pop
await _saveNote(showFeedback: false); await _saveNote(showFeedback: false);
if (!mounted) return; if (!mounted) return;
Navigator.of(context).pop(); navigator.pop();
}, },
child: ErrorBoundary( child: ErrorBoundary(
child: Scaffold( child: Scaffold(
@@ -572,7 +583,9 @@ class _NoteEditorPageState extends ConsumerState<NoteEditorPage> {
// Generate title button - aligned with other header icons // Generate title button - aligned with other header icons
AnimatedOpacity( AnimatedOpacity(
opacity: _titleFocusNode.hasFocus && !_isGeneratingTitle ? 1.0 : 0.0, opacity: _titleFocusNode.hasFocus && !_isGeneratingTitle
? 1.0
: 0.0,
duration: const Duration(milliseconds: 150), duration: const Duration(milliseconds: 150),
child: IgnorePointer( child: IgnorePointer(
ignoring: !_titleFocusNode.hasFocus || _isGeneratingTitle, ignoring: !_titleFocusNode.hasFocus || _isGeneratingTitle,
@@ -909,11 +922,7 @@ class _NoteEditorPageState extends ConsumerState<NoteEditorPage> {
), ),
), ),
) )
: Icon( : Icon(icon, color: color ?? theme.iconPrimary, size: IconSize.lg),
icon,
color: color ?? theme.iconPrimary,
size: IconSize.lg,
),
); );
if (showMenu) { if (showMenu) {