Changelog
July 6, 2026 · View on GitHub
All notable changes to Simple Notes Sync will be documented in this file.
The format is based on Keep a Changelog.
🌍 Languages: Deutsch · English
[2.11.0] - 2026-07-06
✨ New Features
Note Archiving (4a306b5)
- Archive notes to move them out of the main list without deleting them, with a dedicated archive view to restore or manage them later
Default Note Color & Cursor Focus (cfdf542)
- Choose a default color applied to every new note, and optionally place the cursor in the body right away when creating a note
Per-Folder Sort Persistence (4437419)
- Each folder remembers its own sort option and direction across restarts
Configurable Preview Length (43f6eb0)
- Pick how many lines of preview text notes show in the list
Markdown Toolbar Code Block (99af39d)
- New toolbar button inserts a fenced code block while editing
Unified Sync-Target Change Flow (c0ede47, 47844b0, 13be3fa, 3ecf658)
- Server and sync-folder changes now go through a single gate that confirms data handling before switching; the server subtitle shows the active folder, and the Markdown export folder is surfaced as a card with a copy action
🐛 Bug Fixes
Markdown Formatting in PDF Export (495646f, 41ceb09, 0fb65dc)
- PDF export now renders real Markdown formatting instead of raw text, fills blank code lines, adds an inline-code background, and stops
snake_caseidentifiers from rendering as italic - Thanks to @hoseinhzk for the report!
Password Reveal Re-arm (f32ee55)
- Revealing the saved password again now requires a full clear first, so it can't be peeked after a partial edit
Sort Flash & First-Time Gate (c58001a, 3ebe7d2)
- Each folder pane sorts by its own setting to stop a visual flash, and the remote-target gate is suppressed during first-time setup
Sync Folder Handling (d5f606a, ed472a1, 0c6e0e9)
- Connection test detects an existing Markdown folder, the folder-change dialog stays open until the restore finishes, and folder metadata is reset before a REPLACE restore
List & Editor Polish (9dbfd98, d0a4f9e, 24a2a5b)
- The empty state scrolls so pull-to-refresh works, untitled notes fill the title slot with a content preview, and calendar export keeps the full checklist item text in the title
🌍 Translations
- Italian (48%): GVE
- Chinese (Simplified) (99%): @heretic43
[2.10.0] - 2026-07-01
✨ New Features
Biometric App Lock (a6e1f20, a2f0628)
- Opt-in app lock backed by fingerprint, face, or device PIN, with a configurable grace period before re-locking
FLAG_SECUREblocks screenshots/screen recording and hides content in the Recents thumbnail while locked
Configurable Trash Retention (e6b2df3)
- Choose how long deleted notes stay in Trash before being purged: Immediately, 7, 14, 30 (default), or 90 days
- Thanks to @xdpirate for the request!
Rich Clipboard Paste (bf003d1)
- Pasting HTML from Telegram, Word, Google Docs, or a browser now converts formatting (bold/italic/links/lists/headings/code/blockquotes) to Markdown instead of dropping it, with a plain-text fallback
Collapsible & Reorderable Sections (6d50b81)
- Pinned/Folders/Notes section headers can be collapsed, and long-pressed to reorder; both persist across restarts
🐛 Bug Fixes
Scroll Freeze on Long Previews (a51394c)
- Note preview text is now truncated before layout, preventing an ANR while scrolling lists with very long notes
Security Settings Subtitle (ddbc3a4)
- The Security subtitle now says "Biometric unlock off" instead of just "Off"
⚡ Performance Improvements
Faster Note (De)serialization (452e557, e084759)
Note.fromJson()now streams JSON instead of building a full parse tree and using reflection, reducing cold-start time with thousands of notes
Faster List Rendering & Sync Bookkeeping (845c3ec, 4d7a240, 50bfebe, 1cba7a7)
- Pinned/unpinned split and checklist preview sort are cached instead of recomputed every frame
- Note sort/filter/search now run off the main thread
DeletionTrackeris backed by a map instead of a listNotesStorage.loadAllNotesreads files in parallel
🌍 Translations
- Spanish (66%): @PaikLC / Francisco Isaac Ordoñez Pedrero, @Kiimby / Kimby
- Indonesian (100%): @arifpedia / Arif Budiman
- Italian (46%): GVE
- Norwegian Bokmål (100%): @xdpirate
- Chinese (Simplified) (100%): @heretic43
[2.9.0] - 2026-06-22
✨ New Features
In-App Changelog (60a275c, d4e2702, db7a682)
- A native Changelog screen is now available directly in the app, reachable from Settings and via a "View changelog" button in the "What's New" sheet
- Changelog and Contributors are grouped under an "App" section in About
Contributors Screen (5c614ca)
- A new Contributors screen in About credits everyone who has contributed to the project
Selectable Markdown Preview (b07a112)
- Text in the markdown preview can now be selected and copied
- Thanks to @victoriamontero443-wq for the request!
🐛 Bug Fixes
Developer Options Visibility (fb9a97f)
- Once unlocked, developer options stay visible until the app process is restarted instead of disappearing
🌍 Translations
- Spanish (64%): @PaikLC / Francisco Isaac Ordoñez Pedrero
- Chinese (Simplified) (99%): @heretic43
[2.8.0] - 2026-06-16
✨ New Features
Trash / Recycle Bin (1d6fa60, d2dd414)
- Deleting a note now moves it to a Trash instead of erasing it; a new Trash screen (reachable from Settings) lets you restore or permanently delete notes
- Trashed notes are automatically purged after a retention period
- Notes deleted on the server are routed to the local Trash instead of vanishing, so a remote delete can still be recovered (7d9d4b3)
Local-Only Folders (6a0dd97, 72cb314)
- Folders can now be marked local-only so their notes never sync to your WebDAV server - ideal for private or device-specific notes
- Thanks to @alas-he for the request (discussion #88)!
Scrollable Notes-List Widget (ca30ad7, 0566ce9)
- A new home-screen widget shows a scrollable list of your notes with inline markdown formatting (11c069f)
- Options to hide the header, hide pinned, hide folders, filter by folder, and set the font size
- Thanks to @lincomax for the requests!
Live Markdown in the Editor & Previews (9c96cc0, 17ad8d8)
- The editor now highlights markdown live and lets you tap checkboxes to toggle tasks
- Note list and grid card previews render markdown, including checklist ☑/☐ prefixes and styled fenced code blocks (f48209a, a4324a6)
Font Size Options (30de416, 2cda14d)
- New app-wide font size setting plus an independent per-widget font size
- Thanks to @lincomax for the request!
Add Checklist Items to Calendar (82f3bfc)
- Each checklist item now has an "Add to calendar" entry in its context menu
- Thanks to Papa for the request!
Default Open Mode Toggle (5a70f14, 1882210)
- Choose whether text notes open in edit or preview mode by default (now edit by default)
🐛 Bug Fixes
Sync Loop & Folder Fixes (516cd15, 741ba37, f3062c0)
- Tied-timestamp edits now adopt the server copy to break an upload/download loop
- Notes moved during a folder rename are no longer deleted from the server
- Moving a note into a local-only folder is correctly ledgered as a server deletion
Backup Includes Folder Metadata (a854fb9)
- Backups now store and restore folder metadata instead of losing it on restore
Notification Permission Prompt Only Once (58f6e7c)
- The notification permission is now auto-requested only once instead of on repeated launches
- Thanks to @xdpirate for the report!
Editor & Markdown Polish (552f44d, 27ae90d, e15ecb0)
- Markdown toolbar shows only when the content field is focused, and is hidden while editing the title
- Fixed adjacent inline delimiters and italic detection not rendering correctly
Widget Fixes (ec761f7, a9aa973, cb6a937)
- Correct header/pinned visibility, full-height resize, and automatic day/night text color
Checklist Animation Fixes (a6002fd, cac2e3b, de5347a)
- Empty items are preserved when backgrounding the editor, the check animation plays on undo/redo, and items sort immediately after note-to-checklist conversion
Other UI Fixes (5f3c10e, c3bf07f, 40c9148)
- The help button and pull-to-refresh now react immediately to server configuration changes
- The create-folder dialog no longer expands too wide, and the multiselect top bar shows only the count
🔧 Technical
Dependency Updates (4d5cc1e)
- Compose BOM 2026.03.00 - 2026.05.01 (Foundation 1.11, Material3 1.4)
- Material 1.13.0 - 1.14.0
- Coroutines 1.10.2 - 1.11.0
- Gson 2.13.2 - 2.14.0
- WorkManager 2.11.1 - 2.11.2
- MockK 1.14.9 - 1.14.11
- Compose Foundation 1.11 suppresses
animateItemplacement animations duringanimateScrollToItem(); disabled the upstream rollout flag to restore 1.10 behaviour until the upstream fix lands (b/493183465)
[2.7.2] - 2026-06-07
🐛 Bug Fixes
Sync: Folder & Deleted-Flag Heal on no-ETag WebDAV Servers (1d3a5a1)
- On WebDAV servers that never return ETags, skipped notes could keep a stale
folderNameor a falseDELETED_ON_SERVERflag indefinitely; both cases are now healed on each skip without triggering a re-upload loop
UI: Notes List Stays at Top on Cold Start (a9d4533)
- The staggered grid auto-scrolled away from index 0 on initial load (Compose Foundation quirk), hiding the "Pinned" section header; a top-settle guard now holds the list at the top until the layout stabilises
Widget: OptionsBar Icons Visible in Light Mode (c448a43)
- Widget OptionsBar icons (lock, refresh, settings, open-in-app) had a hardcoded white fill and were invisible on light backgrounds; they now adapt to the system theme via
ColorFilter.tint(onSurface)
🌍 Translations
- Spanish: continued expansion — Francisco Isaac Ordoñez Pedrero
- Indonesian: updated — Arif Budiman
- Simplified Chinese: updated — heretic43
- Norwegian Bokmål: updated — xdpirate
[2.7.1] - 2026-06-02
🐛 Bug Fixes
Folder Sync: Server Orphan Files (77b4029)
- Notes moved back to root during folder deletion are now queued for server deletion from their old subfolder path, preventing orphan files on the server
- Fixed URL-encoded folder names (spaces as
%20) causingdeleteServerFolderIfEmptyto skip directory cleanup - Empty server folder directories are now cleaned up after batch pending deletions complete (4e05ad1)
Folder Sync: Notes Stuck in PENDING After Folder Move (18f186a)
- Server scan now deduplicates notes by
noteId; after a folder move the same note could appear in multiple WebDAV directories, causing conflicting folder assignments and an endless PENDING state
Sync: Silent Sync No Longer Clears Visible Banners (1f43b50)
- Background silent syncs can no longer clear or replace a result banner whose auto-hide timer is still running
UI: Banner Content Flash During Dismiss (af07399)
- Fixed a blank flash in the sync result banner when
AnimatedContentreceivedIDLEduring the dismiss animation; visible content now remains stable until the animation completes
UI: Create Folder Dialog Polish (fb72623)
- Keyboard now opens automatically when the dialog appears (no extra tap required)
- First letter of the folder name is auto-capitalized
UI: Folder Deletion Banner Plural String (99dfbae)
- Fixed the confirmation banner after folder deletion: now uses the correct plural resource depending on whether notes were deleted locally or also erased on the server
🌍 Translations
- Spanish: expanded from partial to broad coverage, terminology fix (
borrar→eliminar) (2f19d18), locale registered inlocales_config(974efe1) - Simplified Chinese: 7 debug screen strings added (100% coverage) (2f19d18)
[2.7.0] - 2026-05-30
✨ New Features
Folder Support (e38553d)
- Notes can be organized into folders; each note carries an optional
folderNamefield - Create, rename, and delete folders via dedicated CRUD dialogs
- Move notes to a folder from a bottom sheet accessible in the note list
- Folder navigation in the main screen filters the list by folder
- Folders are persisted with tombstone-based deletion tracking (
FolderStore) - Folders sync bidirectionally via WebDAV using folder-aware URL routing (
FolderSyncManager) - Thanks to @happy-turtle and @racehd for the idea, and @afoni95 for testing!
🐛 Bug Fixes
Grid & Pinned Notes Polish (1e02895)
- Fixed pop-in artifact when pinned notes appeared in staggered grid
- Grid scroll now resets to top when the active filter changes (2375c97)
- Staggered grid split calculations memoized, reducing layout churn (dc117ba)
- Fixed visual glitch in GridColumnChip in the display settings column picker (27a7c0a)
🌍 Translations
- Spanish (new): 08f0948
[2.6.0] - 2026-05-24
✨ New Features
Pinned Notes Section (e849bdf)
- Notes can be pinned via multi-select batch action; pinned notes appear in a dedicated "Pinned" section above the regular list
- Section only visible when at least one note is pinned; pinned cards show a pin icon indicator
- Works in both list and grid view modes
- Requested by @ASFHU, @james0336, @isawaway!
Type Conversion: Text ↔ Checklist (714a7e6)
- Convert any text note to a checklist and back; GFM checkbox notation (
- [ ]/- [x]) is preserved in both directions - Full undo/redo support for type conversions
Auto-Link Bare URLs in Markdown Preview (745a4cd)
- Naked
http://andhttps://URLs are now detected and rendered as clickable links in the Markdown preview - Trailing sentence punctuation is excluded from the linked URL
- Requested by @james0336, @isawaway!
"Copy Text" in Editor Overflow Menu (83e6a3c)
- One-tap copy of the full note content (title + body) to the clipboard; Android 13+ shows the system confirmation, older versions show a Snackbar
- Thanks to @xdpirate for the suggestion!
Append Shared Text to Existing Note (dc59351)
- Share intent now offers a third option to append shared text to an existing note instead of always creating a new one
- A note picker (sorted by last modified) lets you choose the target; the editor opens with the merged content for review
🐛 Bug Fixes
Settings Not Reactive to Offline Mode Toggle (b388016)
isServerConfiguredwas a plain function called once per composable, so toggling offline mode did not trigger recomposition; replaced with aStateFlowderived viacombine/map- Status labels now correctly distinguish "offline mode active" from "no server configured"
Parallel Connections Setting Active in Offline Mode (c6cf4e5)
- The parallel connections radio group remained interactive while all other sync settings were grayed out in offline mode; it is now correctly disabled
Checklist: Unicode Bullet/Checkmark Prefixes Not Stripped on Share Paste (8e67ccd)
• item(U+2022),✓ item,☑ item, and✔ itemare now normalised correctly when pasting via share intent
Checklist: Separator Jumps on Keyboard Show/Hide (8295522)
- The checked/unchecked separator was missing
animateItem(), causing it to snap instead of slide when the soft keyboard resized the list
Checklist: Mixed GFM + Plain Lines Not Parsed Per-Line (2bd8106)
- Mixed input (some GFM, some plain lines) fell through to the raw path, leaving
- [ ] Milkas literal item text; the parser now classifies each line individually
[2.5.2] - 2026-05-22
🐛 Bug Fixes
Navigation Bar Color Not Applied on Android < 10 in Dark Mode (5554710)
- On API < 30, the navigation bar color was not applied in dark mode; the window flag
navigationBarColoris now set explicitly for these devices - Thanks to dfxflkbvnsr for the report!
Snackbar Overlapping the FAB on Main Screen (a9ff4f5)
- The snackbar appeared behind the floating action button; it now renders above the FAB
- Thanks to dfxflkbvnsr for the report!
Back Press Ignored in Note Selection Mode (b8689eb)
- Pressing back while notes were selected did not exit selection mode; the back handler is now correctly registered when selection is active
- Thanks to dfxflkbvnsr for the report!
Multi-Select Color Picker Showed No Current Color (1365893)
- The color picker in multi-select always opened with no color pre-selected; it now highlights the shared color when all selected notes share one
Note Color Lost When Entering Selection Mode (9c4cc5d)
- Tapping a note card to begin selection reset its color to None; the color is now preserved
Checklist UNCHECKED_FIRST Sort Stability on Toggle (2c008fd)
UNCHECKED_FIRSTshared the samesortedBy { originalOrder }branch asMANUAL, causing items to jump on every toggle: unchecked items moved to the top of the unchecked group, checked items sank to the bottom of the checked group- Fixed with a dedicated stable-filter branch that preserves relative order within each group;
MANUALkeeps itsoriginalOrder-based restore unchanged - Thanks to @WuTangWilli for the report!
🌍 Translations
- Indonesian (100%): @arifpedia / Arif Budiman
- Chinese (Simplified) (100%): heretic43
- Hindi (partial): Silent Coder
[2.5.1] - 2026-05-16
🎉 First Google Play production release — v2.5.0 was prepared as the initial production build but was never published to the Play Store. v2.5.1 is the version actually reaching production. It completes the note colour feature that shipped in v2.5.0 by adding the one missing piece: sorting by colour.
✨ New Features
Note List Colour Sorting (93f7852)
- New Color option in the Sort dialog groups notes by colour in canonical palette order (Red → Orange → Yellow → Green → Teal → Blue → Dark blue → Purple → Pink → Brown → Gray)
- Uncoloured notes land at the end (ascending) or the beginning (descending) of the list
- Within each colour group, notes are ordered by last-modified date descending — consistent with the existing Type sort
- Sort selection persists across app restarts via SharedPreferences
[2.5.0] - 2026-05-15
🎉 First Google Play production release! After several rounds of beta testing, v2.5.0 is the first build promoted to the Play Store production track. A huge thank you to everyone who installed early builds, reported issues and helped us shake out the rough edges.
✨ New Features
Google Keep Import (#65)
- Import notes directly from a Google Keep / Google Takeout
.ziparchive — fully on-device, no upload - Pre-scan classifies the archive (active / archived / trashed / labels / shared / total size) before you confirm
- Per-run conflict strategy: always create (default), skip if exists, or replace if exists — matched by content hash (title + body + checklist items)
- Optional archived and trashed include switches
- Indented checklists preserved up to 3 levels (DnD behaviour unchanged)
- Keep
coloris imported and applied immediately (see Note Colours below);isPinnedis persisted in the note model (rendering follows in a later release) - Labels persisted in a separate
notes_labels.jsonindex - Cancellable mid-import; already-imported notes are kept; result dialog shows imported / replaced / skipped / errors with an expandable error list
- Confirmation step for archives larger than 200 MB
- Single auto-sync triggered at the end (only when ≥ 1 note was imported or replaced; respects existing on-save sync gate, throttle, and offline-mode settings)
- Find it under Settings → Import → Import from Google Keep
- Thanks to @simianaya for the feature request!
Note Colours (#65)
- New colour palette (None, Red, Orange, Yellow, Green, Teal, Blue, Dark blue, Purple, Pink, Brown, Gray) with separate light/dark slots so colours stay readable in both themes (4465615)
- Note cards on the home screen are tinted by the chosen colour (7ced207)
- New colour picker bottom sheet (cd0361e)
- Set a note's colour from the editor's overflow menu (b244db9)
- Bulk-set the colour for multiple selected notes from the home screen (7341462)
- In the editor, the colour is rendered as a subtle 3 dp accent stripe instead of a full-screen tint, so reading stays comfortable (bd5c943)
- Colours from Google Keep imports are mapped to this palette automatically
- Thanks to @simianaya for the feature request!
Conflict Strategy for Local & WebDAV Imports
- The conflict strategy that already shipped with the Keep import is now also available for the local file import (3a3d55c) and the WebDAV scan import (d369536)
- Choose per import run whether to always create, skip, or replace matching notes — same content-hash comparison as the Keep import, so behaviour is consistent across all three sources
- Local file import button now uses the standard
SettingsButtonfor visual consistency (75f4dbd)
Select All / Deselect All for WebDAV Import (d928ddb)
- After scanning a WebDAV folder, a single toggle lets you tick or untick every result at once
- Saves a lot of tapping when restoring large note sets
Note List Colour Filter (e773a05)
- Palette icon chip in the filter bar opens a colour-filter dropdown with per-colour note counts
- Combines with the existing type filter (AND logic) and is persisted in SharedPreferences
- Text and List type chips converted to icon-only for visual consistency
- Closes #65
✨ Improvements
Checklist Tap Animation
- Ticking a checklist item now plays a brand-new animation: a brief scale-pop on the row, a soft radial glow and a satisfying check-off effect (7156c12, 2551d21)
- The first item no longer "jumps" when the editor opens — the placement animation is suppressed on initial render (2515874)
- The list keeps its scroll position correctly when items move between the unchecked and checked branches (9792968)
🐛 Bug Fixes
- Imports always assign
SyncStatus.PENDING(51ea959) — imported notes are now reliably picked up by the next sync run, regardless of the import source - Editor autosave includes colour changes (a0a34b9) — switching a note's colour from the editor no longer gets discarded by the no-change guard
♻️ Internal
SyncScheduler extracted
- The duplicated
triggerOnSaveSync()logic fromNoteEditorViewModelandMainViewModelis now centralised insync/SyncScheduler(behaviour strictly equivalent to v2.4.0; reused by the Keep import flow)
APK Size −11% via Locale & Resource Filtering (5a631cb)
localeFiltersrestricted to the 10 supported languages — removes unused translations fromresources.arsc- Strict resource shrinking (
keep.xml) — safe because the app has no dynamic resource lookups - Packaging excludes expanded to remove build-time-only metadata
- Result: 5.23 MB → 4.65 MB (−577 KB, −11%);
resources.arsc: 1.49 MB → 0.95 MB (−540 KB)
📚 Documentation
- New user guide:
project-docs/simple-notes-sync/v2.5.0/google-keep-import-user-guide.md(EN + DE) - New QA cheatsheet:
project-docs/simple-notes-sync/v2.5.0/google-keep-import-adb-tests.md
🙏 Acknowledgements
- @simianaya — for requesting Google Keep import and note colours (#65)
- Everyone who tested early Google Keep exports and reported edge cases
- All beta testers who helped us reach the first Play Store production release — thank you! 🎉
[2.4.0] - 2026-05-04
✨ New Features
Persistent Sync Debug Logger (1de5fdb, 1234f6c, d8d4284, 13defa9, 62e75e7)
- New persistent
SyncDebugLoggerwriting structured entries tosync_debug.logfor diagnosing background-sync issues - Logs every
SyncWorkeroutcome (start, success, soft errors, retries, final failure) - Schema enriched with
attemptcounter andholder(process tag) to distinguish app/worker contexts - WIFI_CONNECT events annotated with
first|changereason for clarity - Explicit final outcome emitted when WorkManager drops retries, so failures aren't invisible
- Disabled by default (26cdf47) — enable in Settings → Debug to collect logs when reporting sync issues
Bypass Cold-Start Guard After Long Process Gap (17d57d5)
- After a long period without app process activity (e.g. overnight), the cold-start sync guard is bypassed so the first sync runs immediately on resume
🐛 Bug Fixes
Reliable WiFi-Connect Sync Trigger
- Require validated WiFi (not just SSID) before triggering sync (a03eadf)
- Retry WiFi-trigger sync on transient unreachability (bea0558)
- Bypass global cooldown for WiFi-connect trigger so the first sync after reconnect actually runs (5195ee0)
- Cap WiFi-trigger backoff at 30 s linear to avoid runaway delays (5ff2a70)
- Shorten WiFi-fallback interval to 30 min for faster process-death recovery (42e6a64)
Cheaper, More Robust Reachability
- Cheap reachability check before expensive PROPFIND (f46f326)
monitoringStartTimemade volatile and switched toelapsedRealtime()to avoid wall-clock skew (7f980fb)- Drop redundant onResume sync cooldown (69a7b05)
Settings & Logging
- Make debug-log export robust on all devices (handles SAF edge cases) (bbf466b)
- Clear
sync_debug.logon the Delete-Logs button so users can reset the log easily (caa329e)
♻️ Internal
WebDAV Server Migration (41ecb13)
- Self-hosted reference server migrated from
bytemark/webdavtohacdias/webdavfor active maintenance and better protocol coverage - No user-visible change for app users; affects the optional bundled server in
server/
🌍 Translations
- New language: Indonesian (
in) — thanks to Arif Budiman (c537455, 6bc7a4e) - New language: Norwegian Bokmål (
nb) — thanks to xdpirate (3ce9164, d11b34d) - New language: Italian (
it) — thanks to Jean-Pierre (3467756, 4bf449c) - New language: Hindi (
hi) — thanks to Silent Coder (2c54735, 9ba64fd, ecfb129) - New language: Russian (
ru) — thanks to PONYATIN (4078a59, f96055e, 1eeebc1) - Chinese (Simplified) updated — thanks to heretic43 (7a2defb)
- New locales
inandnbregistered inlocales_config.xml(349e972);ru,it,hiregistered in 84a5282
🙏 Acknowledgements
A huge thank you to the Weblate translators making Simple Notes Sync available in more languages:
- Arif Budiman — Indonesian
- xdpirate — Norwegian Bokmål
- Jean-Pierre — Italian
- Silent Coder — Hindi
- PONYATIN — Russian
- heretic43 — Chinese (Simplified)
[2.3.1] - 2026-04-24
Beta-only release on Google Play. Not published on F-Droid; the changes are included in v2.4.0.
🐛 Bug Fixes
Visibility-Aware Error Banner on Soft Sync Errors (c4a40f8)
- Silent background sync errors no longer surface as a red error banner — they reset cleanly to IDLE
- Errors are only promoted to a visible banner when the user is actively viewing the app
- New
SyncStateManager.errorIfVisible()API used bySyncWorkerandMainViewModel.triggerAutoSyncfor all soft-error paths - Prevents user-confusing transient warnings during background retries
[2.3.0] - 2026-04-18
🛡️ Security
WebDAV Credentials Now Stored Encrypted (bf117f8)
- WebDAV username and password were previously stored as plaintext in regular SharedPreferences
- Migrated to
EncryptedSharedPreferenceswith AES256-GCM encryption - One-time auto-migration on first start: existing credentials are moved to the encrypted store and removed from the plaintext store
✨ New Features
Battery Optimization Prompt on Sync Enable & Migration (da2ab36)
- When the user disables offline mode, the app immediately checks battery optimization exemption and shows the system dialog if needed
- One-time migration for existing users: users who already have sync enabled but were never prompted see the dialog once on next app start
- Uses new SharedPreferences key
battery_opt_migration_shown
🐛 Bug Fixes
Fix Markdown Auto-Sync Not Firing on Save (1756af4)
- SharedPreferences for markdown export/auto-import were only persisted after a successful initial export — if it failed (HTTP 405, timeout, network error), the prefs were never set and on-save export never fired
- Prefs are now persisted immediately after server config validation; initial export is best-effort
- HTTP 405 fallback added to
ensureMarkdownDirExists()(list-after-failed-exists pattern) - Thanks to @minosimo for the detailed bug report and logs! (#50)
Improve MKCOL 404 Handling and WebDAV Validation (8c5907a)
SafeSardineWrapper.createDirectory(): handle 404 withlist()fallback (analogous to existing 405 handling)WebDavSyncService.testConnection(): verify WebDAV capability via PROPFIND after HEAD check to prevent false "Reachable" statusSyncExceptionMapper: detect MKCOL failures and show user-friendly message with WebDAV URL hint- Thanks to @Ichigo-Meow for reporting! (#55)
Stop Phantom "Untitled" Notes from WebDAV Root Scan (fab23eb)
- Foreign JSON files in the WebDAV root (e.g.
info.json) were parsed on every sync, producing a fresh "Untitled" ghost note with a random UUID — saved as SYNCED, then immediately flagged DELETED_ON_SERVER, accumulating endlessly - Disabled the legacy v1.2.0 root fallback in the normal sync path; the migration scan still runs in
restoreFromServer() - Added UUID-format and id-vs-filename guards in
NoteDownloaderPhase 2 as defense-in-depth - Thanks to @angeld-jr2 for the detailed debug log that made this diagnosable! (#62)
Allow Title-less Notes in Backup Validation (d41d02b)
- Backup restore rejected v2.2.0 backups containing notes with an empty title (e.g. checklists)
validateBackup()now matches the editor: a note is only invalid when both title AND content/checklist-items are blank- Thanks to @angeld-jr2 for reporting!
Map HTTP 401 During Directory Ensure to Auth Error (02c3f77)
ensureNotesDirectoryExists()andensureMarkdownDirectoryExists()swallowed 401s and fell through to MKCOL, surfacing "Cannot create sync folder" instead of "Authentication failed"- Auth errors are now detected and re-thrown before MKCOL; defense-in-depth in
SyncExceptionMapper
Align Widget Checklist Sort with Editor for All Sort Options (dcc740b)
- Widget
ToggleChecklistItemActiononly handled MANUAL and UNCHECKED_FIRST - Extracted shared
ChecklistSorterutility used by both widget and editor for consistent sorting across all seven sort options - Thanks to MrsMinchen for the contribution!
Trigger Auto-Save on Sort Option Change (06c5228)
sortChecklistItems(option)was missingisDirtyandscheduleAutosave, so sort changes were lost without explicit save- Widget updates also added after auto-save and saveOnBack to keep widgets in sync
- Thanks to freemen for reporting!
Truncate Widget Content to Prevent TransactionTooLargeException (7aba796)
- Limit text notes to 100 lines and checklists to 100 items in widget rendering — very long notes exceeded the 1MB Binder IPC limit for RemoteViews
Localize Widget Empty State and Add Tap-to-Reconfigure (0b7dbf8)
- Replaced hardcoded "Note not found" with a string resource
- Tapping the widget now opens the config activity so users can recover after note data is cleared
Move NotesStorage File I/O off the Main Thread (645ce9e)
saveNote,loadNote,loadAllNotes,deleteNoteare now suspend functions onDispatchers.IO- Fixes
loadAllNotes()race-condition crash (FileNotFoundException between listFiles/readText) - Fixes empty TextFieldState on first note open after app start
- Fixes "Note marked PENDING on back-navigation from empty editor"
- Fixes "Widget showing 'Note not found'":
loadNoteSync()now runs insideprovideContentso every widget update reads fresh data
Prevent Flash of Wrong Editor State on Async Note Load (b7b3a1c)
- Async load surfaced TEXT-mode defaults for 1+ frames before the IO load completed, briefly showing wrong TopBar title and content type for checklists
isNewNote=falseis now set synchronously before launching the coroutine; isLoading gates the entire screen
Use Mutex-Protected Deletion Tracking (e777259)
deleteNote()now usestrackDeletionSafe()to prevent race conditions during batch deletes; the legacy unprotected variant is deprecated
Preserve List Scroll Position When Returning from Editor (c5b4955)
- New-note detection moved from the unsorted load to the sorted-flow; editing an existing note no longer resets scroll
Persist Navigation Flags Across Process Death (78b331b)
cameFromEditor/cameFromSettingsare saved/restored viaonSaveInstanceState, preventing incorrect scroll-to-top and sync suppression after system process termination
Trigger onSave Sync After Editor Deletion (5c7f008)
deleteNoteFromEditornow triggers a sync to propagate the deletion to the server immediately, consistent withsaveNotebehavior
Add Reachability Check to Settings syncNow() (d1928be)
- The Settings "Sync now" path was the only
syncNotes()caller bypassingSyncGateChecker.isServerReachable(); unreachable servers caused FATAL exceptions instead of a clean abort
Add HTTP HEAD Check to Server Reachability Gate (13ad82e)
SyncGateCheckernow performs a HEAD request after the TCP socket check to verify the server actually speaks HTTP — prevents false positives for servers with TLS issues
Timestamp-Based Stale Sync State Detection (bd394fa)
SyncStateManagerauto-resetsSYNCINGstate older than 5 minutes; called fromApplication.onCreateandMainViewModel.initto cover both process death and configuration changes
Add Logging to 18 Silent Catch Blocks (728f33a)
- Replace
catch (_: Exception)with logged exceptions acrossImportWizard,WebDavSyncService,ConnectionManager,SyncGateChecker,ThemePreferences,MainViewModel,NoteDownloader, and widget code
Logging and User Hints for Silent Error Paths (e6dac28)
WidgetConfignow logs failures; import shows a user-visible hint when zero notes are imported despite candidates being present
Add Logging to 403 Workaround in SafeSardineWrapper.exists (4917fc4)
- Warns when the Jianguoyun 403-as-exists workaround triggers, so false positives are visible in debug logs
Null Check for sardine.getInputStream in readContent (98a778f)
- Sardine can return null for non-existent resources; safe-call prevents NPE during import
Resolve Deprecated APIs and Lint Warnings (6b87dd2)
LocalClipboardManager→LocalClipboard+ClipEntryIcons.Filled.PlaylistAdd→Icons.AutoMirrored.Filled.PlaylistAddEncryptedSharedPreferences/MasterKey: documented suppression (no replacement for Android 7+)- All
SharedPreferences.edit().putX().apply()chains converted to KTXedit { }blocks
Prevent NPE in UrlValidator for Malformed URLs (1a3c6a7)
parsedUrl.hostcan be null for URLs likehttp:///path; safe-call with early return
Replace Hardcoded German in Battery Optimization Fallback (98c39a6)
ComposeSettingsActivitynow uses the existingbattery_optimization_open_settings_failedstring resource
Widget Config Load Failure Hint (8d7d03f)
- The widget config activity now logs the fallback to defaults and shows a hint when previous config could not be loaded
✨ Improvements
Migrate All Toast Messages to Material 3 Snackbar (a834e25)
- All 9
Toast.makeText()call sites replaced with ViewModel-driven Snackbar events for consistent UX emitSnackbar()helper added toMainViewModelandNoteEditorViewModel;showToast()extension deprecated
Centralized Spacing Tokens (db4ce8f)
- Added
SpacingXSmall(2dp),SpacingMediumLarge(12dp),SpacingXXLarge(32dp) toDimensions;MarkdownRenderermigrated to centralized tokens
Replace Hardcoded Legacy Path Filter with Named Constants (5f4d044)
- Use
Constants.DEFAULT_SYNC_FOLDER_NAMEandSyncUrlBuilder.MARKDOWN_SUFFIXinstead of magic strings in the root-fallback filter
Extract DEFAULT_OFFLINE_MODE Constant (051054d)
- Replace magic boolean in 3
getBoolean()calls; comment documents why default istrue(safe for first install)
🔧 Internal Changes
- StateFlow migration in
NoteEditorViewModel(9071905) —existingNote,isDirty,hasUnsavedChecklistEdits,isRestoringSnapshotare now backed byMutableStateFlow - In-memory cache for
loadAllNoteswith 2s TTL (8b74b43) — avoids re-reading and parsing all JSON files on every onResume; race-safe viaAtomicLongversion counter - Replace
android.util.Logwith project Logger in 4 files (57c3246) —DragDropListState,NoteEditorScreen,ChecklistItemRow,SettingsViewModel - Deduplicate
getTimeoutMsintoConnectionManager(ea05e03) —SyncGateCheckernow delegates - Extract
BatteryOptimizationHelper(c3a1e3b) —ComposeSettingsActivityandComposeMainActivitydeduplicated;setAutoSync()only shows the dialog when not already exempt - Unify SharedPreferences/StateFlow write order (908493b) — write prefs first, then state; in-memory state never diverges from persisted state on partial failures
- Extract
WidgetUpdateHelper(00f66db) — single helper for theGlanceAppWidgetManager → getGlanceIds → forEach updatepattern - Document
@ImmutableonNote(15c6a12) - Document empty product flavors (602c06a)
- Remove redundant
viewBinding = false(0e02124) - Extract widget magic numbers to named constants (2a84b32)
- Safe Long-to-Int coercion for socket timeout (b77ac4d)
- Increase
MAX_LOG_ENTRIESfrom 500 to 5000 (b18fa8f) — full sync cycles with 30+ notes can exceed 500 lines - Remove dead legacy
toReadableTimewithout context param (d3ea343) - Bump version 2.2.0 → 2.3.0 (71cf215)
🌍 Translations
- Chinese (Simplified) updated via Weblate (1be36bb) — thanks to @heretic43!
Translation hosting generously provided by Weblate — thank you for sponsoring open-source projects! 🙏
🙏 Acknowledgements
- @angeld-jr2 — reported the backup-validation crash and provided the debug log that made the phantom-notes bug diagnosable
- @Ichigo-Meow — reported the MKCOL/WebDAV validation issue (#55)
- @minosimo — reported the markdown-auto-sync regression (#50)
- MrsMinchen — contributed the widget checklist sort fix
- freemen — reported the missing auto-save on checklist sort changes
[2.2.0] - 2026-03-30
✨ New Features
Share Intent: Receive Text as New Note or Checklist (766f67e)
- Receive text/plain share intents from other apps as new notes or checklists
- Thanks to @madelgijs for the feature request! (Discussion #46)
New-Note Shortcut Widget (5c79ab6)
- Homescreen widget with auto-layout for quickly creating new notes
- Thanks to @Stowaway2979 for the feature request! (Discussion #49)
Checklist Button in Markdown Toolbar (2157a09)
- Insert checklist items directly from the markdown editor toolbar
Checklist Item Context Menu: Copy, Duplicate, Copy-to-Checklist (d98edd7)
- Focused MoreVert menu on checklist items with copy text, duplicate item, and copy item to another checklist
- Thanks to freemen for the feature request!
Auto-Collapse Expanded Items on Drag (c030794)
- Expanded checklist items automatically collapse when drag-and-drop starts
🐛 Bug Fixes
Fix Checklist Title Corruption from Missing Blank Line (c6cd50e)
- Critical fix:
toMarkdown()was missing a blank line between# Titleand the first checklist item, causing progressive title corruption on every sync cycle (first item merged into title) - Defensive parsing in
fromMarkdown()andfromJson()now detects and repairs corrupted titles - One-time migration repairs all locally stored corrupted checklist notes on first start after update
- CRLF line ending normalization in Markdown parser prevents parse failures on Windows-edited files
- Corruption warning logging in Markdown sync import for monitoring
- Thanks to freemen for helping track down the corruption cascade!
WiFi Sync WorkManager Fallback (ee0b54c)
- Added connectivity-change WorkManager fallback for reliable WiFi-triggered sync
🌍 Translations
📦 Code Quality
- APK packaging optimized: removed bundled kotlin_builtins and LICENSE files (−28 KB)
[2.1.0] - 2026-03-26
🐛 Bug Fixes & UX Improvements
Editor Toolbar Scaling for Narrow Displays (9b6ee8a)
- Adaptive toolbar: on wide displays full titles + Undo/Redo in toolbar; on narrow displays / large font scale: shortened titles ("Edit", "New") + Undo/Redo in overflow menu
- Prevents text wrapping on small screens and high accessibility font scales
- Thanks to @xdpirate for reporting! (#48)
Markdown Preview as Default View (f8b15a5)
- Existing text notes now open in Markdown preview mode by default
- New notes still open in edit mode with auto-keyboard focus
- Thanks to @james0336, @isawaway, and MrsMinchen for the suggestion!
📝 Documentation & Metadata
License Metadata Corrected (89667d1)
- Fixed remaining Apache 2.0 references in F-Droid changelogs (versionCode 27) — now all correctly show AGPL v3
Issue Templates Simplified (5a56cf4)
- Bug report and question templates rewritten: English-only, fewer required fields, cleaner layout
- Thanks to @xdpirate for the feedback! (#48)
Upcoming Features v2.2.0 (5e9168b)
- Added Share Intent (Discussion #46 by @madelgijs), New Note Shortcut Widget (Discussion #49 by @Stowaway2979), Markdown checklist button, and checklist item copy/duplicate to the roadmap
📦 Code Quality
Detekt / Lint / ProGuard Audit (b9e6782)
- Full code quality audit: detekt, lint, ktlint, ProGuard, and unit tests verified clean after all v2.1.0 changes
[2.0.0] - 2026-03-20
🎨 Complete Compose Rewrite, Multi-Theme System & Architecture Overhaul
Major release: full migration to Jetpack Compose, removal of all legacy View-based code (~2,300 lines deleted), complete WebDavSyncService refactoring into focused modules, multi-theme system with 7 color schemes and animated transitions, Material 3 shared axis navigation, checklist drag-and-drop rewrite, comprehensive sync reliability fixes, and modernized dependencies.
✨ New Features
Multi-Theme System with Animated Transitions and Tinted Surfaces (315c0a5)
- New ThemeMode selector: System, Light, Dark, AMOLED
- 7 color schemes: Default, Blue, Green, Red, Purple, Orange, Dynamic (Material You on API 31+)
- Live preview with color swatches in Display Settings
- Crossfade theme transitions (500 ms) — smooth even in debug builds
- Tinted surface palettes for all color schemes (note cards match selected theme)
- Status bar and navigation bar colors sync at runtime on theme change
Grid Column Scaling Control (3d4c2e0)
- Toggle between automatic grid scaling (adaptive 150dp) and fixed column count
- Manual column count 1–5 via chip selector with mini-grid preview
- Section only visible when grid mode is active
- Included in backup/restore
Undo/Redo Promoted to TopAppBar (75edf00)
- Undo and Redo moved from overflow menu to direct TopAppBar actions
- Buttons respect canUndo/canRedo state and appear dimmed when unavailable
Display Mode Chip Selector (046f325)
- Replace radio group with icon-above-label chips (consistent with theme/color selectors)
- Settings subtitle shows display mode, theme mode, and color theme (e.g. "List View · Dark · Default")
Full App Settings Backup/Restore (4d07c11)
- Backup/restore now includes all settings: server, sync, markdown, display, notes behaviour, notifications
Autosave Status in Display Settings (92da701)
- Display settings subtitle shows autosave status instead of theme info
Disable-Logging-After-Export Dialog (2525a85)
- After sharing debug logs, a dialog asks whether to disable file logging
Material 3 Shared Axis Transitions (3f5d19d, 365b0dd)
- Horizontal shared axis (slide + fade) transitions for all navigation
- Consistent animations for both back-arrow and swipe-gesture on API 34+
🐛 Bug Fixes
Checklist Drag-and-Drop Rewrite (89cc9a6)
- Complete rewrite of DragDropListState (~200 → 797 lines) fixing runaway auto-scroll, index desync during separator crossings, concurrent swap race conditions, and swap oscillation at viewport edges
- Key-based item tracking, continuous auto-scroll loop with mutex-locked swaps, anti-flapping guard, viewport-safety checks
Offline Server Deletions Queued (1a5c889)
- Notes deleted with "Delete everywhere" while server unreachable are now queued and processed on next sync instead of silently lost
WebDAV 403 Compatibility (9523733)
- Jianguoyun WebDAV returns 403 for HEAD on collections — now correctly treated as "exists" instead of "not found". Thanks @james0336 for reporting!
Thread-Safety and Resource Leaks (2ab04d1, 3c31f61)
- Fix Activity leaks in NetworkMonitor, migrate syncStatus to StateFlow, add fileLock to Logger, eliminate race conditions in MainViewModel with StateFlow.update{}
- Close all InputStream/connection leaks in sardine calls, move file I/O off main thread, fix HttpURLConnection leak in server status check
Sync Reliability (ec4bb1c, 3d02118, 150543c)
- Fix onResume sync throttle surviving process restarts (now in-memory)
- Prevent spurious sync after package update (race condition in NetworkMonitor)
- Skip auto-sync on resume from editor and settings
Layout Scaling for Small Screens and Large Fonts (ef38a0e)
- Responsive fixes: scrollable dialogs, FilterChipRow column layout, adaptive grid threshold reduced 180→150dp. Danke an Mama <3
Empty Plural Strings in de/tr/uk (2db80a4)
- Fill missing plural forms for time-ago strings — timestamps were invisible on note cards in German, Turkish, Ukrainian
Language Selector on API 33+ (f54ef49)
- Redirect to native Per-App Language Settings on API 33+ instead of in-app selector (eliminates activity-recreate flash)
Save-on-Back Race Condition (afbef19)
- Flush TextFieldState and save in onPause to prevent data loss on back navigation
Banner Color Flash (9b7a285)
- Freeze last visible banner colors during dismiss animation to prevent wrong-color flash
Splash Screen Flash (a5e0899)
- Keep splash screen visible until notes are loaded — no more empty screen flash on cold start
FAB Scrim Transition Artifact (833c30e, 2f75467)
- Snap FAB scrim to invisible before activity transition capture, restore fade-out animation
Snackbar in Settings (24c62b8, 0c76087)
- Replace unreliable Toast with Snackbar in all settings screens, show above keyboard
🏗️ Architecture & Refactoring
WebDavSyncService Split (e0abff4 → 7f467d7)
- Split monolithic 2,735-line WebDavSyncService into 8 focused modules: SyncGateChecker, ETagCache, SyncTimestampManager, SyncExceptionMapper, SyncUrlBuilder, ConnectionManager, NoteUploader, NoteDownloader, MarkdownSyncManager (8 commits, 15→22/22)
Legacy Code Removal (901ca77, 39b6e9f, fb64a31)
- Delete SettingsActivity (1,072 lines), MainActivity (857 lines), NoteEditorActivity (344 lines), all XML layouts/menus/drawables
- Compose Activities are now the sole implementations
Modernization (dfd3b33, ad137c3, 65b6a26, 9e547d2, 07a7502)
- Replace LocalBroadcastManager with SharedFlow, migrate to viewModelFactory DSL, replace overridePendingTransition with ActivityOptions (API 34+), remove all @Suppress("DEPRECATION"), replace AlertDialog.Builder with Compose AlertDialog
📦 Dependencies & Build
Dependency Updates (b57512f)
- Kotlin 2.0.21 → 2.1.0, Compose BOM 2026.01 → 2026.03, lifecycle 2.7 → 2.8.7, coroutines 1.7 → 1.9, navigation 2.7 → 2.8.5, activity 1.8 → 1.9.3, and 15+ more
Code Quality (cf95fcd, 3933df0)
- Resolve all lint and detekt warnings, 500 unused strings deleted, ktlint formatting across 91 files, Kotlin 2.3.20
APK Size Optimization (ce86b68)
- Tighten R8/ProGuard keep rules — APK size 5.4 MB → 5.2 MB (-200 KB, classes.dex -507 KB)
CI/CD (c6a3f25)
- Tag-based GitHub Actions release workflow for draft releases
📄 License
License Change (6baaeda)
- Changed from MIT to AGPL v3
[1.12.0] - 2026-03-12
🌍 i18n, Settings Polish & Community
Focused release adding Chinese (Simplified) localization, proper plural forms for time-ago strings, notification status display in the settings overview, and Liberapay donation integration in the README.
🌍 Translations
Chinese (Simplified) Translation (15a49d6)
- Complete zh-CN localization (547 strings) based on Weblate contribution from @heretic43 (#40)
- App name kept as "Simple Notes" (untranslated)
🐛 Bug Fixes
Proper i18n Plural Forms for Time-Ago Strings (c804964)
- Converted
time_minutes_ago,time_hours_agoandtime_days_agofrom<string>to<plurals>for proper grammatical forms in languages like Ukrainian - Updated
Extensions.ktto usegetQuantityStringaccordingly - All existing languages updated (en/de/tr/uk/zh)
✨ New Features
Notification Status in Settings Overview (5d82e7d)
- The Sync & Notifications card on the settings hub screen now shows the current notification status alongside the trigger count
- Three states displayed: "Notifications enabled", "Errors and warnings only", "Notifications disabled"
- Consistent with the summary style of other settings cards
📝 Documentation
Liberapay Donation Integration (7081286)
- Added Shields.io donation badge to the badge row in README.md and README.de.md
- Added official Liberapay donate button in the Contributing section
- Both English and German READMEs updated
[1.11.0] - 2026-03-10
🔔 Notifications, FAB Polish & Checklist Sorting
Focused release adding configurable notification settings with Android 13+ permission handling, ascending and descending sort-by-creation-date for checklists, a redesigned FAB overlay with animated scrim and unified action pills, restructured sync settings, hidden developer options, and several bug fixes around autosave behaviour and sync counting.
✨ New Features
Notification Settings with Permission Handling (c1f5078)
- Three new toggles in Sync & Notifications settings: global enable, errors-only mode, server unreachable warning
- Full Android 13+ POST_NOTIFICATIONS permission flow: request on first enable, rationale dialog on deny, app-settings redirect on permanent deny
- Permission state re-checked on every screen resume — toggle syncs with system state
Sort Checklists by Creation Date (Ascending + Descending) (a265e3c)
- New sort option "Date created ↑" (oldest first) and "Date created ↓" (newest first)
- Each checklist item gets a
createdAttimestamp, preserved across edits and syncs - Backward compatible: old items without timestamp use index as fallback
- Separator between unchecked/checked groups maintained for both directions
Developer Options Hidden Behind Easter Egg (186a345)
- Debug & Diagnostics settings hidden by default
- Unlock by tapping the app info card 5× in About screen (Android developer-options style)
- Session-only: resets on app restart, not persisted to SharedPreferences
- Countdown toast for last 2 taps, unlock confirmation toast
🐛 Bug Fixes
Autosave Triggered for Empty Checklist Items (f7e25db)
- Adding or deleting empty checklist items no longer triggers autosave
- No-change guard in
performSave()andsaveOnBack()skips save when only empty items differ from saved state - Autosave indicator no longer misleadingly appears after adding an empty item
Markdown Auto-Sync Double-Counting (7dd092e)
- Creating a note with markdown auto-sync enabled no longer shows "2 notes synced" instead of 1
- Exported markdown files excluded from re-import in the same sync cycle via note ID tracking
- Technical re-uploads after markdown import no longer inflated the sync count
nullvsemptyList()mismatch in checklist content comparison fixed
Misleading "Importing Markdown" Banner When No Files Changed (e352ce1)
- Progress banner no longer shows a filename (e.g. "Test Neu.md") when 0 files are actually imported
- Fast-path skips IMPORTING_MARKDOWN phase entirely when all server files are unchanged
- Filename in progress update now only shown when a file is actually being downloaded
🎨 UI Improvements
Animated FAB Scrim and Improved Colors (4a8a202)
- FAB overlay now covers the entire screen including status bar (moved out of Scaffold)
- Semi-transparent animated scrim (50% black, 250 ms tween) replaces transparent dismiss overlay
- Sub-action colours changed from
secondaryContainertoprimaryContainerfor better hierarchy
Unified Action Pills (847154f)
- Label text and icon combined into a single wide pill per action (Aegis Authenticator style)
- Entire pill is one click target — no more separate label + icon FAB
- Uses
surfaceContainerHigh/onSurfacefor consistent appearance in dark mode
Sync Settings Restructured (e9d48cb)
- Screen renamed from "Sync Settings" to "Sync & Notifications"
- Section header renamed from "Network & Performance" to "Network"
- Sub-headers "Instant Sync" and "Background Sync" removed for cleaner layout
- Sync triggers, network, and notifications extracted into separate composables for recomposition isolation
Smooth Fade Transitions in Settings Navigation (1ef565d)
- All settings routes now use a 700 ms fade transition instead of the abrupt default crossfade
- Defined globally on NavHost level — no per-route duplication
🌍 Translations
Thanks to @FromKaniv for the Ukrainian translation and @ksuheyl for the Turkish translation!
[1.10.0] - 2026-03-01
✏️ Editor Overhaul, Share / Export & Sync Reliability
Major release adding PDF export, text and calendar sharing, a redesigned FAB menu, delete-from-editor with undo, batch server deletion with progress, adaptive tablet layouts, WorkManager reliability improvements, and real determinate progress bars for all sync phases.
✨ New Features
Share & Export from Editor (e2b9f79, 2aca873, 57c4e96) (Thanks to @james0336 for requesting PDF export!)
- New overflow menu (⋮) in the editor toolbar: Share as Text, Share as PDF, Export to Calendar
- PDF generated natively via
PdfDocumentAPI — no third-party library required - Shared via
FileProviderfor secure, permission-free sharing with any PDF viewer - Calendar export pre-fills title, all-day start date (today), and note content as description
Expandable FAB Menu (85d68c4, 61788e3)
- FAB replaced with an expanding speed-dial: tap
+to reveal animated sub-action buttons for Text Note and Checklist +icon rotates to×when expanded; sub-actions slide in with staggered spring animation- Transparent dismiss overlay closes the menu on outside tap
- Sub-action buttons and label pills use
secondaryContainercolour, forming a visual unit - Stronger shadow elevation (8–10 dp) ensures the FAB visually floats above note cards in both light and dark theme
Delete Note from Editor with Undo (f3fd806)
- Delete action moved from a blocking dialog to a bottom sheet confirmation
- After confirming, the editor closes and the main screen shows a timed undo snackbar
- Undo restores the note from the deleted state and cancels any scheduled server deletion
Batch Server Deletion with Progress (39a873f)
- New
DELETINGsync phase shown in the banner when deleting multiple notes from the server - Progress bar shows
current / totalwith the current note title - Phase transitions smoothly to
COMPLETEDwith a result message
Adaptive Layouts for Tablets & Landscape (a117cbe)
- Editor content capped at 720 dp width, centred on wide screens
- Settings screens capped at 600 dp width, centred
- Main screen grid uses
Adaptive(180 dp)columns — more columns appear automatically on tablets and in landscape - Prepares for Android 16 (targetSdk 36) which ignores
screenOrientationlocks on displays ≥ 600 dp
Undo/Redo in Note Editor (484bf3a)
- Full undo/redo support for text notes and checklists via toolbar buttons
- Debounced snapshots: rapid keystrokes grouped into a single undo step (500 ms window)
- Stack limited to 50 entries; cleared on note switch to prevent cross-note undo
- Restoring a snapshot correctly updates the cursor position
Configurable WebDAV Connection Timeout (b1aebc4)
- New Settings slider (1–30 s, default 8 s) to configure the WebDAV connection timeout
- Applied to all OkHttpClient instances (connect, read, write) used by Sardine
- Consistent, user-facing error messages for timeout, auth failure, not found, and server errors
Markdown Auto-Sync Timeout Protection (7f74ae9)
- Enabling Markdown auto-sync now has a 10 s timeout for the initial export
- UI toggle updates optimistically and reverts if the export fails or times out
- Prevents the Settings screen from hanging on unreachable servers
Save on Back Navigation (402382c) (Thanks to @GitNichtGibtsNicht for requesting autosave on back!)
- Dirty notes are saved automatically when navigating back from the editor (system back + toolbar back)
- Only active when autosave is enabled; synchronous save without triggering sync
- Autosave toggle description updated to mention this behaviour
🐛 Bug Fixes
Download Progress Always Indeterminate (c83aae3)
ParallelDownloaderalready trackedcompleted / totalinternally butsyncNotes()hardcodedtotal = 0- Fixed:
totalis now passed through → DOWNLOADING phase shows a realLinearProgressIndicator importMarkdownFiles()also reports per-file progress: banner showsX / Y filename.mdwith a determinate bar
FGS Timeout on Android 15+ (1e6eb64)
- Added
ensureActive()checkpoints inWebDavSyncServicedownload loop and markdown import so coroutines respond promptly to WorkManager cancellation on targetSdk 35+ CancellationExceptionhandler inSyncWorkernow logs the stop reason (API 31+)
WorkManager Quota / Standby Stops Not Surfaced (3d66a19)
- Added detailed stop reason logging: 16 WorkManager stop codes mapped to human-readable names
- When a sync is stopped due to JobScheduler quota or app standby, an info banner is shown next time the app comes to foreground
Consistent Editor Overflow Menu Position (242ece3)
- Overflow menu (⋮) is now anchored to the
⋮button in both text and checklist note types - Previously the menu anchored to the outer actions
Row, appearing too far left on checklist notes
Markdown Import: Pre-Heading Content Lost (e33ac23)
- Content before the first
#heading was silently discarded during Markdown import - Checklist detection improved: more item patterns are now recognised
Checklist Autosave Not Triggered on Item Changes (5401df3)
- Deleting, adding, and reordering checklist items now correctly marks the note as dirty and triggers autosave
Minimal Scroll When Adding New Checklist Items (c2fbe0b)
- New checklist items scroll just enough to become visible instead of jumping to the top
False Autosave on Checklist Cursor Tap (9ea7089)
- Tapping a checklist item to position the cursor no longer triggers a false autosave
- No-op guards added to
updateChecklistItemText()andupdateChecklistItemChecked()
Undo to Saved State Still Triggered Autosave (cf5027b)
- Undoing all changes back to the last saved state now resets
isDirtyand cancels the pending autosave - New
savedSnapshotproperty captures state at load time and after every explicit save
Foreign JSON Files Downloaded Unnecessarily (c409243)
- Non-note JSON files (e.g.
google-services.json) filtered before download via UUID format check
Note Count Strings Not Pluralized Correctly (8ca8df3)
- Note count strings converted to proper Android plural forms (EN + DE)
🎨 UI Improvements
Smooth Sync Banner Animations (c409243)
- Banner enter: fadeIn (300 ms, EaseOutCubic) — no more abrupt push from top
- Banner exit: fadeOut + shrinkVertically (300/400 ms, EaseInCubic)
- Phase transitions use AnimatedContent crossfade (250 ms) for text changes
- Minimum display duration per active phase (400 ms) prevents unreadable flashes
- Auto-hide job decoupled from flow collector — guaranteed minimum display time
Markdown Folder Mentioned in Sync Settings (a8bb80c)
- Sync folder hint now explicitly mentions the
notes-md/subdirectory used for Markdown auto-sync
[1.9.0] - 2026-02-25
🔄 Sync Quality, Performance & UI
Major release adding note filtering, markdown preview, configurable sync folder, opt-in autosave, widget polish, and significant sync improvements — server switch data loss fixed, parallel uploads, import wizard, and three sync edge-cases resolved.
🐛 Bug Fixes
First Sync Fails if /notes/ Folder Doesn't Exist on Server (e012d17)
- First sync no longer fails silently when the
/notes/directory hasn't been created on the server yet - Root cause:
checkServerForChanges()returnedfalse(no changes) instead oftrue(proceed) whenlastSyncTime > 0and folder was missing - Fix: returns
trueto allow initial upload — server will create the folder on first PUT
Server Switch Causes False "Deleted on Server" Status (0985209)
- Switching to a new server no longer causes local notes to be falsely marked as deleted
- Root cause: E-Tag and content hash caches from the old server were not cleared, causing upload-skip to fire incorrectly — notes appeared SYNCED without being uploaded to the new server
- Fix:
clearServerCaches()clears all E-Tag, content hash, last sync timestamp, and deletion tracker entries on server change resetAllSyncStatusToPending()now also resets DELETED_ON_SERVER status to PENDING
Server Deletion Detection Guard Too Aggressive (56c0363)
- Users with 2–9 notes who deleted all from the Nextcloud web UI never got DELETED_ON_SERVER status
- Guard threshold raised from >1 to ≥10 to allow legitimate mass-deletion for small portfolios
Parallel Markdown Export Race Condition (56c0363)
- Two notes with identical titles could overwrite each other's Markdown file during parallel upload
- Root cause: concurrent
exists()→put()sequence without synchronization - Fix: Markdown export serialized via Mutex (JSON uploads remain parallel)
E-Tag Not Cached for "Local Newer" Download Skip (56c0363)
- When local note was newer than server version, the server E-Tag was not cached
- Caused unnecessary re-downloads on every subsequent sync
- Fix: E-Tag now saved in the else-branch of download result processing
Tune Button Color Mismatch (135559a)
- Untoggled tune button now uses default TopAppBar icon color instead of custom color
Import Wizard Loses Checklist Content (5031848)
- Checklist detection during Markdown import now preserves full note content
Checklist Scroll Jump When Checking First Visible Item (8238af4)
- Checking the first visible checklist item no longer causes a scroll jump
Checklist Original Order Lost After Insert/Delete (e601642)
- Original item order is now cemented after insert/delete operations to prevent reordering glitches
Inconsistent Scroll on Check/Un-Check (19dfb03)
- Consistent scroll behavior when checking and unchecking checklist items
✨ New Features
Notes Import Wizard (e012d17)
- New import screen in Settings — import notes from WebDAV server or local storage
- Supported formats:
.md(with/without YAML frontmatter),.json(Simple Notes format or generic),.txt(plain text) - WebDAV scan: recursive subfolder scan (depth 1), respects existing DeletionTracker entries
- Imported notes from YAML frontmatter or Simple Notes JSON are imported as SYNCED; others as PENDING
- Accessible via Settings → Import
Parallel Uploads (187d338)
- Notes are uploaded in parallel instead of sequentially — ~2× faster for multi-note changes
- Upload time for 4 notes reduced from ~11.5 s to ~6 s (measured on device)
- Second sync with unchanged notes: upload phase ~0 ms (all skipped via content hash)
- Bounded concurrency via Semaphore; file I/O writes serialized via Mutex
- New:
/notes-md/existence check cached per sync run (saves ~480 ms × N exists() calls)
Unified Parallel Connections Setting (ef200d0)
- Parallel downloads (1/3/5/7/10) and uploads (hidden, max 6) merged into single "Parallel Connections" setting
- New options: 1, 3, 5 (reduced from 5 options — 7 and 10 removed since uploads cap at 6)
- Users with 7 or 10 selected are automatically migrated to 5
- Uploads capped at
min(setting, 6)at runtime
Filter Chip Row (952755f, 71a0469, 07c41bb)
- New filter bar below TopAppBar — filter notes by All / Text / Checklists
- Inline search field for quick note filtering by title
- Sort button moved from dialog into compact filter row icon
- Tune button in TopAppBar toggles filter row visibility
Markdown Preview (e83a89a)
- Live markdown preview for text notes with formatting toolbar
- Supports headings, bold, italic, strikethrough, lists, horizontal rules, code blocks
- Toggle between edit and preview mode
Custom App Title (bf478c7)
- Configurable app name in settings
Configurable WebDAV Sync Folder (58cdf1e)
- Custom sync folder name (default:
notes, configurable for multi-app setups)
Opt-in Autosave (5800183)
- Autosave with debounce timer (3s after last edit, configurable in settings)
- Disabled by default, opt-in via Settings
Scroll to Top After Manual Sync (4697e49)
- Notes list scrolls to top after completing a manual sync
🔄 Improvements
Widget: Monet Tint in Translucent Background (0f5a734)
- Monet dynamic color tint preserved in translucent widget backgrounds
Widget: Options Bar Background Removed (5e3273a)
- Options bar background removed for seamless widget integration
Widget: Strikethrough for Completed Items (eb9db2e)
- Completed checklist items in widgets now show strikethrough styling
Widget: Auto-Refresh on onStop (2443908)
- Widgets automatically refresh when leaving the app (onStop lifecycle hook)
Checklist: Un-Check Restores Original Position (188a0f6)
- Un-checking an item restores it to its original position
Sort Button: Compact Icon Button (a1bd15a)
- Replaced AssistChip with compact IconButton + SwapVert icon
🛠️ Internal
Code Quality (6708156)
- Fixed deprecated
Icons.Outlined.Notes→Icons.AutoMirrored.Outlined.Notes - Removed unused
Colorimport from ServerSettingsScreen + detekt baseline entry - Logger timestamps use
Locale.ROOTinstead ofLocale.getDefault() - Removed obsolete
Build.VERSION_CODES.Ncheck (minSdk=24)
Detekt Compliance (f0e143c)
- Extraction of
ALL_DELETED_GUARD_THRESHOLDconstant for magic number compliance
ProGuard/R8 Verification
- Release build verified — no rule changes needed for v1.9.0
Image Support Deferred to v2.0.0 (845ba03)
- Local image embedding removed from v1.9.0 scope
- Feature preserved as v2.0.0 specification with full architecture proposal
Weblate PR Workflow (efd782f)
- Weblate integration switched to PR-based translation workflow
Documentation (395d154)
- Documentation updated for v1.8.2 and v1.9.0 (FEATURES, UPCOMING, QUICKSTART)
- Fixed broken links across docs (closes #22)
[1.8.2] - 2026-02-16
🔧 Stability, Editor & Widget Improvements
Major stability release fixing 26 issues — sync deadlocks, data loss prevention, SSL certificates, markdown sync loop, silent download failures, editor UX improvements, widget polish, and APK size optimization.
🐛 Bug Fixes
Sync Stuck in "Already in Progress" (IMPL_01) (a62ab78)
- Fixed 5 code paths in SyncWorker where
tryStartSync()was called but state was never reset - Early returns (no changes, gate blocked, server unreachable) now call
SyncStateManager.reset() - CancellationException handler now resets state instead of leaving it in SYNCING
- Generic Exception handler now calls
markError()to properly transition state - Root cause: SyncStateManager stayed in SYNCING state permanently, blocking all future syncs
Self-Signed SSL Certificates in Release Builds (IMPL_02) (b3f4915)
- Added
<certificates src="user" />to network security base config - User-installed CA certificates now work in release builds (previously debug-only)
- Required for self-hosted WebDAV servers with self-signed SSL certificates
Text Notes Not Scrollable in Medium Widgets (IMPL_04) (8429306)
- Changed NARROW_MED and WIDE_MED widget size classes to use
TextNoteFullView(scrollable) - Previously used
TextNotePreviewwhich was truncated and non-scrollable - 2x1 and 4x1 widgets now show scrollable text content
- Removed unused
TextNotePreviewfunction and related constants
Keyboard Auto-Capitalization (IMPL_05) (d93b439)
- Title field now uses
KeyboardCapitalization.Words - Content field now uses
KeyboardCapitalization.Sentences - Checklist items now use
KeyboardCapitalization.Sentences
Documentation: Sort Option Naming (IMPL_06) (465bd9c)
- Changed "color"/"Farbe" to "type"/"Typ" in README files
- Updated F-Droid metadata descriptions (de-DE and en-US)
Keyboard Auto-Scroll for Text Notes (IMPL_07) (bc266b9)
- Migrated TextNoteContent from
TextFieldValueAPI toTextFieldStateAPI - Added external
scrollStateparameter toOutlinedTextField - Auto-scrolls to cursor position when keyboard opens
Checklist Scroll Jump When Typing (IMPL_10) (974ef13)
- Replaced faulty auto-scroll logic from v1.8.1 with viewport-aware scroll
- Only scrolls if item actually extends below viewport
Checklist Visual Glitch During Fast Scrolling (IMPL_11) (82e8972)
- Added
isDragConfirmedstate to prevent accidental drag activation during scroll - Scoped
animateItem()to confirmed drag operations only - Root cause:
Modifier.animateItem()caused fade-in/out animations when items entered/left viewport
Checklist Drag Interrupted at Separator (IMPL_26) (8828391)
- Dragging a checklist item across the checked/unchecked separator no longer drops the item
- Item stays in active drag while its checked state toggles seamlessly
- Root cause: Separate
itemsIndexedblocks destroyed Composition on boundary crossing — unified into singleitemsblock
SyncMutex Deadlock via clearSessionCache() Exception (IMPL_13) (99f451b)
- Wrapped
clearSessionCache()in try-catch insidefinallyblock - Prevents Mutex from staying locked when cache cleanup throws
False Error Banner on Sync Cancellation (IMPL_14) (1c45680)
- CancellationException no longer shows error banner to user
- Removed duplicate state resets in SyncWorker catch blocks
Socket Leak in isServerReachable() (IMPL_15) (fac54d7)
- Socket now properly closed in all code paths (was leaking on successful connect)
CancellationException Swallowed in ParallelDownloader (IMPL_16) (4c34746)
- CancellationException now re-thrown instead of caught and retried
- Prevents infinite retry loop when WorkManager cancels sync
Checklist Data Loss on onResume (IMPL_17) (b436623)
- Checklist edits now persist when returning from notification shade or app switcher
- Root cause:
onResume()reloaded note from database, discarding unsaved in-memory changes
Duplicate Stale-Sync Cleanup (IMPL_18) (71ae747)
- Removed copy-paste duplicate reset block in
SimpleNotesApplication.onCreate()
NotesStorage Shadow + Download Cancellation (IMPL_19) (ede429c, 50ae9d8)
- Removed shadow
NotesStorageinstance inhasUnsyncedChanges()(19a) - Replaced
runBlockingwithcoroutineScopeindownloadRemoteNotes()for proper cancellation (19b) - Added read timeout to OkHttpClient instances (19c)
Silent Download Failures Reported as Success (IMPL_21) (371d5e3)
- Download exceptions now propagate instead of being silently caught
- Sync correctly reports failure when downloads fail
PENDING Notes Not Detected (IMPL_22) (20de019)
hasUnsyncedChanges()now checks for notes with PENDING sync status- Fixes issue where switching servers left notes unsynced
E-Tag/Timestamp Download Order (IMPL_23) (68dbb4e)
- E-Tag comparison now runs before timestamp check (was skipping changed notes)
- Fixes cross-device sync where timestamps matched but content differed
Silent Sync Promote to Visible (IMPL_24) (940a494)
- Pull-to-refresh during background sync now shows sync banner instead of "already in progress" error
Markdown Sync Feedback Loop (IMPL_25) (74194d4)
- Fixed 5 root causes creating an infinite export→import→re-export cycle
- UUID normalization, server-mtime preservation, timezone-aware comparison, path sanitization, content-type-aware comparison
✨ New Features
Enter-Key Navigation from Title to Content (IMPL_09) (81b9aca)
- Title field is now single-line with
ImeAction.Next - Pressing Enter/Next jumps to content field or first checklist item
🔄 Improvements
Widget Content Padding (IMPL_08) (2ae5ce5)
- Unified padding for all widget views: 12dp horizontal, 4dp top, 12dp bottom
Widget Entry Spacing (IMPL_12) (c3d4b33)
- Increased checklist and text widget spacing for better readability
Sync State Timeout
- Added 5-minute timeout for stale sync states in
SyncStateManager tryStartSync()auto-resets if existing sync is older than 5 minutes
Cold Start State Cleanup
SimpleNotesApplication.onCreate()now resets orphaned SYNCING state
APK Size Optimization (IMPL_03) (7867894)
- Replaced broad ProGuard rule with granular rules — keeps only what reflection actually needs
Version Bump
- versionCode: 21 → 22
- versionName: 1.8.1 → 1.8.2
1.8.1 - 2026-02-11
🛠️ Bugfix & Polish Release
Checklist fixes, widget improvements, sync hardening, and code quality cleanup.
🐛 Bug Fixes
Checklist Sort Persistence (7dbc06d)
- Fixed sort option not applied when reopening a checklist
- Root cause:
sortChecklistItems()always sorted unchecked-first instead of reading_lastChecklistSortOption - Now correctly restores all sort modes (Manual, Alphabetical, Unchecked/Checked First)
Widget Scroll on Standard Size (c72b3fe)
- Fixed scroll not working on standard 3×2 widget size (110–150dp height)
- Added
NARROW_SCROLLandWIDE_SCROLLsize classes with 150dp threshold - Removed
clickablemodifier from unlocked checklists to enable scrolling
Auto-Sync Toast Removed (fe6935a)
- Removed unexpected toast notification on automatic background sync
- Silent auto-sync stays silent; only errors are shown
Gradient & Drag Regression (24fe32a)
- Fixed gradient overlay regression on long checklist items
- Fixed drag-and-drop flicker when moving items between boundaries
🆕 New Features
Widget Checklist Sorting & Separators (66d98c0)
- Widgets now apply saved sort option from the editor
- Visual separator between unchecked/checked items (MANUAL & UNCHECKED_FIRST modes)
- Auto-sort when toggling checkboxes in the widget
- Changed ✅ → ☑️ emoji for checked items
Checklist Preview Sorting (2c43b47)
- Main screen preview (NoteCard, NoteCardCompact, NoteCardGrid) now respects saved sort option
- New
ChecklistPreviewHelperwith shared sorting logic
Auto-Scroll on Line Wrap (3e4b1bd)
- Checklist editor auto-scrolls when typing causes text to wrap to a new line
- Keeps cursor visible at bottom of list during editing
Separator Drag Cross-Boundary (7b55811)
- Drag-and-drop now works across the checked/unchecked separator
- Items auto-toggle their checked state when dragged across boundaries
- Extracted
DraggableChecklistItemcomposable for reusability
🔄 Improvements
Sync Rate-Limiting & Battery Protection (ffe0e46, a1a574a)
- Global 30-second cooldown between sync operations (auto/WiFi/periodic)
- onSave syncs bypass global cooldown (retain own 5s throttle)
- New
SyncStateManagersingleton for centralized state tracking - Prevents battery drain from rapid successive syncs
Toast → Banner Migration (27e6b9d)
- All non-interactive notifications migrated to unified Banner system
- Server-delete results show as INFO/ERROR banners
- Added INFO phase to SyncPhase enum with auto-hide (2.5s)
- Snackbars with Undo actions remain unchanged
ProGuard Rules Audit (6356173)
- Added missing keep rules for Widget ActionCallback classes
- Added Compose-specific ProGuard rules
- Prevents ClassNotFoundException in release builds
🧹 Code Quality
Detekt Compliance (1a6617a)
- Resolved all 12 detekt findings (0 issues remaining)
- Refactored
NoteEditorViewModel.loadNote()to reduce nesting depth - Extracted constants for magic numbers in editor
- Removed unused imports from
UpdateChangelogSheet - Set
maxIssues: 0in detekt config
1.8.0 - 2026-02-10
🚨 CRITICAL BUGFIX (Tag recreated)
R8/ProGuard Obfuscation Fix - Prevents Data Loss
- 🔧 CRITICAL: Fixed incorrect ProGuard class path for
Note$Companion$NoteRaw- Original v1.8.0 had specific
-keeprules that didn't match - R8 obfuscated all NoteRaw fields (id→a, title→b, ...)
- Gson couldn't parse JSON anymore → ALL notes appeared lost
- Reverted to safe broad rule:
-keep class dev.dettmer.simplenotes.** { *; }
- Original v1.8.0 had specific
- 🛡️ Added safety-guards in
detectServerDeletions()- Prevents mass deletion when
serverNoteIdsis empty (network errors) - Aborts if ALL local notes would be marked as deleted
- Prevents mass deletion when
- ✅ Notes were never actually lost (JSON files intact on disk + server)
- ✅ Downgrade to v1.7.2 restored all notes
⚠️ If you installed original v1.8.0: Your notes are safe! Just update.
🎉 Major: Widgets, Sorting & Advanced Sync
Complete widget system with interactive checklists, note sorting, and major sync improvements!
🆕 Homescreen Widgets
Full Jetpack Glance Widget Framework (539987f)
- 5 responsive size classes (SMALL, NARROW_MED, NARROW_TALL, WIDE_MED, WIDE_TALL)
- Interactive checklist checkboxes that sync immediately to server
- Material You dynamic colors with configurable background opacity (0-100%)
- Lock widget toggle to prevent accidental edits
- Read-only mode with permanent options bar for locked widgets
- Widget configuration activity with note selection and settings
- Auto-refresh after sync completion
- Tap content to open editor (unlocked) or show options (locked)
- Complete resource cleanup fixes for connection leaks
Widget State Management:
- NoteWidgetState keys for per-instance persistence via DataStore
- Five top-level ActionCallbacks (Toggle Checkbox, Lock, Options, Refresh, Config)
- Type-safe parameter passing with NoteWidgetActionKeys
📊 Note & Checklist Sorting
Note Sorting (96c819b)
- Sort by: Updated (newest/oldest), Created, Title (A-Z/Z-A), Type
- Persistent sort preferences (saved in SharedPreferences)
- Sort dialog in main screen with direction toggle
- Combined sortedNotes StateFlow in MainViewModel
Checklist Sorting (96c819b, 900dad7)
- Sort by: Manual, Alphabetical, Unchecked First, Checked Last
- Visual separator between unchecked/checked items with count display
- Auto-sort on item toggle and reordering
- Drag-only within same group (unchecked/checked)
- Smooth fade/slide animations for item transitions
- Unit tested with 9 test cases for sorting logic validation
🔄 Sync Improvements
Server Deletion Detection (40d7c83, bf7a74e)
- New
DELETED_ON_SERVERsync status for multi-device scenarios - Detects when notes are deleted on other clients
- Zero performance impact (uses existing PROPFIND data)
- Deletion count shown in sync banner: "3 synced · 2 deleted on server"
- Edited deleted notes automatically re-upload to server (status → PENDING)
Sync Status Legend (07607fc)
- Help button (?) in main screen TopAppBar
- Dialog explaining all 5 sync status icons with descriptions
- Only visible when sync is configured
Live Sync Progress UI (df37d2a)
- Real-time phase indicators: PREPARING, UPLOADING, DOWNLOADING, IMPORTING_MARKDOWN
- Upload progress shows x/y counter (known total)
- Download progress shows count (unknown total)
- Single unified SyncProgressBanner (replaces dual system)
- Auto-hide: COMPLETED (2s), ERROR (4s)
- No misleading counters when nothing to sync
- Silent auto-sync stays silent, errors always shown
Parallel Downloads (bdfc0bf)
- Configurable concurrent downloads (default: 3 simultaneous)
- Kotlin coroutines async/awaitAll pattern
- Individual download timeout handling
- Graceful sequential fallback on concurrent errors
- Optimized network utilization for faster sync
✨ UX Improvements
Checklist Enhancements:
- Overflow gradient for long text items (3462f93)
- Auto-expand on focus, collapse to 5 lines when unfocused
- Drag & Drop flicker fix with straddle-target-center detection (538a705)
- Adjacency filter prevents item jumps during fast drag
- Race-condition fix for scroll + move operations
Settings UI Polish:
- Smooth language switching without activity recreate (881c0fd)
- Grid view as default for new installations (6858446)
- Sync settings restructured into clear sections: Triggers & Performance (eaac5a0)
- Changelog link added to About screen (49810ff)
Post-Update Changelog Dialog (661d9e0)
- Shows localized changelog on first launch after update
- Material 3 ModalBottomSheet with slide-up animation
- Loads F-Droid changelogs via assets (single source of truth)
- One-time display per versionCode (stored in SharedPreferences)
- Clickable GitHub link for full changelog
- Dismissable via button or swipe gesture
- Test mode in Debug Settings with reset option
Backup Settings Improvements (3e946ed)
- New BackupProgressCard with LinearProgressIndicator
- 3-phase status system: In Progress → Completion → Clear
- Success status shown for 2s, errors for 3s
- Removed redundant toast messages
- Buttons stay visible and disabled during operations
- Exception logging for better error tracking
🐛 Bug Fixes
Widget Text Display (d045d4d)
- Fixed text notes showing only 3 lines in widgets
- Changed from paragraph-based to line-based rendering
- LazyColumn now properly scrolls through all content
- Empty lines preserved as 8dp spacers
- Preview limits increased: compact 100→120, full 200→300 chars
🔧 Code Quality
Detekt Cleanup (1da1a63)
- Resolved all 22 Detekt warnings
- Removed 7 unused imports
- Defined constants for 5 magic numbers
- Optimized state reads with derivedStateOf
- Build: 0 Lint errors + 0 Detekt warnings
📚 Documentation
- Complete implementation plans for all 23 v1.8.0 features
- Widget system architecture and state management docs
- Sorting logic unit tests with edge case coverage
- F-Droid changelogs (English + German)
1.7.2 - 2026-02-04
🐛 Critical Bug Fixes
JSON/Markdown Timestamp Sync
Problem: External editors (Obsidian, Typora, VS Code, custom editors) update Markdown content but don't update YAML updated: timestamp, causing the Android app to skip changes.
Solution:
- Server file modification time (
mtime) is now used as source of truth instead of YAML timestamp - Content changes detected via hash comparison
- Notes marked as
PENDINGafter Markdown import → JSON automatically re-uploaded on next sync - Fixes sorting issues after external edits
SyncStatus on Server Always PENDING
Problem: All JSON files on server contained "syncStatus": "PENDING" even after successful sync, confusing external clients.
Solution:
- Status is now set to
SYNCEDbefore JSON serialization - Server and local copies are now consistent
- External web/Tauri editors can correctly interpret sync state
Deletion Tracker Race Condition
Problem: Batch deletes could lose deletion records due to concurrent file access.
Solution:
- Mutex-based synchronization for deletion tracking
- New
trackDeletionSafe()function prevents race conditions - Guarantees zombie note prevention even with rapid deletes
ISO8601 Timezone Parsing
Problem: Markdown imports failed with timezone offsets like +01:00 or -05:00.
Solution:
- Multi-format ISO8601 parser with fallback chain
- Supports UTC (Z), timezone offsets (+01:00, +0100), and milliseconds
- Compatible with Obsidian, Typora, VS Code timestamps
⚡ Performance Improvements
E-Tag Batch Caching
- E-Tags are now written in single batch operation instead of N individual writes
- Performance gain: ~50-100ms per sync with multiple notes
- Reduced disk I/O operations
Memory Leak Prevention
SafeSardineWrappernow implementsCloseablefor explicit resource cleanup- HTTP connection pool is properly evicted after sync
- Prevents socket exhaustion during frequent syncs
🔧 Technical Details
- IMPL_001:
kotlinx.coroutines.sync.Mutexfor thread-safe deletion tracking - IMPL_002: Pattern-based ISO8601 parser with 8 format variants
- IMPL_003: Connection pool eviction + dispatcher shutdown in
close() - IMPL_004: Batch
SharedPreferences.Editorupdates - IMPL_014: Server
mtimeparameter inNote.fromMarkdown() - IMPL_015:
syncStatusset beforetoJson()call
📚 Documentation
- External Editor Specification for web/Tauri editor developers
- Detailed implementation documentation for all bugfixes
1.7.1 - 2026-02-02
🐛 Critical Bug Fixes
Android 9 App Crash Fix (#15)
Problem: App crashed on Android 9 (API 28) when using WorkManager Expedited Work for background sync.
Root Cause: When setExpedited() is used in WorkManager, the CoroutineWorker must implement getForegroundInfo() to return a Foreground Service notification. On Android 9-11, WorkManager calls this method, but the default implementation throws IllegalStateException: Not implemented.
Solution: Implemented getForegroundInfo() in SyncWorker to return a proper ForegroundInfo with sync progress notification.
Details:
- Added
ForegroundInfowith sync progress notification for Android 9-11 - Android 10+: Sets
FOREGROUND_SERVICE_TYPE_DATA_SYNCfor proper service typing - Added Foreground Service permissions to AndroidManifest.xml
- Notification shows sync progress with indeterminate progress bar
- Thanks to @roughnecks for the detailed debugging!
VPN Compatibility Fix (#11)
- WiFi socket binding now correctly detects Wireguard VPN interfaces (tun*, wg*, -wg-)
- Traffic routes through VPN tunnel instead of bypassing it directly to WiFi
- Fixes "Connection timeout" when syncing to external servers via VPN
🔧 Technical Changes
- New
SafeSardineWrapperclass ensures proper HTTP connection cleanup - Reduced unnecessary 401 authentication challenges with preemptive auth headers
- Added ProGuard rule to suppress harmless TextInclusionStrategy warnings on older Android versions
- VPN interface detection via
NetworkInterface.getNetworkInterfaces()pattern matching - Foreground Service detection and notification system for background sync tasks
🌍 Localization
- Fixed hardcoded German error messages - now uses string resources for proper localization
- Added German and English strings for sync progress notifications
1.7.0 - 2026-01-26
🎉 Major: Grid View, WiFi-Only Sync & VPN Support
Pinterest-style grid, WiFi-only sync mode, and proper VPN support!
🎨 Grid Layout
- Pinterest-style staggered grid without gaps
- Consistent 12dp spacing between cards
- Scroll position preserved when returning from settings
- New unified
NoteCardGridwith dynamic preview lines (3 small, 6 large)
📡 Sync Improvements
- WiFi-only sync toggle - Sync only when connected to WiFi
- VPN support - Sync works correctly when VPN is active (traffic routes through VPN)
- Server change detection - All notes reset to PENDING when server URL changes
- Faster server check - Socket timeout reduced from 2s to 1s
- "Sync already running" feedback - Shows snackbar when sync is in progress
🔒 Self-Signed SSL Support
- Documentation added - Guide for using self-signed certificates
- Uses Android's built-in CA trust store
- Works with ownCloud, Nextcloud, Synology, home servers
🔧 Technical
NoteCardGridcomponent with dynamic maxLines- Removed FullLine spans for gapless layout
resetAllSyncStatusToPending()in NotesStorage- VPN detection in
getOrCacheWiFiAddress()
1.6.1 - 2026-01-20
🧹 Code Quality & Build Improvements
-
detekt: 0 issues - All 29 code quality issues resolved
- Trivial fixes: Unused imports, MaxLineLength
- File rename: DragDropState.kt → DragDropListState.kt
- MagicNumbers → Constants (Dimensions.kt, SyncConstants.kt)
- SwallowedException: Logger.w() added for better error tracking
- LongParameterList: ChecklistEditorCallbacks data class created
- LongMethod: ServerSettingsScreen split into components
- @Suppress annotations for legacy code (WebDavSyncService, SettingsActivity)
-
Zero build warnings - All 21 deprecation warnings eliminated
- File-level @Suppress for deprecated imports
- ProgressDialog, LocalBroadcastManager, AbstractSavedStateViewModelFactory
- onActivityResult, onRequestPermissionsResult
- Gradle Compose config cleaned up (StrongSkipping is now default)
-
ktlint reactivated - Linting re-enabled with Compose-specific rules
- .editorconfig created with Compose formatting rules
- Legacy files excluded: WebDavSyncService.kt, build.gradle.kts
- ignoreFailures=true for gradual migration
-
CI/CD improvements - GitHub Actions lint checks integrated
- detekt + ktlint + Android Lint run before build in pr-build-check.yml
- Ensures code quality on every pull request
🔧 Technical Improvements
-
Constants refactoring - Better code organization
- ui/theme/Dimensions.kt: UI-related constants
- utils/SyncConstants.kt: Sync operation constants
-
Preparation for v2.0.0 - Legacy code marked for removal
- SettingsActivity and MainActivity (replaced by Compose versions)
- All deprecated APIs documented with removal plan
1.6.0 - 2026-01-19
🎉 Major: Configurable Sync Triggers
Fine-grained control over when your notes sync - choose which triggers fit your workflow best!
⚙️ Sync Trigger System
-
Individual trigger control - Enable/disable each sync trigger separately in settings
-
5 Independent Triggers:
- onSave Sync - Sync immediately after saving a note (5s throttle)
- onResume Sync - Sync when app is opened (60s throttle)
- WiFi-Connect Sync - Sync when WiFi is connected
- Periodic Sync - Background sync every 15/30/60 minutes (configurable)
- Boot Sync - Start background sync after device restart
-
Smart Defaults - Only event-driven triggers active by default (onSave, onResume, WiFi-Connect)
-
Battery Optimized - ~0.2%/day with defaults, up to ~1.0% with periodic sync enabled
-
Offline Mode UI - Grayed-out sync toggles when no server configured
-
Dynamic Settings Subtitle - Shows count of active triggers on main settings screen
🔧 Server Configuration Improvements
- Offline Mode Toggle - Disable all network features with one switch
- Split Protocol & Host - Protocol (http/https) shown as non-editable prefix
- Clickable Settings Cards - Full card clickable for better UX
- Clickable Toggle Rows - Click text/icon to toggle switches (not just the switch itself)
🐛 Bug Fixes
- Fixed: Missing 5th sync trigger (Boot) in main settings screen subtitle count
- Various fixes - UI improvements and stability enhancements
🔧 Technical Improvements
- Reactive offline mode state - StateFlow ensures UI updates correctly
- Separated server config checks -
hasServerConfig()vsisServerConfigured()(offline-aware) - Improved constants - All sync trigger keys and defaults in Constants.kt
- Better code organization - Settings screens refactored for clarity
Looking Ahead
🚀 v1.7.0 will bring server folder checking and additional community features. Feature requests welcome as GitHub Issue.
1.5.0 - 2026-01-15
🎉 Major: Jetpack Compose UI Redesign
The complete UI has been migrated from XML Views to Jetpack Compose. The app is now more modern, faster, and smoother.
🌍 New Feature: Internationalization (i18n)
- English language support - All 400+ strings translated
- Automatic language detection - Follows system language
- Manual language selection - Switchable in settings
- Per-App Language (Android 13+) - Native language setting via system settings
- locales_config.xml - Complete Android integration
⚙️ Modernized Settings
- 7 categorized settings screens - Clearer and more intuitive
- Compose Navigation - Smooth transitions between screens
- Consistent design - Material Design 3 throughout
✨ UI Improvements
- Selection Mode - Long-press for multi-select instead of swipe-to-delete
- Batch Delete - Delete multiple notes at once
- Silent-Sync Mode - No banner during auto-sync (only for manual sync)
- App Icon in About Screen - High-quality display
- App Icon in Empty State - Instead of emoji when note list is empty
- Splash Screen Update - Uses app foreground icon
- Slide Animations - Smooth animations in NoteEditor
🔧 Technical Improvements
- Jetpack Compose - Complete UI migration
- Compose ViewModel Integration - StateFlow for reactive UI
- Improved Code Quality - Detekt/Lint warnings fixed
- Unused Imports Cleanup - Cleaner codebase
Looking Ahead
🚀 v1.6.0 will bring server folder checking and further technical modernizations. Feature requests welcome as GitHub Issue.
1.4.1 - 2026-01-11
Fixed
-
🗑️ Deleting older notes (v1.2.0 compatibility)
- Notes from app version v1.2.0 or earlier are now correctly deleted from the server
- Fixes issue with multi-device usage with older notes
-
🔄 Checklist sync backward compatibility
- Checklists now also saved as text fallback in the
contentfield - Older app versions (v1.3.x) display checklists as readable text
- Format: GitHub-style task lists (
[ ] Item/[x] Item) - Recovery mode: If checklist items are lost, they are recovered from content
- Checklists now also saved as text fallback in the
Improved
- 📝 Checklist auto line-wrap
- Long checklist texts now automatically wrap
- No more limit to 3 lines
- Enter key still creates a new item
Looking Ahead
🚀 v1.5.0 will be the next major release. We're collecting ideas and feedback! Feature requests welcome as GitHub Issue.
1.4.0 - 2026-01-10
🎉 New Feature: Checklists
-
✅ Checklist Notes
- New note type: Checklists with tap-to-toggle items
- Add items via dedicated input field with "+" button
- Drag & drop reordering (long-press to activate)
- Swipe-to-delete items
- Visual distinction: Checked items get strikethrough styling
- Type selector when creating new notes (Text or Checklist)
-
📝 Markdown Integration
- Checklists export as GitHub-style task lists (
- [ ]/- [x]) - Compatible with Obsidian, Notion, and other Markdown editors
- Full round-trip: Edit in Obsidian → Sync back to app
- YAML frontmatter includes
type: checklistfor identification
- Checklists export as GitHub-style task lists (
Fixed
-
� Markdown Parsing Robustness
- Fixed content extraction after title (was returning empty for some formats)
- Now handles single newline after title (was requiring double newline)
- Protection: Skips import if parsed content is empty but local has content
-
📂 Duplicate Filename Handling
- Notes with identical titles now get unique Markdown filenames
- Format:
title_shortid.md(e.g.,test_71540ca9.md) - Prevents data loss from filename collisions
-
🔔 Notification UX
- No sync notifications when app is in foreground
- User sees changes directly in UI - no redundant notification
- Background syncs still show notifications as expected
Privacy Improvements
- 🔒 WiFi Permissions Removed
- Removed
ACCESS_WIFI_STATEpermission - Removed
CHANGE_WIFI_STATEpermission - WiFi binding now works via IP detection instead of SSID matching
- Cleaned up all SSID-related code from codebase and documentation
- Removed
Technical Improvements
-
📦 New Data Model
NoteTypeenum:TEXT,CHECKLISTChecklistItemdata class with id, text, isChecked, orderNote.ktextended withnoteTypeandchecklistItemsfields
-
🔄 Sync Protocol v1.4.0
- JSON format updated to include checklist fields
- Full backward compatibility with v1.3.x notes
- Robust JSON parsing with manual field extraction
1.3.2 - 2026-01-10
Changed
- 🧹 Code-Qualität: "Clean Slate" Release
- Alle einfachen Lint-Issues behoben (Phase 1-7 des Cleanup-Plans)
- Unused Imports und Members entfernt
- Magic Numbers durch benannte Konstanten ersetzt
- SwallowedExceptions mit Logger.w() versehen
- MaxLineLength-Verstöße reformatiert
- ConstructorParameterNaming (snake_case → camelCase mit @SerializedName)
- Custom Exceptions: SyncException.kt und ValidationException.kt erstellt
Added
- 📝 F-Droid Privacy Notice
- Datenschutz-Hinweis für die Datei-Logging-Funktion
- Erklärt dass Logs nur lokal gespeichert werden
- Erfüllt F-Droid Opt-in Consent-Anforderungen
Technical Improvements
-
⚡ Neue Konstanten für bessere Wartbarkeit
SYNC_COMPLETED_DELAY_MS,ERROR_DISPLAY_DELAY_MS(MainActivity)CONNECTION_TIMEOUT_MS(SettingsActivity)SOCKET_TIMEOUT_MS,MAX_FILENAME_LENGTH,ETAG_PREVIEW_LENGTH(WebDavSyncService)AUTO_CANCEL_TIMEOUT_MS(NotificationHelper)- RFC 1918 IP-Range Konstanten (UrlValidator)
DAYS_THRESHOLD,TRUNCATE_SUFFIX_LENGTH(Extensions)
-
🔒 @Suppress Annotations für legitime Patterns
- ReturnCount: Frühe Returns für Validierung sind idiomatisch
- LoopWithTooManyJumpStatements: Komplexe Sync-Logik dokumentiert
Notes
- Komplexe Refactorings (LargeClass, LongMethod) für v1.3.3+ geplant
- Deprecation-Warnungen (LocalBroadcastManager, ProgressDialog) bleiben bestehen
1.3.1 - 2026-01-08
Fixed
- 🔧 Multi-Device JSON Sync (Danke an Thomas aus Bielefeld)
- JSON-Dateien werden jetzt korrekt zwischen Geräten synchronisiert
- Funktioniert auch ohne aktiviertes Markdown
- Hybrid-Optimierung: Server-Timestamp (Primary) + E-Tag (Secondary) Checks
- E-Tag wird nach Upload gecached um Re-Download zu vermeiden
Performance Improvements
-
⚡ JSON Sync Performance-Parität
- JSON-Sync erreicht jetzt gleiche Performance wie Markdown (~2-3 Sekunden)
- Timestamp-basierte Skip-Logik für unveränderte Dateien (~500ms pro Datei gespart)
- E-Tag-Matching als Fallback für Dateien die seit letztem Sync modifiziert wurden
- Beispiel: 24 Dateien von 12-14s auf ~2.7s reduziert (keine Änderungen)
-
⏭️ Skip unveränderte Dateien (Haupt-Performance-Fix!)
- JSON-Dateien: Überspringt alle Notizen, die seit letztem Sync nicht geändert wurden
- Markdown-Dateien: Überspringt unveränderte MD-Dateien basierend auf Server-Timestamp
- Spart ~500ms pro Datei bei Nextcloud (~20 Dateien = 10 Sekunden gespart!)
- Von 21 Sekunden Sync-Zeit auf 2-3 Sekunden reduziert
-
⚡ Session-Caching für WebDAV
- Sardine-Client wird pro Sync-Session wiederverwendet (~600ms gespart)
- WiFi-IP-Adresse wird gecacht statt bei jeder Anfrage neu ermittelt (~300ms gespart)
/notes/Ordner-Existenz wird nur einmal pro Sync geprüft (~500ms gespart)- Gesamt: ~1.4 Sekunden zusätzlich gespart
-
📝 Content-basierte Markdown-Erkennung
- Extern bearbeitete Markdown-Dateien werden auch erkannt wenn YAML-Timestamp nicht aktualisiert wurde
- Löst das Problem: Obsidian/Texteditor-Änderungen wurden nicht importiert
- Hybridansatz: Erst Timestamp-Check (schnell), dann Content-Vergleich (zuverlässig)
Added
- 🔄 Sync-Status-Anzeige (UI)
- Sichtbares Banner "Synchronisiere..." mit ProgressBar während Sync läuft
- Sync-Button und Pull-to-Refresh werden deaktiviert während Sync aktiv
- Verhindert versehentliche Doppel-Syncs durch visuelle Rückmeldung
- Auch in Einstellungen: "Jetzt synchronisieren" Button wird deaktiviert
Fixed
-
🔧 Sync-Mutex verhindert doppelte Syncs
- Keine doppelten Toast-Nachrichten mehr bei schnellem Pull-to-Refresh
- Concurrent Sync-Requests werden korrekt blockiert
-
🐛 Lint-Fehler behoben
View.generateViewId()statt hardcodierte IDs in RadioButtonsapp:tintstattandroid:tintfür AppCompat-Kompatibilität
Added
-
🔍 detekt Code-Analyse
- Statische Code-Analyse mit detekt 1.23.4 integriert
- Pragmatische Konfiguration für Sync-intensive Codebasis
- 91 Issues identifiziert (als Baseline für v1.4.0)
-
🏗️ Debug Build mit separatem Package
- Debug-APK kann parallel zur Release-Version installiert werden
- Package:
dev.dettmer.simplenotes.debug(Debug) vsdev.dettmer.simplenotes(Release) - App-Name zeigt "Simple Notes (Debug)" für einfache Unterscheidung
-
📊 Debug-Logging UI
- Neuer "Debug Log" Button in Einstellungen → Erweitert
- Zeigt letzte Sync-Logs mit Zeitstempeln
- Export-Funktion für Fehlerberichte
Technical
WebDavSyncService: Hybrid-Optimierung für JSON-Downloads (Timestamp PRIMARY, E-Tag SECONDARY)WebDavSyncService: E-Tag refresh nach Upload statt Invalidierung (verhindert Re-Download)- E-Tag Caching:
SharedPreferencesmit Key-Patternetag_json_{noteId} - Skip-Logik:
if (serverModified <= lastSync) skip→ ~1ms pro Datei - Fallback E-Tag:
if (serverETag == cachedETag) skip→ für Dateien modifiziert nach lastSync - PROPFIND nach PUT: Fetch E-Tag nach Upload für korrektes Caching
SyncStateManager: Neuer Singleton mitStateFlow<Boolean>für Sync-StatusMainActivity: Observer aufSyncStateManager.isSyncingfür UI-Updates- Layout:
sync_status_bannermitProgressBar+TextView WebDavSyncService: Skip-Logik für unveränderte JSON/MD Dateien basierend auflastSyncTimestampWebDavSyncService: Neue Session-Cache-Variablen (sessionSardine,sessionWifiAddress,notesDirEnsured)getOrCreateSardine(): Cached Sardine-Client mit automatischer Credentials-KonfigurationgetOrCacheWiFiAddress(): WiFi-Adresse wird nur einmal pro Sync ermitteltclearSessionCache(): Aufräumen am Ende jeder Sync-SessionensureNotesDirectoryExists(): Cached Directory-Check- Content-basierter Import: Vergleicht MD-Content mit lokaler Note wenn Timestamps gleich
- Build-Tooling: detekt aktiviert, ktlint vorbereitet (deaktiviert wegen Parser-Problemen)
- Debug BuildType:
applicationIdSuffix = ".debug",versionNameSuffix = "-debug"
1.3.0 - 2026-01-07
Added
-
🚀 Multi-Device Sync (Thanks to Thomas from Bielefeld for reporting!)
- Automatic download of new notes from other devices
- Deletion tracking prevents "zombie notes" (deleted notes don't come back)
- Smart cleanup: Re-created notes (newer timestamp) are downloaded
- Works with all devices: v1.2.0, v1.2.1, v1.2.2, and v1.3.0
-
🗑️ Server Deletion via Swipe Gesture
- Swipe left on notes to delete from server (requires confirmation)
- Prevents duplicate notes on other devices
- Works with deletion tracking system
- Material Design confirmation dialog
-
⚡ E-Tag Performance Optimization
- Smart server checking with E-Tag caching (~150ms vs 3000ms for "no changes")
- 20x faster when server has no updates
- E-Tag hybrid approach: E-Tag for JSON (fast), timestamp for Markdown (reliable)
- Battery-friendly with minimal server requests
-
📥 Markdown Auto-Sync Toggle
- NEW: Unified Auto-Sync toggle in Settings (replaces separate Export/Auto-Import toggles)
- When enabled: Notes export to Markdown AND import changes automatically
- When disabled: Manual sync button appears for on-demand synchronization
- Performance: Auto-Sync OFF = 0ms overhead
-
🔘 Manual Markdown Sync Button
- Manual sync button for performance-conscious users
- Shows import/export counts after completion
- Only visible when Auto-Sync is disabled
- On-demand synchronization (~150-200ms only when triggered)
-
⚙️ Server-Restore Modes
- MERGE: Keep local notes + add server notes
- REPLACE: Delete all local + download from server
- OVERWRITE: Update duplicates, keep non-duplicates
- Restore modes now work correctly for WebDAV restore
Technical
- New
DeletionTrackermodel with JSON persistence NotesStorage: Added deletion tracking methodsWebDavSyncService.hasUnsyncedChanges(): Intelligent server checks with E-Tag cachingWebDavSyncService.downloadRemoteNotes(): Deletion-aware downloadsWebDavSyncService.restoreFromServer(): Support for restore modesWebDavSyncService.deleteNoteFromServer(): Server deletion with YAML frontmatter scanningWebDavSyncService.importMarkdownFiles(): Automatic Markdown import during syncWebDavSyncService.manualMarkdownSync(): Manual sync with result countsMainActivity.setupSwipeToDelete(): Two-stage swipe deletion with confirmation- E-Tag caching in SharedPreferences for performance
1.2.2 - 2026-01-06
Fixed
- Backward Compatibility for v1.2.0 Users (Critical)
- App now reads BOTH old (Root) AND new (
/notes/) folder structures - Users upgrading from v1.2.0 no longer lose their existing notes
- Server-Restore now finds notes from v1.2.0 stored in Root folder
- Automatic deduplication prevents loading the same note twice
- Graceful error handling if Root folder is not accessible
- App now reads BOTH old (Root) AND new (
Technical
WebDavSyncService.downloadRemoteNotes()- Dual-mode download (Root + /notes/)WebDavSyncService.restoreFromServer()- Now uses dual-mode download- Migration happens naturally: new uploads go to
/notes/, old notes stay readable
1.2.1 - 2026-01-05
Fixed
-
Markdown Initial Export Bugfix
- Existing notes are now exported as Markdown when Desktop Integration is activated
- Previously, only new notes created after activation were exported
- Progress dialog shows export status with current/total counter
- Error handling for network issues during export
- Individual note failures don't abort the entire export
-
Markdown Directory Structure Fix
- Markdown files now correctly land in
/notes-md/folder - Smart URL detection supports both Root-URL and
/notesURL structures - Previously, MD files were incorrectly placed in the root directory
- Markdown import now finds files correctly
- Markdown files now correctly land in
-
JSON URL Normalization
- Simplified server configuration: enter only base URL (e.g.,
http://server:8080/) - App automatically creates
/notes/for JSON files and/notes-md/for Markdown - Smart detection: both
http://server:8080/andhttp://server:8080/notes/work correctly - Backward compatible: existing setups with
/notesin URL continue to work - No migration required for existing users
- Simplified server configuration: enter only base URL (e.g.,
Changed
-
Markdown Directory Creation
notes-md/folder is now created on first sync (regardless of Desktop Integration setting)- Prevents 404 errors when mounting WebDAV folder
- Better user experience: folder is visible before enabling the feature
-
Settings UI Improvements
- Updated example URL from
/webdavto/notesto match app behavior - Example now shows:
http://192.168.0.188:8080/notes
- Updated example URL from
Technical
WebDavSyncService.ensureMarkdownDirectoryExists()- Creates MD folder earlyWebDavSyncService.getMarkdownUrl()- Smart URL detection for both structuresWebDavSyncService.exportAllNotesToMarkdown()- Exports all local notes with progress callbackSettingsActivity.onMarkdownExportToggled()- Triggers initial export with ProgressDialog
1.2.0 - 2026-01-04
Added
-
Local Backup System
- Export all notes as JSON file to any location (Downloads, SD card, cloud folder)
- Import backup with 3 modes: Merge, Replace, or Overwrite duplicates
- Automatic safety backup created before every restore
- Backup validation (format and version check)
-
Markdown Desktop Integration
- Optional Markdown export parallel to JSON sync
.mdfiles synced tonotes-md/folder on WebDAV- YAML frontmatter with
id,created,updated,device - Manual import button to pull Markdown changes from server
- Last-Write-Wins conflict resolution via timestamps
-
Settings UI Extensions
- New "Backup & Restore" section with local + server restore
- New "Desktop Integration" section with Markdown toggle
- Universal restore dialog with radio button mode selection
Changed
- Server Restore Behavior: Users now choose restore mode (Merge/Replace/Overwrite) instead of hard-coded replace-all
Technical
BackupManager.kt- Complete backup/restore logicNote.toMarkdown()/Note.fromMarkdown()- Markdown conversion with YAML frontmatterWebDavSyncService- Extended for dual-format sync (JSON master + Markdown mirror)- ISO8601 timestamp formatting for desktop compatibility
- Filename sanitization for safe Markdown file names
Documentation
- Added WebDAV mount instructions (Windows, macOS, Linux)
- Complete sync architecture documentation
- Desktop integration analysis
1.1.2 - 2025-12-28
Fixed
-
"Job was cancelled" Error
- Fixed coroutine cancellation in sync worker
- Proper error handling for interrupted syncs
-
UI Improvements
- Back arrow instead of X in note editor (better UX)
- Pull-to-refresh for manual sync trigger
- HTTP/HTTPS protocol selection with radio buttons
- Inline error display (no toast spam)
-
Performance & Battery
- Sync only on actual changes (saves battery)
- Auto-save notifications removed
- 24-hour server offline warning instead of instant error
Changed
- Settings grouped into "Auto-Sync" and "Sync Interval" sections
- HTTP only allowed for local networks (RFC 1918 IPs)
- Swipe-to-delete without UI flicker
1.1.1 - 2025-12-27
Fixed
- WiFi Connect Sync
- No error notifications in foreign WiFi networks
- Server reachability check before sync (2s timeout)
- Silent abort when server offline
- Pre-check waits until network is ready
- No errors during network initialization
Changed
- Notifications
- Old sync notifications cleared on app start
- Error notifications auto-dismiss after 30 seconds
UI
- Sync icon only shown when sync is configured
- Swipe-to-delete without flicker
- Scroll to top after saving note
Technical
- Server check with 2-second timeout before sync attempts
- Network readiness check in WiFi connect trigger
- Notification cleanup on MainActivity.onCreate()
1.1.0 - 2025-12-26
Added
-
Configurable Sync Intervals
- User choice: 15, 30, or 60 minutes
- Real-world battery impact displayed (15min: ~0.8%/day, 30min: ~0.4%/day, 60min: ~0.2%/day)
- Radio button selection in settings
- Doze Mode optimization (syncs batched in maintenance windows)
-
About Section
- App version from BuildConfig
- Links to GitHub repository and developer profile
- MIT license information
- Material 3 card design
Changed
- Settings UI redesigned with grouped sections
- Periodic sync updated dynamically when interval changes
- WorkManager uses selected interval for background sync
Removed
- Debug/Logs section from settings (cleaner UI)
Technical
PREF_SYNC_INTERVAL_MINUTESpreference key- NetworkMonitor reads interval from SharedPreferences
ExistingPeriodicWorkPolicy.UPDATEfor live interval changes
1.0.0 - 2025-12-25
Added
- Initial release
- WebDAV synchronization
- Note creation, editing, deletion
- 6 sync triggers:
- Periodic sync (configurable interval)
- App start sync
- WiFi connect sync
- Manual sync (menu button)
- Pull-to-refresh
- Settings "Sync Now" button
- Material 3 design
- Light/Dark theme support
- F-Droid compatible (100% FOSS)