Fixes 22 Detekt warnings across the codebase:
- Remove 7 unused imports from UI components
- Add @Suppress annotations for 4 preview functions
- Define constants for 5 magic numbers
- Optimize state reads with derivedStateOf (2 fixes)
- Add @Suppress for long parameter list
- Move WidgetSizeClass to separate file
- Reformat long line in NoteEditorScreen
- Suppress unused parameter and property annotations
- Suppress WebDavSyncService method length/complexity with TODO for v1.9.0 refactoring
Test results:
- detekt: 0 warnings
- lintFdroidDebug: 0 errors
- Build successful
Progress v1.8.0: 0 Lint errors + 0 Detekt warnings complete
- Add SortOption enum for note sorting (Updated, Created, Title, Type)
- Add SortDirection enum with ASCENDING/DESCENDING and toggle()
- Add ChecklistSortOption enum for in-editor sorting (Manual, Alphabetical, Unchecked/Checked First)
- Implement persistent note sort preferences in SharedPreferences
- Add SortDialog for main screen with sort option and direction selection
- Add ChecklistSortDialog for editor screen with current sort option state
- Implement sort logic in MainViewModel with combined sortedNotes StateFlow
- Implement sort logic in NoteEditorViewModel with auto-sort for MANUAL and UNCHECKED_FIRST
- Add separator display logic for MANUAL and UNCHECKED_FIRST sort options
- Add 16 sorting-related strings (English and German)
- Update Constants.kt with sort preference keys
- Update MainScreen.kt, NoteEditorScreen.kt with sort UI integration
Complete Jetpack Glance Widget Framework
- Implement NoteWidget with 5 responsive size classes
- Support TEXT and CHECKLIST note types
- Material You dynamic colors integration
- Interactive checklist checkboxes in large layouts
- Read-only mode for locked widgets
Widget Configuration System
- NoteWidgetConfigActivity for placement and reconfiguration (Android 12+)
- NoteWidgetConfigScreen with note selection and settings
- Lock widget toggle to prevent accidental edits
- Background opacity slider with 0-100% range
- Auto-save on back navigation plus Save FAB
Widget State Management
- NoteWidgetState keys for per-instance persistence via DataStore
- NoteWidgetActionKeys for type-safe parameter passing
- Five top-level ActionCallback classes
* ToggleChecklistItemAction (updates checklist and marks for sync)
* ToggleLockAction (toggle read-only mode)
* ShowOptionsAction (show permanent options bar)
* RefreshAction (reload from storage)
* OpenConfigAction (launch widget config activity)
Responsive Layout System
- SMALL (110x80dp): Title only
- NARROW_MEDIUM (110x110dp): Preview or compact checklist
- NARROW_TALL (110x250dp): Full content display
- WIDE_MEDIUM (250x110dp): Preview layout
- WIDE_TALL (250x250dp): Interactive checklist
Interactive Widget Features
- Tap content to open editor (unlock) or show options (lock)
- Checklist checkboxes with immediate state sync
- Options bar with Lock/Unlock, Refresh, Settings, Open in App buttons
- Per-widget background transparency control
Connection Leak Fixes (Part of IMPL_019)
- Override put/delete/createDirectory in SafeSardineWrapper with response.use{}
- Proper resource cleanup in exportAllNotesToMarkdown and syncMarkdownFiles
- Use modern OkHttp APIs (toMediaTypeOrNull, toRequestBody)
UI Improvements (Part of IMPL_019)
- Checkbox toggle includes KEY_LAST_UPDATED to force Glance recomposition
- Note selection in config is visual-only (separate from save)
- Config uses moveTaskToBack() plus FLAG_ACTIVITY_CLEAR_TASK
- Proper options bar with standard Material icons
Resources and Configuration
- 8 drawable icons for widget controls
- Widget metadata file (note_widget_info.xml)
- Widget preview layout for Android 12+ widget picker
- Multi-language strings (English and German)
- Glance Jetpack dependencies version 1.1.1
System Integration
- SyncWorker updates all widgets after sync completion
- NoteEditorViewModel reloads checklist state on resume
- ComposeNoteEditorActivity reflects widget edits
- WebDavSyncService maintains clean connections
- AndroidManifest declares widget receiver and config activity
Complete v1.8.0 Widget Feature Set
- Fully responsive design for phones, tablets and foldables
- Seamless Material Design 3 integration
- Production-ready error handling
- Zero connection leaks
- Immediate UI feedback for all interactions
- Separator component: Visual divider between unchecked and checked items
* Shows count of completed items with denominator styling
* Prevents accidental drag across group boundaries
* Smooth transitions with fade/slide animations
- Sorting logic: Maintains unchecked items first, checked items last
* Stable sort: Relative order within groups is preserved
* Auto-updates on item toggle and reordering
* Validates drag moves to same-group only
- UI improvements: Enhanced LazyColumn animations
* AnimatedVisibility for smooth item transitions
* Added animateItem() for LazyColumn layout changes
* Item elevation during drag state
- Comprehensive test coverage
* 9 unit tests for sorting logic validation
* Edge cases: empty lists, single items, mixed groups
* Verifies order reassignment and group separation
Affected components:
- CheckedItemsSeparator: New UI component for visual separation
- NoteEditorViewModel: sortChecklistItems() method with validation
- NoteEditorScreen: Separator integration & animation setup
- ChecklistSortingTest: Complete test suite with 9 test cases
- Localizations: German & English plurals
- Swap detection: Changed from midpoint check to straddle-target-center detection
* Old: Checks if midpoint of dragged item lies within target
* New: Checks if dragged item spans the midpoint of target
* Prevents oscillation when items have different sizes
- Adjacency filter: Only adjacent items (index ± 1) as swap candidates
* Prevents item jumps during fast drag
* Reduces recalculation of visibleItemsInfo
- Race-condition fix for scroll + move
* draggingItemIndex update moved after onMove() in coroutine block
* Prevents inconsistent state between index update and layout change
Affected files:
- DragDropListState.kt: onDrag() method (~10 lines changed)
- Add OverflowGradient.kt: Reusable Compose component for visual text overflow indicator
- Gradient fade effect shows "more text below" without hard cutoff
- Smooth black-to-transparent gradient (customizable intensity)
- Auto-expands ChecklistItem when focused for full editing
- Collapses back to max 5 lines when focus lost
- Prevents accidental text hiding while editing
- Improved visual feedback for long text items
- Works on all screen sizes and orientations
Closes #IMPL_018
- Add SyncProgress.kt: Data class for entire sync lifecycle UI state
- Add SyncPhase enum: IDLE, PREPARING, UPLOADING, DOWNLOADING, IMPORTING_MARKDOWN, COMPLETED, ERROR
- Rewrite SyncStateManager.kt: SyncProgress (StateFlow) is single source of truth
- Remove pre-set phases: CHECKING_SERVER and SAVING cause flickering
- UPLOADING phase only set when actual uploads happen
- DOWNLOADING phase only set when actual downloads happen
- IMPORTING_MARKDOWN phase only set when feature enabled
- Add onProgress callback to uploadLocalNotes() with uploadedCount/totalToUpload
- Add onProgress callback to downloadRemoteNotes() for actual downloads only
- Progress display: x/y for uploads (known total), count for downloads (unknown)
- Add SyncProgressBanner.kt: Unified banner (replaces dual system)
- Update SyncStatusBanner.kt: Kept for legacy compatibility, only COMPLETED/ERROR
- Update MainViewModel.kt: Remove _syncMessage, add syncProgress StateFlow
- Update MainScreen.kt: Use only SyncProgressBanner (unified)
- Update ComposeMainActivity.kt: Auto-hide COMPLETED (2s), ERROR (4s) via lifecycle
- Add strings.xml (DE+EN): sync_phase_* and sync_wifi_only_error
- Banner appears instantly on sync button click (PREPARING phase)
- Silent auto-sync (onResume) completely silent, errors always shown
- No misleading counters when nothing to sync
Closes #IMPL_006
- New SyncStatusLegendDialog.kt showing all 5 sync status icons with descriptions
- Help button (?) in MainScreen TopAppBar (only visible when sync available)
- Localized strings (English + German) for all 5 status explanations
- Material You design with consistent colors matching NoteCard icons
- Dialog shows: Synced, Pending, Conflict, Local only, Deleted on server
IMPL_021_SYNC_STATUS_LEGEND.md
- Add DELETED_ON_SERVER to SyncStatus enum
- Add deletedOnServerCount to SyncResult
- Implement detectServerDeletions() function in WebDavSyncService
- Integrate server deletion detection in downloadRemoteNotes()
- Update UI icons in NoteCard, NoteCardGrid, NoteCardCompact
- Add string resources for deleted_on_server status
- No additional HTTP requests (uses existing PROPFIND data)
- Zero performance impact
Closes #IMPL_016
- AndroidManifest.xml: Added WorkManager SystemForegroundService declaration
with dataSync foregroundServiceType to fix lint error for Expedited Work
- .github/ISSUE_TEMPLATE/config.yml: Added Feature Requests & Ideas link
pointing to GitHub Discussions for non-bug feature discussions
This commit fixes the critical crash on Android 9 (API 28) that occurred when using
WorkManager Expedited Work for background sync operations.
## Root Cause
When setExpedited() is used in WorkManager, the CoroutineWorker must implement
getForegroundInfo() to return a ForegroundInfo object with 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
- Returns ForegroundInfo with sync progress notification
- Android 10+: Sets FOREGROUND_SERVICE_TYPE_DATA_SYNC for proper service typing
- Added required Foreground Service permissions to AndroidManifest.xml
## Technical Changes
- SyncWorker.kt: Added getForegroundInfo() override
- NotificationHelper.kt: Added createSyncProgressNotification() factory method
- strings.xml: Added sync_in_progress UI strings (EN + DE)
- AndroidManifest.xml: Added FOREGROUND_SERVICE permissions
- Version updated to 1.7.1 (versionCode 18)
## Previously Fixed (in this release)
- Kernel-VPN compatibility (Wireguard interface detection)
- HTTP connection lifecycle optimization (SafeSardineWrapper)
- Stability improvements for sync sessions
## Testing
- Tested on Android 9 (API 28) - No crash on second app start
- Tested on Android 15 (API 35) - No regressions
- WiFi-connect sync working correctly
- Expedited work notifications display properly
Fixes#15
Thanks to @roughnecks for detailed bug report and testing!
- Added SafeSardineWrapper to properly close HTTP responses
- Prevents resource exhaustion after extended use (30-45 min)
- Added preemptive authentication to reduce 401 round-trips
- Added ProGuard rule for TextInclusionStrategy warnings
- Updated version to 1.7.1
Refs: #15
Fixes:
1. Notification click now opens ComposeMainActivity instead of legacy MainActivity
2. WiFi-Only toggle moved to its own 'Network Restriction' section at top of sync settings
3. Added hint explaining WiFi-Connect trigger is not affected by WiFi-Only setting
UI Changes:
- New section header: 'Network Restriction' / 'Netzwerk-Einschränkung'
- WiFi-Only toggle now clearly separated from sync triggers
- Info card shows when WiFi-Only is enabled explaining the exception
- Add WebDavSyncService.canSync() as single source of truth
- Add SyncGateResult data class for structured response
- Update MainViewModel.triggerManualSync() to use canSync()
- Update MainViewModel.triggerAutoSync() to use canSync() - FIXES onResume bug
- Update NoteEditorViewModel.triggerOnSaveSync() to use canSync()
- Update SettingsViewModel.syncNow() to use canSync()
- Update SyncWorker to use canSync() instead of direct prefs check
All 9 sync paths now respect WiFi-only setting through one central gate.
- SyncWorker: Add central WiFi-only guard before all sync operations
- NoteEditorViewModel: Add WiFi-only check before onSave sync trigger
- Prevents notes from syncing over 5G/mobile when WiFi-only is enabled
- Fixes: onSave sync ignored WiFi-only setting completely
- NEW: Configurable sync triggers (onSave, onResume, WiFi, Periodic, Boot)
- NEW: Offline mode toggle to disable all network features
- Various fixes and UI improvements
- Version bumped to 1.6.0 (code 14)
FEATURES
========
Batch Delete Toast Aggregation:
- New deleteMultipleNotesFromServer() method
- Shows single aggregated toast instead of multiple ("3 notes deleted from server")
- Partial success handling ("3 of 5 notes deleted from server")
- Added string resources: snackbar_notes_deleted_from_server, snackbar_notes_deleted_from_server_partial
Text Editor Cursor Fix:
- Fixed cursor jumping to end after every keystroke when editing notes
- Added initialCursorSet flag to only set cursor position on first load
- Cursor now stays at user's position while editing
- Changed LaunchedEffect(content) to LaunchedEffect(Unit) to prevent repeated resets
DOCUMENTATION REFACTOR
======================
Breaking Change: English is now the default language
- README.md: Now English (was German)
- QUICKSTART.md: Now English (was German)
- CHANGELOG.md: Now English (was mixed EN/DE)
- docs/*.md: All English (was German)
- German versions: Use .de.md suffix (README.de.md, QUICKSTART.de.md, etc.)
Updated for v1.5.0:
- CHANGELOG.md: Fully translated to English with v1.5.0 release notes
- CHANGELOG.de.md: Created German version
- FEATURES.md: Added i18n section, Selection Mode, Jetpack Compose updates
- FEATURES.de.md: Updated with v1.5.0 features
- UPCOMING.md: v1.5.0 marked as released, v1.6.0/v1.7.0 roadmap
- UPCOMING.de.md: Updated German version
All language headers updated:
- English: [Deutsch](*.de.md) · **English**
- German: **Deutsch** · [English](*.md)
F-DROID METADATA
================
Changelogs (F-Droid):
- fastlane/metadata/android/en-US/changelogs/13.txt: Created
- fastlane/metadata/android/de-DE/changelogs/13.txt: Created
Descriptions:
- full_description.txt (EN/DE): Updated with v1.5.0 changes
- Selection Mode instead of Swipe-to-Delete
- i18n support highlighted
- Jetpack Compose UI mentioned
- Silent-Sync Mode added
OTHER FIXES
===========
Code Quality:
- Unused imports removed from multiple files
- maxLineLength fixes
- Detekt config optimized (increased thresholds for v1.5.0)
- AboutScreen: Uses app foreground icon directly
- EmptyState: Shows app icon instead of emoji
- themes.xml: Splash screen uses app foreground icon
- Added comprehensive English (strings.xml) and German (strings-de.xml) localization with 400+ strings
- Created new LanguageSettingsScreen with System Default, English, and German options
- Fixed hardcoded German notification toasts in MainActivity and ComposeMainActivity
- Integrated Language selector in Settings as top-level menu item
- Changed ComposeSettingsActivity from ComponentActivity to AppCompatActivity for AppCompatDelegate compatibility
- Added locales_config.xml for Android 13+ Per-App Language support
- Updated Extensions.kt with i18n-aware timestamp formatting (toReadableTime with context)
- Translated all UI strings including settings, toasts, notifications, and error messages
- Added dynamic language display in SettingsMainScreen showing current language
Fixes:
- Notification permission toast now respects system language setting
- Activity correctly restarts when language is changed
- All string formatting with parameters properly localized
Migration:
- MainViewModel: All toast messages now use getString()
- SettingsViewModel: All toast and dialog messages localized
- NotificationHelper: Notification titles and messages translated
- UrlValidator: Error messages now accept Context parameter for translation
- NoteCard, DeleteConfirmationDialog, SyncStatusBanner: All strings externalized
Testing completed on device with both EN and DE locale switching.
Closes#5
Silent-Sync Implementation (Auto-Sync Banner Fix):
- Add SYNCING_SILENT state to SyncStateManager for background syncs
- Auto-sync (onResume) now triggers silently without banner interruption
- Silent-sync state blocks additional manual syncs (mutual exclusion)
- Error banners still display even after silent-sync failures
- SyncStatus tracks 'silent' flag to hide COMPLETED banners after silent-sync
UI/UX Improvements (from v1.5.0 post-migration fixes):
- Fix text wrapping in checklist items (singleLine=false, maxLines=5)
- Fix cursor position in text notes (use TextFieldValue with TextRange)
- Display app icon instead of emoji in AboutScreen
- Add smooth slide animations for NoteEditor transitions
- Remove visual noise from AboutScreen icon
Technical Changes:
- ComposeNoteEditorActivity: Add back animation with OnBackPressedCallback
- ComposeMainActivity: Add entry/exit slide animations for note editing
- NoteEditorScreen: Use TextFieldValue for proper cursor positioning
- ChecklistItemRow: Enable text wrapping for long checklist items
- AboutScreen: Convert Drawable to Bitmap via Canvas (supports AdaptiveIcon)
- SyncStatusBanner: Exclude SYNCING_SILENT from visibility checks
- MainActivity: Update legacy auto-sync to use silent mode
Fixes #[auto-sync-banner], improves #[user-experience]
Branch: feature/v1.5.0
Features:
- Migrate NoteEditorActivity from XML to Jetpack Compose
- Support both TEXT and CHECKLIST note types
- FOSS native drag & drop using Compose Foundation APIs (no external dependencies)
- Auto-keyboard focus with explicit keyboard controller show() calls
- Consistent placeholder text for empty checklist items
- Unified delete dialog with Server/Local deletion options
Components:
- ComposeNoteEditorActivity: Activity wrapper with ViewModelFactory for SavedStateHandle
- NoteEditorScreen: Main editor screen supporting TEXT and CHECKLIST modes
- NoteEditorViewModel: State management with WebDav server deletion support
- ChecklistItemRow: Individual checklist item with drag handle, checkbox, text input
- DragDropState: FOSS drag & drop implementation using LazyListState
Improvements:
- Auto-keyboard shows when creating new notes (focuses title/content)
- Keyboard consistently shows when adding new checklist items
- Placeholder text 'Neues Element…' for empty list items
- Delete dialog unified with MainScreen (Server/Local options)
- Server deletion via WebDavSyncService.deleteNoteFromServer()
Debug Enhancements:
- Debug builds have orange icon background (#FFB74D) with red badge
- Debug builds show 'Simple Notes (Debug)' app name
- Easy differentiation between debug and release APKs in launcher
Build Status:
- compileStandardDebug: SUCCESS
- No breaking changes to existing XML-based screens
- Material 3 theming with Dynamic Colors (Material You) applied
Migration Notes:
- Old NoteEditorActivity (XML-based) remains for reference/backwards compatibility
- All editor UI is now Compose-based
- ComposeMainActivity updated to use new ComposeNoteEditorActivity
- Plan document (v1.5.0_EXTENDED_FEATURES_PLAN.md) updated with implementation details
Fixed:
- Delete notes from older app versions (v1.2.0 compatibility)
- Checklist sync backwards compatibility (v1.3.x)
- Fallback content in GitHub task list format
- Recovery mode for lost checklistItems
Improved:
- Checklist auto line wrap (no maxLines limit)
- Enter key creates new item (via TextWatcher)
Metadata:
- Changelogs for versionCode 12
- IzzyOnDroid metadata updated
Fixes#7 - Thanks @IzzySoft for reporting and investigating!
Removed:
- getBuildDate() function from build.gradle.kts
- BUILD_DATE buildConfigField
- Build date display in SettingsActivity
Sorry for the hour of work this caused - will be more careful about RB in the future.
New Features:
- Multi-Device Sync with deletion tracking (prevents zombie notes)
- Server deletion via swipe gesture with confirmation dialog
- E-Tag performance optimization (~150ms vs 3s for no-change syncs)
- Markdown Auto-Sync toggle (unified Export + Auto-Import)
- Manual Markdown sync button for performance control
- Server-Restore modes (Merge/Replace/Overwrite)
Technical Implementation:
- DeletionTracker model with JSON persistence
- Intelligent server checks with E-Tag caching
- Deletion-aware download logic
- Two-stage swipe deletion with Material Design dialog
- Automatic Markdown import during sync
- YAML frontmatter scanning for robust file deletion
Thanks to Thomas from Bielefeld for reporting the multi-device sync issue!
Compatible with: v1.2.0-v1.3.0
- Added dual-mode download for server restore
- Scans both /notes/ (new) and Root (old v1.2.0) folders
- Normal sync only uses /notes/ for performance
- Fixed URL construction bugs
- Updated F-Droid changelogs
## 🐛 Fixed
- Initial Markdown export: Existing notes now exported when Desktop Integration activated
- Markdown directory structure: Files now land correctly in /notes-md/
- JSON URL normalization: Smart detection for both Root-URL and /notes-URL
- GitHub release notes: Fixed language order (DE primary, EN collapsible) and emoji
## ✨ Improved
- Settings UI: Example URL shows /notes instead of /webdav
- Server config: Enter only base URL (app adds /notes/ and /notes-md/ automatically)
- Flexible URL input: Both http://server/ and http://server/notes/ work
- Changelogs: Shortened for F-Droid 500 char limit
## 🔧 Technical
- getNotesUrl() helper with smart /notes/ detection
- getMarkdownUrl() simplified to use getNotesUrl()
- All JSON operations updated to use normalized URLs
- exportAllNotesToMarkdown() with progress callback
- Workflow: Swapped CHANGELOG_DE/EN, replaced broken emoji with 🌍
versionCode: 6
versionName: 1.2.1
✨ New Features:
- Local backup/restore system with 3 modes (Merge/Replace/Overwrite)
- Markdown export for desktop access via WebDAV mount
- Dual-format architecture (JSON master + Markdown mirror)
- Settings UI extended with backup & desktop integration sections
📝 Changes:
- Server restore now asks for mode selection (user safety)
- WebDAV mount instructions for Windows/Mac/Linux in README
- Complete CHANGELOG.md with all version history
🔧 Technical:
- BackupManager.kt for complete backup/restore logic
- Note.toMarkdown/fromMarkdown with YAML frontmatter
- ISO8601 timestamps for desktop compatibility
- Last-Write-Wins conflict resolution
📚 Documentation:
- CHANGELOG.md (Keep a Changelog format)
- README updates (removed Joplin/Obsidian, added WebDAV-mount)
- F-Droid changelogs (DE+EN, under 500 chars)
- SYNC_ARCHITECTURE.md in project-docs
- MARKDOWN_DESKTOP_REALITY_CHECK.md strategic plan
- WEB_EDITOR_PLAN_v1.3.0.md for future web editor feature
- Replace default Android icon with custom notepad design
- Use PNG-based adaptive icons (mipmap) instead of vector drawables for better launcher compatibility
- Add ic_launcher_background.png (light blue #90CAF9) for all densities
- Add ic_launcher_foreground.png (transparent notepad design) for all densities
- Update legacy WebP icons (mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi) with new design
- Update Fastlane metadata icons (de-DE + en-US) with 512x512 PNG
- Improve F-Droid NonFreeNet AntiFeature documentation:
* Clarify HTTP restricted to local networks only (RFC 1918 private IPs, localhost, .local domains)
* Document upcoming v1.1.2 security restrictions
* Emphasize HTTPS support and recommendation
Icon Design:
- White notepad paper with gray border
- Red header line (like real notepads)
- Three blue text bars (representing notes)
- Orange pencil with white tip in bottom-right corner
- Light blue background for adaptive icon
Technical Changes:
- Delete drawable/ic_launcher_background.xml (vector drawables)
- Delete drawable/ic_launcher_foreground.xml (vector drawables)
- Update mipmap-anydpi-v26/ic_launcher.xml: @drawable -> @mipmap
- Update mipmap-anydpi-v26/ic_launcher_round.xml: @drawable -> @mipmap
- Remove monochrome tag (not needed for this design)
Addresses IzzyOnDroid Issue #2 feedback
1. Add en-US screenshots as fallback for all languages
- Copy phoneScreenshots from de-DE to en-US
- Ensures non-German users see screenshots
2. Disable Google DEPENDENCY_INFO_BLOCK
- Add dependenciesInfo { includeInApk = false }
- Removes encrypted Google blob from APK
- Improves privacy and F-Droid compatibility
Fixes#2
- Fixed compileSdk syntax error in build.gradle.kts (was using incorrect 'compileSdk { version = release(36) }' instead of 'compileSdk = 36')
- Moved splits configuration out of defaultConfig to correct location
- Added comprehensive ProGuard rules to handle OkHttp's optional dependencies (BouncyCastle, Conscrypt, OpenJSSE)
- Added ProGuard rules for Sardine WebDAV, Coroutines, and Gson
- Build now completes successfully both locally and in CI/CD