- Change TextNoteFullView() to render individual lines instead of paragraphs
- Preserve empty lines as 8dp spacers for paragraph separation
- Add maxLines=5 per line item to prevent single-item overflow
- Increase preview limits: compact 100→120, full 200→300 chars
- Increase preview maxLines: compact 2→3, full 3→5 lines
Fixes widget text truncation bug where long text notes only showed
3 lines regardless of widget size. By splitting into individual line
items, LazyColumn can properly scroll through all content. Each line
is rendered as a separate item that fits within the visible area.
- Restructure settings into two clear sections: Triggers & Performance
- Add sync_section_triggers and sync_section_network_performance strings (DE + EN)
- Group all 5 triggers together (Instant: onSave/onResume, Background: WiFi/Periodic/Boot)
- Move WiFi-Only + Parallel Downloads to separate "Network & Performance" section
- Place Manual Sync info card after triggers, before Performance section
Improves UX by logically grouping related settings. Triggers are now
in one cohesive block, separated from network/performance options.
Easier to find and understand sync configuration.
- Change DEFAULT_DISPLAY_MODE from 'list' to 'grid'
- Update display_mode_info strings (EN + DE)
- Remove outdated 'full width' reference from info text
- New description reflects actual two-column grid layout
Only affects new installations - existing users keep their preference.
Grid view provides better overview and cleaner visual hierarchy.
- Prevent activity recreate during language changes via configChanges
- Add onConfigurationChanged() handler in ComposeSettingsActivity
- Simplify setAppLanguage() - let system handle locale change smoothly
- Update language_info strings to reflect smooth transition
- Remove unused Activity parameter and imports
Fixes flicker during language switching by handling configuration
changes instead of recreating the entire activity. Compose recomposes
automatically when locale changes, providing seamless UX.
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
- New: Grid view for notes – thanks to freemen
- New: WiFi-only sync toggle in settings
- New: Encryption for local backups – thanks to @SilentCoderHere (ref #9)
- Fixed: Sync now works correctly when VPN is active – thanks to @roughnecks (closes#11)
- Improved: Server change now resets sync status for all notes
- Improved: 'Sync already running' feedback for additional executions
- Various bug fixes and UI improvements
- Added support for self-signed SSL certificates; documentation updated – thanks to Stefan L.
- SHA-256 hash of the signing certificate is now shown in the README and on release pages – thanks to @isawaway (ref #10)
This release brings enhanced security, better sync reliability, and improved usability for self-hosted and private server setups.
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)
🎨 Major Features:
- Full Jetpack Compose UI redesign
- Material Design 3 with Dynamic Colors
- i18n support (English/German)
- Checklists with drag & drop
- Silent-Sync mode
Closes#5