Skip to content

Conversation

@jdalbey
Copy link

@jdalbey jdalbey commented Jan 24, 2026

This Pull Request implements External File Change Detection for notes.json.

Overview

Adds real-time detection of external changes to notes.json with user prompts when the file is modified by external processes, sync services, other instances of sticky, or manual edits. Includes confirmation dialogs to prevent data loss. Includes an optional auto-reload preference for frictionless multi-device synchronization.

Evidence of Need

Requests for a feature similar to this appear multiple times in the current open issues list:
#154 #102 #63 #2

Users who install Sticky on multiple machines would like to synchronize their notes using cloud storage (Dropbox, Syncthing, etc.) or shared network folders. By detecting changes to notes.json the user can be presented with a confirmation prompt to reload the notes being displayed in the UI.

This implementation also handles conflict resolution in the rare situation where external changes conflict with user edits to a note.

Technical Implementation

  1. Real-time monitoring is implemented using GFileMonitor (inotify) to detect external changes immediately and prompt the user.
  2. Conflict resolution is handled by checking file modification time before every save as well as checking a "dirty bit" to prevent unnecessary saves and false conflict warnings.
  3. A new preference setting is added that will suppress the confirmation prompts and reload external changes automatically.

Key Components:

File Monitoring (in common.py):

  • Added new signals: external-change-detected, file-modified-before-save
  • setup_file_monitor() - Monitors notes.json file
  • on_file_changed() - Handles external change events
  • ignore_next_change flag prevents reacting to app's own writes

Dialog Handling (in sticky.py):

  • Three dialogs handle separate scenarios:
    a. External changes detected (no conflicts) → Options for "Reload" / "Cancel"
    b. (Edge case) External changes with unsaved local changes (race condition) → "Reload from disk" / "Keep my changes"
    c. (Edge case) File modified before save → "Don't Save" / "Backup and Save" / "Save Anyway"
  • When notes are hidden the display of dialogs is deferred to prevent annoying interruptions.
  • Checkbox option to suppress subsequent confirmation prompts.

Auto-Reload Preference:

  • New setting: auto-reload-external-changes (default: false)
  • Only auto-reloads when there are unsaved changes in the UI.
  • Conflicts always result in a prompt, regardless of preference setting.

Changes Made

Modified Files:

  • usr/lib/sticky/common.py - FileHandler class with monitoring logic
  • usr/lib/sticky/sticky.py - Application class with dialog handlers
  • usr/share/glib-2.0/schemas/org.x.sticky.gschema.xml - New preference key

New Files:

  • docs/external-change-detection-manual-tests.md - Manual test scenarios

Testing Performed

All 17 manual test scenarios are passing.

Known Limitations

  1. Less than 1 second data loss window - If external change arrives within ~1 second of a UI edit (before update_note_list() is called), auto-reload may discard the very recent edit. This is extremely rare in normal usage and only affects users with auto-reload enabled.
  2. Sequential dialogs possible - If multiple external changes occur while a modal dialog is open, they queue and appear sequentially. This is a GTK limitation with modal dialogs blocking the event loop.
  3. Minor edge case - Creating notes from manager while notes are hidden may not trigger proper notes_hidden state update, causing one deferred dialog anomaly (documented in Test 15).

Screenshots

Dialog examples:

External Change Detected (no conflicts):
externalchanges

File Modified (conflict at save time):
filemodified

Note on use of generative AI

Most of the implementation was performed with an AI coding assistant. Every line of code was inspected and verified by the contributor and a comprehensive set of tests was performed by hand.

… It is False by default. However, we add a checkbox to the confirmation prompt "Always reload". So the confirmation prompt appears by default, but at any time the user can check the checkbox and it will stop prompting and do auto-reload. If the user later wants the prompt back they can go to Preferences and turn off the setting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant