import 'dart:io'; import 'package:worldhopper/models/downloaded_series.dart'; import 'package:worldhopper/models/entry.dart'; import 'package:worldhopper/repositories/downloaded_chapters_repository.dart'; import 'package:worldhopper/services/epub_download_service.dart'; /// Service for checking if content is available offline /// /// Determines whether a given OPDS entry can be accessed without /// an internet connection. class OfflineContentChecker { final EpubDownloadService _epubService; final DownloadedChaptersRepository? _chaptersRepo; OfflineContentChecker({ required EpubDownloadService epubService, DownloadedChaptersRepository? chaptersRepo, }) : _epubService = epubService, _chaptersRepo = chaptersRepo; /// Check if the given content is available offline /// /// Returns true if: /// - The entry is in the downloaded chapters DB with a valid file path /// - For EPUBs: Also checks if the file is cached via flutter_cache_manager /// /// Returns false otherwise. Future isContentAvailableOffline( Entry entry, { String? serverId, }) async { // Check downloaded chapters first (works for both EPUBs and image streams) final chaptersRepo = _chaptersRepo; if (chaptersRepo != null && serverId != null) { final chapter = await chaptersRepo.getByEntryId(serverId, entry.id); if (chapter != null && chapter.status == DownloadStatus.complete && chapter.filePath != null) { // Verify the file/directory actually exists on disk if (chapter.contentType == ChapterContentType.epub) { if (await File(chapter.filePath!).exists()) return true; } else { if (await Directory(chapter.filePath!).exists()) return true; } } } // Fall back to EPUB cache check if (entry.isEpub) { return await _epubService.isEpubCached(entry); } // Image streams without downloads require server connection if (entry.isImageStream) { return false; } // Default to false for unknown content types return false; } /// Get the local file path for a downloaded chapter Future getLocalPath(String serverId, String entryId) async { final chaptersRepo = _chaptersRepo; if (chaptersRepo == null) return null; final chapter = await chaptersRepo.getByEntryId(serverId, entryId); if (chapter != null && chapter.status == DownloadStatus.complete && chapter.filePath != null) { return chapter.filePath; } return null; } /// Get a detailed status message about offline availability Future getOfflineStatusMessage(Entry entry) async { if (entry.isEpub) { final isCached = await _epubService.isEpubCached(entry); if (isCached) { return 'This EPUB is cached and available offline.'; } else { return 'This EPUB is not cached. Connect to internet to download.'; } } if (entry.isImageStream) { return 'Image streams require an internet connection. Pages may not load offline.'; } return 'This content requires an internet connection.'; } }