117 lines
4 KiB
Dart
117 lines
4 KiB
Dart
import 'dart:io';
|
||
|
||
import 'package:dio/dio.dart';
|
||
import 'package:worldhopper/models/entry.dart';
|
||
import 'package:worldhopper/models/server.dart';
|
||
import 'package:worldhopper/models/stream_link.dart';
|
||
import 'package:worldhopper/services/opds_parser.dart' show ParsedFeed;
|
||
|
||
/// Server-reported reading progress for an entry.
|
||
///
|
||
/// This represents progress as reported by the server, not the local database.
|
||
/// Used to show progress indicators in the feed without requiring a local
|
||
/// reading history.
|
||
class EntryProgress {
|
||
/// The entry ID this progress belongs to.
|
||
final String entryId;
|
||
|
||
/// Current page (0-indexed).
|
||
final int currentPage;
|
||
|
||
/// Total pages.
|
||
final int totalPages;
|
||
|
||
/// Progress as a fraction (0.0 to 1.0).
|
||
double get percentage =>
|
||
totalPages > 0 ? (currentPage + 1) / totalPages : 0.0;
|
||
|
||
/// Whether the entry has been fully read.
|
||
bool get isCompleted => totalPages > 0 && currentPage >= totalPages - 1;
|
||
|
||
const EntryProgress({
|
||
required this.entryId,
|
||
required this.currentPage,
|
||
required this.totalPages,
|
||
});
|
||
}
|
||
|
||
/// Abstract interface for all server interactions.
|
||
///
|
||
/// Each server software type (OPDS, Kavita, etc.) provides its own
|
||
/// implementation. The UI layer should interact exclusively through this
|
||
/// interface, never branching on [ServerSoftwareType].
|
||
abstract class ServerSoftware {
|
||
/// Returns true if the server URL matches this software's pattern.
|
||
bool detectFromUrl(Server server);
|
||
|
||
/// Test if the server is reachable and credentials are valid.
|
||
///
|
||
/// Returns `true` on success. Throws on failure with details about what
|
||
/// went wrong (network error, auth failure, unexpected response, etc.).
|
||
Future<bool> testConnection(Server server, {CancelToken? cancelToken});
|
||
|
||
/// Fetch the root catalog/feed for a server.
|
||
Future<ParsedFeed> fetchRootFeed(Server server, {CancelToken? cancelToken});
|
||
|
||
/// Fetch a feed/catalog from a specific URL.
|
||
Future<ParsedFeed> fetchFeed(Server server, String url,
|
||
{CancelToken? cancelToken});
|
||
|
||
/// Fetch server-side reading progress for a list of entries.
|
||
///
|
||
/// Returns a map of entry ID → [EntryProgress]. Entries without progress
|
||
/// on the server are omitted from the result.
|
||
///
|
||
/// For OPDS servers, progress is extracted from [StreamLink.lastRead] which
|
||
/// is already present in the feed data. For servers with richer APIs (e.g.
|
||
/// Kavita), this can call dedicated progress endpoints.
|
||
Future<Map<String, EntryProgress>> fetchEntryProgress(
|
||
Server server,
|
||
List<Entry> entries,
|
||
);
|
||
|
||
/// Report page progress to the server (for reading tracking).
|
||
Future<void> reportPageProgress(
|
||
Server server, StreamLink streamLink, int page);
|
||
|
||
/// Report EPUB reading progress as a fractional percentage (0.0–1.0).
|
||
/// Default is a no-op — servers without rich progress APIs can ignore it.
|
||
Future<void> reportEpubProgress(
|
||
Server server,
|
||
Entry entry,
|
||
double progress,
|
||
) async {}
|
||
|
||
/// Mark an entry (volume/chapter) as fully read.
|
||
Future<void> markAsRead(Server server, Entry entry);
|
||
|
||
/// Mark an entry (volume/chapter) as unread.
|
||
Future<void> markAsUnread(Server server, Entry entry);
|
||
|
||
/// Download an EPUB file. Returns the local file.
|
||
/// If [savePath] is provided, writes directly to that path; otherwise uses a
|
||
/// temporary/cache location.
|
||
Future<File> downloadEpub(
|
||
Server server,
|
||
Entry entry, {
|
||
String? savePath,
|
||
void Function(double progress)? onProgress,
|
||
CancelToken? cancelToken,
|
||
});
|
||
|
||
/// Download all pages of an image stream chapter. Returns the directory path.
|
||
Future<String> downloadImageStreamChapter({
|
||
required Server server,
|
||
required StreamLink streamLink,
|
||
required String seriesId,
|
||
required String chapterId,
|
||
void Function(int downloaded, int total)? onProgress,
|
||
CancelToken? cancelToken,
|
||
});
|
||
|
||
/// Get HTTP auth headers for image/resource requests (CachedNetworkImage, etc).
|
||
Map<String, String> getAuthHeaders(Server server);
|
||
|
||
/// Clear any cached state for a server (tokens, HTTP clients, etc).
|
||
void clearCachedState(String serverId);
|
||
}
|