Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/src/engine/epub/epub_reader_engine.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:math' as math;

import 'package:flutter/widgets.dart';

Expand Down Expand Up @@ -356,7 +357,10 @@ final class EpubReaderEngine extends ReaderEngine {
await _goTo(
_locatorFor(
position.chapter,
local: progress == 1 ? 1 : 0,
local: progress == 1
? 1
: position.offset /
math.max(1, _progressIndex!.lengths[position.chapter]),
textOffset: position.offset,
),
seek: seek,
Expand Down
24 changes: 21 additions & 3 deletions lib/src/engine/epub/epub_viewport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,11 @@ final class _EpubViewportState extends State<EpubViewport> {
return true;
}

void _publishPage(int index, {int? restoredOffset}) {
void _publishPage(
int index, {
int? restoredOffset,
bool schedulePrefetch = true,
}) {
if (_restoring || _busy || _pages.isEmpty) {
return;
}
Expand Down Expand Up @@ -558,7 +562,9 @@ final class _EpubViewportState extends State<EpubViewport> {
coverageEnd: coverageEnd,
atEnd: complete && after == _pages.length,
);
_schedulePrefetch();
if (schedulePrefetch) {
_schedulePrefetch();
}
}

void _scrollChanged() {
Expand Down Expand Up @@ -835,7 +841,19 @@ final class _EpubViewportState extends State<EpubViewport> {
wasComplete != current.complete) {
setState(() {});
}
_publishPageCount(current);
if (!wasComplete &&
current.complete &&
widget.engine.preferences.layoutMode ==
ReaderLayoutMode.paginated) {
_publishPage(
_pageIndex,
restoredOffset: widget.engine.locator.textOffset,
schedulePrefetch: false,
);
} else {
_publishPageCount(current);
}

_warmImages(
current.pages,
(_pageIndex - _spreadsBehind) * _columns,
Expand Down
46 changes: 45 additions & 1 deletion test/engine/epub_content_renderer_test.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:papyrus_reader/papyrus_reader.dart';

import '../support/in_process_epub_worker.dart';
import '../support/synthetic_epub.dart';

void main() {
testWidgets('progress seeks restore the custom renderer within a chapter', (
tester,
) async {
final renderer = _TrackingRenderer();
final engine = EpubReaderEngine(
renderer: renderer,
workerFactory: () async => InProcessEpubWorker(),
);
addTearDown(engine.dispose);
await engine.load(
ReaderDocument(
id: 'custom-scroll',
format: ReaderFormat.epub,
loadBytes: () async => syntheticEpub(
singleSpine: true,
firstChapterBody:
'<p>${List.filled(200, "Scrollable text").join(" ")}</p>',
),
),
preferences: const ReaderPreferences(layoutMode: ReaderLayoutMode.scroll),
);
await tester.pumpWidget(
MaterialApp(
home: ListenableBuilder(
listenable: engine,
builder: (context, _) => engine.buildViewport(context),
),
),
);
await tester.pumpAndSettle();
for (final progress in [.25, .75, 1.0]) {
await pumpReaderCommand(tester, engine.goToProgress(progress));
expect(
renderer.controller.offset /
renderer.controller.position.maxScrollExtent,
closeTo(progress, .01),
);
expect(engine.locator.totalProgression, closeTo(progress, .01));
}
});

testWidgets('programmatic restoration does not publish progress', (
tester,
) async {
Expand Down
27 changes: 27 additions & 0 deletions test/presentation/epub_prefetch_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ import '../support/in_process_epub_worker.dart';
import '../support/synthetic_epub.dart';

void main() {
testWidgets(
'prefetch reports completion when the entire book fits on one page',
(tester) async {
final engine = testEpubEngine();
await engine.load(
ReaderDocument(
id: 'one-page',
format: ReaderFormat.epub,
loadBytes: () async => syntheticEpub(
singleSpine: true,
firstChapterBody: '<p>A complete short book.</p>',
),
),
preferences: const ReaderPreferences(pageTurnAnimation: false),
);
await tester.pumpWidget(
MaterialApp(home: Builder(builder: engine.buildViewport)),
);
await tester.pumpAndSettle();
expect(engine.snapshot.contentReady, isTrue);
expect(engine.snapshot.atEnd, isTrue);
expect(engine.locator.totalProgression, 1);
expect(engine.snapshot.coverage.single.end, 1);
expect(engine.locator.textOffset, 0);
},
);

testWidgets(
'an immediate turn can use a page prepared before the viewport grows',
(tester) async {
Expand Down
Loading