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_case identifiers 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_SECURE blocks 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
  • DeletionTracker is backed by a map instead of a list
  • NotesStorage.loadAllNotes reads 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 animateItem placement animations during animateScrollToItem(); 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 folderName or a false DELETED_ON_SERVER flag 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) causing deleteServerFolderIfEmpty to 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 AnimatedContent received IDLE during 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 (borrareliminar) (2f19d18), locale registered in locales_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 folderName field
  • 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


[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:// and https:// 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)

  • isServerConfigured was a plain function called once per composable, so toggling offline mode did not trigger recomposition; replaced with a StateFlow derived via combine/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 ✔ item are 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 - [ ] Milk as 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 navigationBarColor is 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_FIRST shared the same sortedBy { originalOrder } branch as MANUAL, 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; MANUAL keeps its originalOrder-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 .zip archive — 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 color is imported and applied immediately (see Note Colours below); isPinned is persisted in the note model (rendering follows in a later release)
  • Labels persisted in a separate notes_labels.json index
  • 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 SettingsButton for 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 from NoteEditorViewModel and MainViewModel is now centralised in sync/SyncScheduler (behaviour strictly equivalent to v2.4.0; reused by the Keep import flow)

APK Size −11% via Locale & Resource Filtering (5a631cb)

  • localeFilters restricted to the 10 supported languages — removes unused translations from resources.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 SyncDebugLogger writing structured entries to sync_debug.log for diagnosing background-sync issues
  • Logs every SyncWorker outcome (start, success, soft errors, retries, final failure)
  • Schema enriched with attempt counter and holder (process tag) to distinguish app/worker contexts
  • WIFI_CONNECT events annotated with first|change reason 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)
  • monitoringStartTime made volatile and switched to elapsedRealtime() 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.log on the Delete-Logs button so users can reset the log easily (caa329e)

♻️ Internal

WebDAV Server Migration (41ecb13)

  • Self-hosted reference server migrated from bytemark/webdav to hacdias/webdav for active maintenance and better protocol coverage
  • No user-visible change for app users; affects the optional bundled server in server/

🌍 Translations

🙏 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 by SyncWorker and MainViewModel.triggerAutoSync for 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 EncryptedSharedPreferences with 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 with list() fallback (analogous to existing 405 handling)
  • WebDavSyncService.testConnection(): verify WebDAV capability via PROPFIND after HEAD check to prevent false "Reachable" status
  • SyncExceptionMapper: 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 NoteDownloader Phase 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() and ensureMarkdownDirectoryExists() 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 ToggleChecklistItemAction only handled MANUAL and UNCHECKED_FIRST
  • Extracted shared ChecklistSorter utility 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 missing isDirty and scheduleAutosave, 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, deleteNote are now suspend functions on Dispatchers.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 inside provideContent so 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=false is now set synchronously before launching the coroutine; isLoading gates the entire screen

Use Mutex-Protected Deletion Tracking (e777259)

  • deleteNote() now uses trackDeletionSafe() 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/cameFromSettings are saved/restored via onSaveInstanceState, preventing incorrect scroll-to-top and sync suppression after system process termination

Trigger onSave Sync After Editor Deletion (5c7f008)

  • deleteNoteFromEditor now triggers a sync to propagate the deletion to the server immediately, consistent with saveNote behavior

Add Reachability Check to Settings syncNow() (d1928be)

  • The Settings "Sync now" path was the only syncNotes() caller bypassing SyncGateChecker.isServerReachable(); unreachable servers caused FATAL exceptions instead of a clean abort

Add HTTP HEAD Check to Server Reachability Gate (13ad82e)

  • SyncGateChecker now 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)

  • SyncStateManager auto-resets SYNCING state older than 5 minutes; called from Application.onCreate and MainViewModel.init to cover both process death and configuration changes

Add Logging to 18 Silent Catch Blocks (728f33a)

  • Replace catch (_: Exception) with logged exceptions across ImportWizard, WebDavSyncService, ConnectionManager, SyncGateChecker, ThemePreferences, MainViewModel, NoteDownloader, and widget code

Logging and User Hints for Silent Error Paths (e6dac28)

  • WidgetConfig now 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)

  • LocalClipboardManagerLocalClipboard + ClipEntry
  • Icons.Filled.PlaylistAddIcons.AutoMirrored.Filled.PlaylistAdd
  • EncryptedSharedPreferences/MasterKey: documented suppression (no replacement for Android 7+)
  • All SharedPreferences.edit().putX().apply() chains converted to KTX edit { } blocks

Prevent NPE in UrlValidator for Malformed URLs (1a3c6a7)

  • parsedUrl.host can be null for URLs like http:///path; safe-call with early return

Replace Hardcoded German in Battery Optimization Fallback (98c39a6)

  • ComposeSettingsActivity now uses the existing battery_optimization_open_settings_failed string 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 to MainViewModel and NoteEditorViewModel; showToast() extension deprecated

Centralized Spacing Tokens (db4ce8f)

  • Added SpacingXSmall (2dp), SpacingMediumLarge (12dp), SpacingXXLarge (32dp) to Dimensions; MarkdownRenderer migrated to centralized tokens

Replace Hardcoded Legacy Path Filter with Named Constants (5f4d044)

  • Use Constants.DEFAULT_SYNC_FOLDER_NAME and SyncUrlBuilder.MARKDOWN_SUFFIX instead 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 is true (safe for first install)

🔧 Internal Changes

  • StateFlow migration in NoteEditorViewModel (9071905) — existingNote, isDirty, hasUnsavedChecklistEdits, isRestoringSnapshot are now backed by MutableStateFlow
  • In-memory cache for loadAllNotes with 2s TTL (8b74b43) — avoids re-reading and parsing all JSON files on every onResume; race-safe via AtomicLong version counter
  • Replace android.util.Log with project Logger in 4 files (57c3246) — DragDropListState, NoteEditorScreen, ChecklistItemRow, SettingsViewModel
  • Deduplicate getTimeoutMs into ConnectionManager (ea05e03) — SyncGateChecker now delegates
  • Extract BatteryOptimizationHelper (c3a1e3b) — ComposeSettingsActivity and ComposeMainActivity deduplicated; 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 the GlanceAppWidgetManager → getGlanceIds → forEach update pattern
  • Document @Immutable on Note (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_ENTRIES from 500 to 5000 (b18fa8f) — full sync cycles with 30+ notes can exceed 500 lines
  • Remove dead legacy toReadableTime without context param (d3ea343)
  • Bump version 2.2.0 → 2.3.0 (71cf215)

🌍 Translations

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)

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 # Title and the first checklist item, causing progressive title corruption on every sync cycle (first item merged into title)
  • Defensive parsing in fromMarkdown() and fromJson() 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)

📦 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 (e0abff47f467d7)

  • 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_ago and time_days_ago from <string> to <plurals> for proper grammatical forms in languages like Ukrainian
  • Updated Extensions.kt to use getQuantityString accordingly
  • 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 createdAt timestamp, 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() and saveOnBack() 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
  • null vs emptyList() 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 secondaryContainer to primaryContainer for 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 / onSurface for 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 PdfDocument API — no third-party library required
  • Shared via FileProvider for 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 secondaryContainer colour, 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 DELETING sync phase shown in the banner when deleting multiple notes from the server
  • Progress bar shows current / total with the current note title
  • Phase transitions smoothly to COMPLETED with 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 screenOrientation locks 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)

  • ParallelDownloader already tracked completed / total internally but syncNotes() hardcoded total = 0
  • Fixed: total is now passed through → DOWNLOADING phase shows a real LinearProgressIndicator
  • importMarkdownFiles() also reports per-file progress: banner shows X / Y filename.md with a determinate bar

FGS Timeout on Android 15+ (1e6eb64)

  • Added ensureActive() checkpoints in WebDavSyncService download loop and markdown import so coroutines respond promptly to WorkManager cancellation on targetSdk 35+
  • CancellationException handler in SyncWorker now 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() and updateChecklistItemChecked()

Undo to Saved State Still Triggered Autosave (cf5027b)

  • Undoing all changes back to the last saved state now resets isDirty and cancels the pending autosave
  • New savedSnapshot property 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() returned false (no changes) instead of true (proceed) when lastSyncTime > 0 and folder was missing
  • Fix: returns true to 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.NotesIcons.AutoMirrored.Outlined.Notes
  • Removed unused Color import from ServerSettingsScreen + detekt baseline entry
  • Logger timestamps use Locale.ROOT instead of Locale.getDefault()
  • Removed obsolete Build.VERSION_CODES.N check (minSdk=24)

Detekt Compliance (f0e143c)

  • Extraction of ALL_DELETED_GUARD_THRESHOLD constant 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 TextNotePreview which was truncated and non-scrollable
  • 2x1 and 4x1 widgets now show scrollable text content
  • Removed unused TextNotePreview function 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 TextFieldValue API to TextFieldState API
  • Added external scrollState parameter to OutlinedTextField
  • 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 isDragConfirmed state 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 itemsIndexed blocks destroyed Composition on boundary crossing — unified into single items block

SyncMutex Deadlock via clearSessionCache() Exception (IMPL_13) (99f451b)

  • Wrapped clearSessionCache() in try-catch inside finally block
  • 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 NotesStorage instance in hasUnsyncedChanges() (19a)
  • Replaced runBlocking with coroutineScope in downloadRemoteNotes() 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_SCROLL and WIDE_SCROLL size classes with 150dp threshold
  • Removed clickable modifier 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 ChecklistPreviewHelper with 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 DraggableChecklistItem composable 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 SyncStateManager singleton 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: 0 in 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 -keep rules 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.** { *; }
  • 🛡️ Added safety-guards in detectServerDeletions()
    • Prevents mass deletion when serverNoteIds is empty (network errors)
    • Aborts if ALL local notes would be marked as deleted
  • ✅ 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_SERVER sync 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 PENDING after 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 SYNCED before 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

  • SafeSardineWrapper now implements Closeable for explicit resource cleanup
  • HTTP connection pool is properly evicted after sync
  • Prevents socket exhaustion during frequent syncs

🔧 Technical Details

  • IMPL_001: kotlinx.coroutines.sync.Mutex for 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.Editor updates
  • IMPL_014: Server mtime parameter in Note.fromMarkdown()
  • IMPL_015: syncStatus set before toJson() 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 ForegroundInfo with sync progress notification for Android 9-11
  • Android 10+: Sets FOREGROUND_SERVICE_TYPE_DATA_SYNC for 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 SafeSardineWrapper class 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 NoteCardGrid with 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

  • NoteCardGrid component 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() vs isServerConfigured() (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 content field
    • 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

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: checklist for identification

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_STATE permission
    • Removed CHANGE_WIFI_STATE permission
    • WiFi binding now works via IP detection instead of SSID matching
    • Cleaned up all SSID-related code from codebase and documentation

Technical Improvements

  • 📦 New Data Model

    • NoteType enum: TEXT, CHECKLIST
    • ChecklistItem data class with id, text, isChecked, order
    • Note.kt extended with noteType and checklistItems fields
  • 🔄 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 RadioButtons
    • app:tint statt android:tint fü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) vs dev.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: SharedPreferences mit Key-Pattern etag_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 mit StateFlow<Boolean> für Sync-Status
  • MainActivity: Observer auf SyncStateManager.isSyncing für UI-Updates
  • Layout: sync_status_banner mit ProgressBar + TextView
  • WebDavSyncService: Skip-Logik für unveränderte JSON/MD Dateien basierend auf lastSyncTimestamp
  • WebDavSyncService: Neue Session-Cache-Variablen (sessionSardine, sessionWifiAddress, notesDirEnsured)
  • getOrCreateSardine(): Cached Sardine-Client mit automatischer Credentials-Konfiguration
  • getOrCacheWiFiAddress(): WiFi-Adresse wird nur einmal pro Sync ermittelt
  • clearSessionCache(): Aufräumen am Ende jeder Sync-Session
  • ensureNotesDirectoryExists(): 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 DeletionTracker model with JSON persistence
  • NotesStorage: Added deletion tracking methods
  • WebDavSyncService.hasUnsyncedChanges(): Intelligent server checks with E-Tag caching
  • WebDavSyncService.downloadRemoteNotes(): Deletion-aware downloads
  • WebDavSyncService.restoreFromServer(): Support for restore modes
  • WebDavSyncService.deleteNoteFromServer(): Server deletion with YAML frontmatter scanning
  • WebDavSyncService.importMarkdownFiles(): Automatic Markdown import during sync
  • WebDavSyncService.manualMarkdownSync(): Manual sync with result counts
  • MainActivity.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

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 /notes URL structures
    • Previously, MD files were incorrectly placed in the root directory
    • Markdown import now finds files correctly
  • 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/ and http://server:8080/notes/ work correctly
    • Backward compatible: existing setups with /notes in URL continue to work
    • No migration required for existing users

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 /webdav to /notes to match app behavior
    • Example now shows: http://192.168.0.188:8080/notes

Technical

  • WebDavSyncService.ensureMarkdownDirectoryExists() - Creates MD folder early
  • WebDavSyncService.getMarkdownUrl() - Smart URL detection for both structures
  • WebDavSyncService.exportAllNotesToMarkdown() - Exports all local notes with progress callback
  • SettingsActivity.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
    • .md files synced to notes-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 logic
  • Note.toMarkdown() / Note.fromMarkdown() - Markdown conversion with YAML frontmatter
  • WebDavSyncService - 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_MINUTES preference key
  • NetworkMonitor reads interval from SharedPreferences
  • ExistingPeriodicWorkPolicy.UPDATE for 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)