157 Commits

Author SHA1 Message Date
05e79d763e chore: Update file author credits to Ilyas Hallak 2025-12-01 22:10:41 +01:00
358037427c refactor: Remove unused stripHTMLSimple method from StringExtensions
- Remove stripHTMLSimple regex-based HTML stripping method
- Keep stripHTML with NSAttributedString-based implementation (used in codebase)
- Method was not used anywhere in the project
2025-12-01 22:06:52 +01:00
fcf6c3e441 feat: Add debug menu and image diagnostics, improve test coverage
- Add DebugMenuView with network simulation, offline cache management, and Core Data reset
- Add OfflineImageDebugView for diagnosing offline image loading issues
- Implement debug diagnostics for cached articles and hero image caching
- Add cache info display (size, article count) in debug menu
- Add shake gesture detection for debug menu access
- Fix LocalBookmarksSyncView callback syntax in PhoneTabView
- Clean up StringExtensionsTests by removing stripHTMLSimple tests and performance tests
- Remove SnapshotHelper import from readeckUITests.swift
- Remove snapshot testing code from readeckUITests
- Add comprehensive test cases for edge cases (malformed HTML, Unicode, newlines, lists)
2025-12-01 22:03:19 +01:00
8dc5f3000a feat: Add annotations, cache management, and offline feature improvements
- Add annotation creation to API and repository layer (AnnotationsRepository)
- Add DtoMapper for AnnotationDto to domain model conversion
- Extend PAnnotationsRepository protocol with createAnnotation method
- Add cache management to SettingsRepository (getCacheSize, getMaxCacheSize, updateMaxCacheSize, clearCache)
- Extend PSettingsRepository protocol with cache settings methods
- Use localized Highlight label in annotation overlay JavaScript for WebView and NativeWebView
- Improve API error handling with detailed logging for HTTP errors and response data
- Add LocalizedError extension for APIError with human-readable descriptions
- Update localization strings for German and English (Highlight, Synchronization, VPN warning)
- Update RELEASE_NOTES.md with version 2.0.0 offline reading feature details
2025-12-01 22:01:23 +01:00
4fd55ef5d0 Refactor settings to use Clean Architecture with ViewModels
- Add cache settings UseCases (get/update size, clear cache)
- Create CacheSettingsViewModel and OfflineSettingsViewModel
- Replace direct UserDefaults access with repository pattern
- Add CachedArticlesPreviewView for viewing offline articles
- Integrate offline settings into main SettingsContainerView
- Wire up new UseCases in factory pattern
2025-12-01 21:56:13 +01:00
39bb82ee3e Migrate offline settings from UserDefaults to CoreData
Move offline reading settings from JSON-based UserDefaults storage to CoreData SettingEntity for consistency with other app settings.

Changes:
- Add offline settings fields to SettingEntity (offlineEnabled, offlineMaxUnreadArticles, offlineSaveImages, offlineLastSyncDate)
- Update SettingsRepository to use CoreData instead of UserDefaults for offline settings
- Use consistent async/await pattern with withCheckedThrowingContinuation
- Remove JSON encoding/decoding in favor of direct CoreData properties

Benefits:
- Unified settings storage in CoreData
- Type-safe property access
- Automatic migration support
- No redundant UserDefaults entries
2025-12-01 21:43:29 +01:00
b9f8e11782 Refactor offline sync to enforce Clean Architecture
Refactorings:
- Extract HTMLImageEmbedder and HTMLImageExtractor utilities
- Create UseCases for cached data access (GetCachedBookmarksUseCase, GetCachedArticleUseCase)
- Create CreateAnnotationUseCase to remove API dependency from ViewModel
- Simplify CachedAsyncImage by extracting helper methods
- Fix Kingfisher API compatibility (Source types, Result handling)
- Add documentation to OfflineCacheSyncUseCase
- Remove unused TestView from production code

Enforces Clean Architecture:
- ViewModels now only use UseCases, no direct Repository or API access
- All data layer access goes through Domain layer
2025-11-30 19:12:51 +01:00
305b8f733e Implement offline hero image caching with custom cache keys
Major improvements to offline reading functionality:

**Hero Image Offline Support:**
- Add heroImageURL field to BookmarkEntity for persistent storage
- Implement ImageCache-based caching with custom keys (bookmark-{id}-hero)
- Update CachedAsyncImage to support offline loading via cache keys
- Hero images now work offline without URL dependency

**Offline Bookmark Loading:**
- Add proactive offline detection before API calls
- Implement automatic fallback to cached bookmarks when offline
- Fix network status initialization race condition
- Network monitor now checks status synchronously on init

**Core Data Enhancements:**
- Persist hero image URLs in BookmarkEntity.heroImageURL
- Reconstruct ImageResource from cached URLs on offline load
- Add extensive logging for debugging persistence issues

**UI Updates:**
- Update BookmarkDetailView2 to use cache keys for hero images
- Update BookmarkCardView (all 3 layouts) with cache key support
- Improve BookmarksView offline state handling with task-based loading
- Add 50ms delay for network status propagation

**Technical Details:**
- NetworkMonitorRepository: Fix initial status from hardcoded true to actual network check
- BookmarksViewModel: Inject AppSettings for offline detection
- OfflineCacheRepository: Add verification logging for save/load operations
- BookmarkEntityMapper: Sync heroImageURL on save, restore on load

This enables full offline reading with hero images visible in bookmark lists
and detail views, even after app restart.
2025-11-28 23:01:20 +01:00
e4657aa281 Fix offline reading bugs and improve network monitoring (Phase 5)
Bugfixes:
- Add toggle for offline mode simulation (DEBUG only)
- Fix VPN false-positives with interface count check
- Add detailed error logging for download failures
- Fix last sync timestamp display
- Translate all strings to English

Network Monitoring:
- Add NetworkMonitorRepository with NWPathMonitor
- Check path.status AND availableInterfaces for reliability
- Add manual reportConnectionFailure/Success methods
- Auto-load cached bookmarks when offline
- Visual debug banner (green=online, red=offline)

Architecture:
- Clean architecture with Repository → UseCase → ViewModel
- Network status in AppSettings for global access
- Combine publishers for reactive updates
2025-11-21 21:37:24 +01:00
fdc6b3a6b6 Add offline reading UI and app integration (Phase 4 & 5)
Phase 4 - Settings UI:
- Add OfflineSettingsViewModel with reactive bindings
- Add OfflineSettingsView with toggle, slider, sync button
- Integrate into SettingsContainerView
- Extend factories with offline dependencies
- Add debug button to simulate offline mode (DEBUG only)

Phase 5 - App Integration:
- AppViewModel: Auto-sync on app start with 4h check
- BookmarksViewModel: Offline fallback loading cached articles
- BookmarksView: Offline banner when network unavailable
- BookmarkDetailViewModel: Cache-first article loading
- Fix concurrency issues with CurrentValueSubject

Features:
- Background sync on app start (non-blocking)
- Cached bookmarks shown when offline
- Instant article loading from cache
- Visual offline indicator banner
- Full offline reading experience

All features compile and build successfully.
2025-11-18 17:44:43 +01:00
f5dab38038 Add offline cache infrastructure with clean architecture
Create separate cache repository layer:
- Add POfflineCacheRepository protocol for cache operations
- Add OfflineCacheRepository with CoreData and Kingfisher
- Add OfflineCacheSyncUseCase to coordinate sync workflow
- Update PBookmarksRepository to focus on API calls only
- Extend BookmarkEntityMapper with toDomain() conversion

UseCase coordinates between cache, API, and settings repositories
following dependency inversion principle.
2025-11-17 23:53:44 +01:00
24dba33b39 Merge branch 'develop' into offline-sync 2025-11-17 18:20:24 +01:00
a3b3863fa3 Refactor tag management system with improved search and real-time sync
- Add CreateLabelUseCase for consistent label creation across app and extension
- Implement TagRepository for Share Extension to persist new labels to Core Data
- Enhance CoreDataTagManagementView with real-time search functionality
- Add automatic tag synchronization on app startup and resume
- Improve Core Data context configuration for better extension support
- Unify label terminology across UI components (tags -> labels)
- Fix label persistence issues in Share Extension
- Add immediate Core Data persistence for newly created labels
- Bump version to 36
2025-11-10 21:29:38 +01:00
c4cd3a0dc3 Add foundation layer for offline article caching
Implement data layer infrastructure for Offline Reading feature (Stage 1):
- Add OfflineSettings model with 4-hour sync interval
- Extend BookmarkEntity with cache fields (htmlContent, cachedDate, imageURLs, etc.)
- Add offline cache methods to BookmarksRepository with Kingfisher image prefetching
- Extend SettingsRepository with offline settings persistence
- Add PSettingsRepository protocol with offline methods
- Implement FIFO cleanup for cached articles
2025-11-08 23:15:17 +01:00
db0ce09b4c Add sync category to Logger
- Add LogCategory.sync for offline sync operations
- Add Logger.sync static property for easy access
2025-11-08 23:15:17 +01:00
4134b41be2 Fix tag scrolling and improve debug logging
- Fix duplicate ID warning in CoreDataTagManagementView by using objectID
- Enhance debug logging system with category filtering
2025-11-08 19:18:56 +01:00
e5d4e6d8a0 Fix tag scrolling and improve debug logging
- Fix duplicate ID warning in CoreDataTagManagementView by using objectID
- Enhance debug logging system with category filtering
2025-11-08 19:18:41 +01:00
4b788650b8 Redesign settings screen with native iOS style
- Move font settings to dedicated detail screen with larger preview
- Add inline explanations directly under each setting
- Reorganize sections: split General into Reading Settings and Sync Settings
- Combine Legal, Privacy and Support into single section
- Move "What's New" to combined Legal/Privacy/Support section
- Redesign app info footer with muted styling and center alignment
- Remove white backgrounds from font preview for better light/dark mode support
2025-11-08 19:12:08 +01:00
f3719fa9d4 Refactor tag management to use Core Data with configurable sorting
This commit introduces a comprehensive refactoring of the tag management
system, replacing the previous API-based approach with a Core Data-first
strategy for improved performance and offline support.

Major Changes:

Tag Management Architecture:
- Add CoreDataTagManagementView using @FetchRequest for reactive updates
- Implement cache-first sync strategy in LabelsRepository
- Create SyncTagsUseCase following Clean Architecture principles
- Add TagSortOrder enum for configurable tag sorting (by count/alphabetically)
- Mark LegacyTagManagementView as deprecated

Share Extension Improvements:
- Replace API-based tag loading with Core Data queries
- Display top 150 tags sorted by usage count
- Remove unnecessary label fetching logic
- Add "Most used tags" localized title
- Improve offline bookmark tag management

Main App Enhancements:
- Add tag sync triggers in AddBookmarkView and BookmarkLabelsView
- Implement user-configurable tag sorting in settings
- Add sort order indicator labels with localization
- Automatic UI updates via SwiftUI @FetchRequest reactivity

Settings & Configuration:
- Add TagSortOrder setting with persistence
- Refactor Settings model structure
- Add FontFamily and FontSize domain models
- Improve settings repository with tag sort order support

Use Case Layer:
- Add SyncTagsUseCase for background tag synchronization
- Update UseCaseFactory with tag sync support
- Add mock implementations for testing

Localization:
- Add German and English translations for:
  - "Most used tags"
  - "Sorted by usage count"
  - "Sorted alphabetically"

Technical Improvements:
- Batch tag updates with conflict detection
- Background sync with silent failure handling
- Reduced server load through local caching
- Better separation of concerns following Clean Architecture
2025-11-08 13:46:40 +01:00
460b05ef34 Add delete annotation feature with swipe gesture
Implemented ability to delete annotations via swipe-to-delete gesture in the annotations list view. Added close button with X icon to dismiss the annotations sheet.

Changes:
- Added DeleteAnnotationUseCase with repository integration
- Extended API with DELETE endpoint for annotations
- Implemented swipe-to-delete in AnnotationsListView
- Added error handling and optimistic UI updates
- Updated toolbar with close button (X icon)
2025-11-01 14:03:39 +01:00
7338db5fab Improve debug logging system
- Redesign logging configuration UI with cleaner list-based navigation
- Replace segmented controls with detailed selection screens for better UX
- Add in-app debug log viewer with filtering and search capabilities
- Implement opt-in logging toggle to reduce device performance impact
- Add log storage system with 1000 entry limit
- Enable log export via share sheet
- Show warning banner when logging is disabled
2025-11-01 13:54:40 +01:00
4b93c605f1 Redesign settings screen with native iOS style
- Refactor all settings views to use List with .insetGrouped style
- Create reusable SettingsRow components for consistent UI
- Separate onboarding flow into dedicated OnboardingServerView
- Consolidate font, theme, and card layout into unified Appearance section
- Add visual card layout previews in dedicated selection screen
- Move "Open links in" option to Appearance with descriptive footer
- Improve settings organization and native iOS feel
2025-10-31 23:39:59 +01:00
4e973751f4 Simplify release notes for regular users 2025-10-30 22:27:14 +01:00
571d61c8e5 Update release notes for markdown rendering improvement 2025-10-30 21:54:02 +01:00
05ae421a40 Add MarkdownUI package and cleanup project structure
- Add swift-markdown-ui package dependency (v2.4.1)
- Remove old Logger.swift (moved to Utils/Logger.swift)
- Remove RELEASE_NOTES.md from Resources (moved to UI/Resources)
- Update German localization strings for settings sections
- Bump build version to 32
2025-10-30 21:50:33 +01:00
85bad35788 Refactor release notes to use MarkdownUI library
- Create MarkdownContentView to encapsulate MarkdownUI rendering
- Replace custom AttributedString markdown parsing with MarkdownUI
- Simplify ReleaseNotesView by removing manual markdown styling
- Improve markdown rendering with proper support for lists, links, and formatting
- Make markdown rendering easily replaceable by keeping it in a dedicated view
2025-10-30 21:48:28 +01:00
db3cbf41d4 Fix URL label translation and formatting
- Add localization keys for "open_url" and "open_original_page" in EN/DE
- Create URLUtil.openUrlLabel() helper function for consistent formatting
- Replace incorrect string concatenation with proper localized labels
- Fix: "example.comopen" now displays as "Open example.com" (EN) or "example.com öffnen" (DE)
- Update BookmarkDetailLegacyView, BookmarkDetailView2, and BookmarkCardView
2025-10-30 21:14:40 +01:00
cdfa6dc4c5 Fix annotation navigation by scrolling outer ScrollView instead of WebView
The JavaScript was executing scrollIntoView() but the WebView itself cannot
scroll (isScrollEnabled = false). Fixed by calculating the annotation's Y
position in the WebView and scrolling the outer ScrollView to the correct
position instead.

Changes:
- WebView.swift: Added onScrollToPosition callback and scrollToPosition
  message handler. JavaScript now calculates and sends annotation position
  to Swift instead of using scrollIntoView().
- NativeWebView.swift: Same changes for iOS 26+ with polling mechanism for
  window.__pendingScrollPosition.
- BookmarkDetailLegacyView.swift: Implemented onScrollToPosition callback
  that calculates final scroll position (header height + annotation position)
  and scrolls the outer ScrollView.
- BookmarkDetailView2.swift: Same implementation as BookmarkDetailLegacyView.
2025-10-30 21:07:13 +01:00
87464943ac bumped build version and version 2025-10-29 22:12:02 +01:00
907cc9220f perf: Optimize label loading for 1000+ labels
Major performance improvements to prevent crashes and lag when working with large label collections:

Main App:
- Switch to Core Data as primary source for labels (instant loading)
- Implement background API sync to keep labels up-to-date
- Add LazyVStack for efficient rendering of large label lists
- Use batch operations instead of individual queries (1 query vs 1000)
- Generate unique IDs for local labels to prevent duplicate warnings

Share Extension:
- Convert getTags() to async with background context
- Add saveTags() method with batch insert support
- Load labels from Core Data first, then sync with API
- Remove duplicate server reachability checks
- Reduce memory usage and prevent UI freezes

Technical Details:
- Labels now load instantly from local cache
- API sync happens in background without blocking UI
- Batch fetch operations for optimal database performance
- Proper error handling for offline scenarios
- Fixed duplicate ID warnings in ForEach loops

Fixes crashes and lag reported by users with 1000+ labels.
2025-10-26 21:24:12 +01:00
c629894611 feat: Show annotations button only when article contains annotations
Add conditional visibility for the annotations button in the toolbar based on whether the loaded article contains any rd-annotation tags.

Changes:
- Add hasAnnotations property to BookmarkDetailViewModel
- Check for <rd-annotation tags when processing article content
- Conditionally show/hide annotations button in BookmarkDetailView2
2025-10-26 21:20:08 +01:00
b77e4e3e9f refactor: Centralize annotation colors and improve color consistency
- Move AnnotationColor enum to Constants.swift for centralized color management
- Add hexColor property to provide hex values for JavaScript overlays
- Add cssColorWithOpacity method for flexible opacity control
- Update NativeWebView and WebView to use centralized color values
- Replace modal color picker with inline overlay for better UX
- Implement annotation creation directly from text selection
- Add API endpoint for creating annotations with selectors
2025-10-25 09:19:49 +02:00
1b9f79bccc fix: Use callJavaScript instead of evaluateJavaScript for WebPage
WebPage in iOS 26 uses callJavaScript method, not evaluateJavaScript.
2025-10-22 15:58:07 +02:00
d1157defbe fix: Resolve WebPage binding error in NativeWebView text selection
Capture webPage locally in Task to avoid @State binding issues when
calling evaluateJavaScript in async context.
2025-10-22 15:54:55 +02:00
a041300b4f feat: Add text selection support for iOS 26+ NativeWebView
Implement text selection detection in NativeWebView:
- Add onTextSelected callback parameter to NativeWebView
- Use JavaScript polling to detect text selections
- Calculate text offsets for precise annotation positioning
- Integrate color picker in BookmarkDetailView2 for iOS 26+
- Match feature parity with legacy WebView implementation

Text selection now works on both WebView implementations.
2025-10-22 15:35:56 +02:00
ec12815a51 feat: Add text selection and annotation creation UI
Implement interactive text annotation feature:
- Add text selection detection via JavaScript in WebView
- Create AnnotationColorPicker with 4 color options (yellow, green, blue, red)
- Integrate color picker sheet in bookmark detail views
- Calculate text offsets for precise annotation positioning
- Add onTextSelected callback for WebView component
- Prepare UI for future API integration

Users can now select text in articles and choose a highlight color.
API integration for persisting annotations will follow.
2025-10-22 15:30:34 +02:00
cf06a3147d feat: Add annotations support with color-coded highlighting
Add comprehensive annotations feature to bookmark detail views:
- Implement annotations list view with date formatting and state machine
- Add CSS-based highlighting for rd-annotation tags in WebView components
- Support Readeck color scheme (yellow, green, blue, red) for annotations
- Enable tap-to-scroll functionality to navigate to selected annotations
- Integrate annotations button in bookmark detail toolbar
- Add API endpoint and repository layer for fetching annotations
2025-10-22 15:25:55 +02:00
47f8f73664 fix: Improve markdown formatting in release notes view
Add custom AttributedString extension to properly format markdown with correct spacing and header styles. This fixes the compressed appearance of release notes by adding proper line breaks between sections and applying appropriate font sizes to headers.
2025-10-19 20:41:04 +02:00
d97e404cc7 fix: Prevent UICollectionView crash from concurrent bookmark list updates
Add isUpdating flag to prevent race conditions when updating the bookmark list.
This fixes crashes that occurred when returning to the app after adding a bookmark
via the share extension while the list was being updated.
2025-10-19 20:40:02 +02:00
6906509aea fix: Remove trailing slash from endpoint instead of adding it
Trailing slash is added elsewhere in the codebase, so here we remove it if present to avoid duplication
2025-10-19 19:40:25 +02:00
afe3d1e261 feat: Add endpoint normalization with validation rules
- Default to https if no scheme provided
- Only accept http and https schemes
- Add trailing slash to path automatically
- Remove query parameters and fragments
- Update endpoint field with normalized value after save
2025-10-19 19:37:35 +02:00
554e223bbc feat: Redesign server settings form with prompt parameters and quick input chips
- Remove redundant field labels, use prompt parameter instead
- Add QuickInputChip component for quick URL entry
- Add chips: http://, https://, 192.168., :8000
- Improve spacing and layout consistency
- Cleaner, more modern UI appearance
2025-10-19 19:26:40 +02:00
819eb4fc56 feat: Add helpful hint text for server endpoint field
- Clarify HTTP/HTTPS support
- Note HTTP restriction to local networks
- Mention optional port configuration
- Indicate trailing slash not required
2025-10-19 19:17:30 +02:00
6385d10317 fix: Set gray tint color for server endpoint TextField placeholder 2025-10-19 19:16:12 +02:00
31ed3fc0e1 fix: Use @State instead of @StateObject for @Observable AppViewModel
- Replace @StateObject with @State for @Observable conformance
- Remove unnecessary Task wrapper in init
- Call loadSetupStatus() synchronously since it's already @MainActor
2025-10-19 19:06:35 +02:00
04de2c20d4 refactor: Use @Observable and inject factory in AppViewModel
- Replace ObservableObject with @Observable macro
- Inject UseCaseFactory instead of individual use cases
- Use factory.makeCheckServerReachabilityUseCase() on demand
- Use factory.makeLogoutUseCase() for 401 handling
2025-10-19 19:01:54 +02:00
fde1140f24 refactor: Check server reachability on app resume instead of app start
- Move server check from init to onAppResume() in AppViewModel
- Add scenePhase observer in readeckApp
- Check only when app becomes active (.active phase)
- Respects 30s cache - won't call API if recently checked
2025-10-19 11:08:13 +02:00
e5334d456d refactor: Remove NWPathMonitor auto-sync, keep only on-demand server checks
- Delete NetworkConnectivity.swift with problematic NWPathMonitor
- Remove serverDidBecomeAvailable notification
- Remove unused startAutoSync from OfflineSyncManager
- Server check now only on app start via AppViewModel
2025-10-19 10:47:19 +02:00
1957995a9e refactor: Update NetworkConnectivity to use CheckServerReachabilityUseCase 2025-10-19 10:45:21 +02:00
bf3ee7a1d7 fix: Add MockCheckServerReachabilityUseCase implementation 2025-10-19 10:32:44 +02:00