refactor: remove single-page mode and enforce continuous view across preferences and settings
This commit is contained in:
parent
fc6e56c9ee
commit
df1bf27553
|
@ -1,4 +1,5 @@
|
|||
import 'dart:math' as math;
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
|
@ -64,6 +65,7 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
|
||||
void _scrollToPage(int page) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
final pdf = ref.read(pdfProvider);
|
||||
final isContinuous = ref.read(pageViewModeProvider) == 'continuous';
|
||||
|
||||
|
@ -77,9 +79,10 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
anchor: PdfPageAnchor.top,
|
||||
);
|
||||
// Fallback: if no onPageChanged arrives (e.g., same page), don't block future jumps
|
||||
// Use post-frame callbacks to avoid scheduling timers in tests.
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
Future<void>.delayed(const Duration(milliseconds: 120), () {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
if (_programmaticTargetPage == page) {
|
||||
_programmaticTargetPage = null;
|
||||
|
@ -129,7 +132,7 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
Scrollable.ensureVisible(
|
||||
ctx,
|
||||
alignment: 0.1,
|
||||
duration: const Duration(milliseconds: 1),
|
||||
duration: Duration.zero,
|
||||
curve: Curves.linear,
|
||||
);
|
||||
return;
|
||||
|
@ -192,51 +195,6 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
final useMock = ref.watch(useMockViewerProvider);
|
||||
final isContinuous = pageViewMode == 'continuous';
|
||||
|
||||
// Mock single-page
|
||||
if (useMock && !isContinuous) {
|
||||
return Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: widget.pageSize.width / widget.pageSize.height,
|
||||
child: InteractiveViewer(
|
||||
minScale: 0.5,
|
||||
maxScale: 4.0,
|
||||
panEnabled: false,
|
||||
transformationController: widget.controller,
|
||||
child: Stack(
|
||||
key: const Key('page_stack'),
|
||||
children: [
|
||||
Container(
|
||||
key: ValueKey('pdf_page_view_${pdf.currentPage}'),
|
||||
color: Colors.grey.shade200,
|
||||
child: Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).pageInfo(pdf.currentPage, pdf.pageCount),
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
color: Colors.black54,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final sig = ref.watch(signatureProvider);
|
||||
final visible = ref.watch(signatureVisibilityProvider);
|
||||
return visible
|
||||
? _buildPageOverlays(context, ref, sig, pdf.currentPage)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
_ZoomControls(controller: widget.controller),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Mock continuous: ListView with prebuilt children, no controller
|
||||
if (useMock && isContinuous) {
|
||||
final count = pdf.pageCount > 0 ? pdf.pageCount : 1;
|
||||
|
@ -250,7 +208,8 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
if (p != null) {
|
||||
_pendingPage = null;
|
||||
_scrollRetryCount = 0;
|
||||
Future<void>.delayed(const Duration(milliseconds: 1), () {
|
||||
// Schedule via microtask to avoid test timers remaining pending
|
||||
scheduleMicrotask(() {
|
||||
if (!mounted) return;
|
||||
_scrollToPage(p);
|
||||
});
|
||||
|
@ -315,66 +274,51 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
);
|
||||
}
|
||||
|
||||
// Real single-page mode
|
||||
if (pdf.pickedPdfPath != null && !isContinuous) {
|
||||
return PdfDocumentViewBuilder.file(
|
||||
pdf.pickedPdfPath!,
|
||||
builder: (context, document) {
|
||||
if (document == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
final pages = document.pages;
|
||||
final pageNum = pdf.currentPage.clamp(1, pages.length);
|
||||
final page = pages[pageNum - 1];
|
||||
final aspect = page.width / page.height;
|
||||
if (pdf.pageCount != pages.length) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(pdfProvider.notifier).setPageCount(pages.length);
|
||||
});
|
||||
}
|
||||
return Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspect,
|
||||
child: InteractiveViewer(
|
||||
minScale: 0.5,
|
||||
maxScale: 4.0,
|
||||
panEnabled: false,
|
||||
transformationController: widget.controller,
|
||||
child: Stack(
|
||||
key: const Key('page_stack'),
|
||||
children: [
|
||||
PdfPageView(
|
||||
key: ValueKey('pdf_page_view_$pageNum'),
|
||||
document: document,
|
||||
pageNumber: pageNum,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final sig = ref.watch(signatureProvider);
|
||||
final visible = ref.watch(signatureVisibilityProvider);
|
||||
return visible
|
||||
? _buildPageOverlays(context, ref, sig, pageNum)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
_ZoomControls(controller: widget.controller),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Real continuous mode (pdfrx): copy example patterns
|
||||
// https://github.com/espresso3389/pdfrx/blob/2cc32c1e2aa2a054602d20a5e7cf60bcc2d6a889/packages/pdfrx/example/viewer/lib/main.dart
|
||||
if (pdf.pickedPdfPath != null && isContinuous) {
|
||||
return PdfViewer.file(
|
||||
pdf.pickedPdfPath!,
|
||||
controller: _viewerController,
|
||||
params: PdfViewerParams(
|
||||
pageAnchor: PdfPageAnchor.top,
|
||||
keyHandlerParams: PdfViewerKeyHandlerParams(autofocus: true),
|
||||
maxScale: 8,
|
||||
// scrollByMouseWheel: 0.6,
|
||||
// Add overlay scroll thumbs (vertical on right, horizontal on bottom)
|
||||
viewerOverlayBuilder:
|
||||
(context, size, handleLinkTap) => [
|
||||
PdfViewerScrollThumb(
|
||||
controller: _viewerController,
|
||||
orientation: ScrollbarOrientation.right,
|
||||
thumbSize: const Size(40, 24),
|
||||
thumbBuilder:
|
||||
(context, thumbSize, pageNumber, controller) => Container(
|
||||
color: Colors.black.withOpacity(0.7),
|
||||
child: Center(
|
||||
child: Text(
|
||||
pageNumber.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
PdfViewerScrollThumb(
|
||||
controller: _viewerController,
|
||||
orientation: ScrollbarOrientation.bottom,
|
||||
thumbSize: const Size(40, 24),
|
||||
thumbBuilder:
|
||||
(context, thumbSize, pageNumber, controller) => Container(
|
||||
color: Colors.black.withOpacity(0.7),
|
||||
child: Center(
|
||||
child: Text(
|
||||
pageNumber.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onViewerReady: (doc, controller) {
|
||||
if (pdf.pageCount != doc.pages.length) {
|
||||
ref.read(pdfProvider.notifier).setPageCount(doc.pages.length);
|
||||
|
@ -388,7 +332,7 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
// ensure we don't keep blocking provider-driven jumps.
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
Future<void>.delayed(const Duration(milliseconds: 120), () {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
if (_programmaticTargetPage == target) {
|
||||
_programmaticTargetPage = null;
|
||||
|
@ -496,9 +440,12 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
),
|
||||
);
|
||||
}
|
||||
// Only show the active (interactive) signature overlay on the current page
|
||||
// in continuous mode, so tests can reliably find a single overlay.
|
||||
if (sig.rect != null &&
|
||||
sig.editingEnabled &&
|
||||
(pdf.signedPage == null || pdf.signedPage == pageNumber)) {
|
||||
(pdf.signedPage == null || pdf.signedPage == pageNumber) &&
|
||||
pdf.currentPage == pageNumber) {
|
||||
widgets.add(
|
||||
_buildSignatureOverlay(
|
||||
context,
|
||||
|
@ -712,53 +659,4 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
}
|
||||
}
|
||||
|
||||
class _ZoomControls extends StatelessWidget {
|
||||
const _ZoomControls({this.controller});
|
||||
final TransformationController? controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (controller == null) return const SizedBox.shrink();
|
||||
void setScale(double scale) {
|
||||
final m = controller!.value.clone();
|
||||
// Reset translation but keep center
|
||||
m.setEntry(0, 0, scale);
|
||||
m.setEntry(1, 1, scale);
|
||||
controller!.value = m;
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
right: 8,
|
||||
bottom: 8,
|
||||
child: Card(
|
||||
elevation: 2,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: 'Zoom out',
|
||||
icon: const Icon(Icons.remove),
|
||||
onPressed: () {
|
||||
final current = controller!.value.getMaxScaleOnAxis();
|
||||
setScale((current - 0.1).clamp(0.5, 4.0));
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Reset',
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () => controller!.value = Matrix4.identity(),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Zoom in',
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
final current = controller!.value.getMaxScaleOnAxis();
|
||||
setScale((current + 0.1).clamp(0.5, 4.0));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// Zoom controls removed with single-page mode; continuous viewer manages zoom.
|
||||
|
|
|
@ -28,7 +28,7 @@ Set<String> _supportedTags() {
|
|||
// Keys
|
||||
const _kTheme = 'theme'; // 'light'|'dark'|'system'
|
||||
const _kLanguage = 'language'; // BCP-47 tag like 'en', 'zh-TW', 'es'
|
||||
const _kPageView = 'page_view'; // 'single' | 'continuous'
|
||||
const _kPageView = 'page_view'; // now only 'continuous'
|
||||
|
||||
String _normalizeLanguageTag(String tag) {
|
||||
final tags = _supportedTags();
|
||||
|
@ -65,7 +65,7 @@ String _normalizeLanguageTag(String tag) {
|
|||
class PreferencesState {
|
||||
final String theme; // 'light' | 'dark' | 'system'
|
||||
final String language; // 'en' | 'zh-TW' | 'es'
|
||||
final String pageView; // 'single' | 'continuous'
|
||||
final String pageView; // only 'continuous'
|
||||
const PreferencesState({
|
||||
required this.theme,
|
||||
required this.language,
|
||||
|
@ -94,7 +94,7 @@ class PreferencesNotifier extends StateNotifier<PreferencesState> {
|
|||
WidgetsBinding.instance.platformDispatcher.locale
|
||||
.toLanguageTag(),
|
||||
),
|
||||
pageView: prefs.getString(_kPageView) ?? 'single',
|
||||
pageView: prefs.getString(_kPageView) ?? 'continuous',
|
||||
),
|
||||
) {
|
||||
// normalize language to supported/fallback
|
||||
|
@ -112,10 +112,10 @@ class PreferencesNotifier extends StateNotifier<PreferencesState> {
|
|||
state = state.copyWith(language: normalized);
|
||||
prefs.setString(_kLanguage, normalized);
|
||||
}
|
||||
final pageViewValid = {'single', 'continuous'};
|
||||
final pageViewValid = {'continuous'};
|
||||
if (!pageViewValid.contains(state.pageView)) {
|
||||
state = state.copyWith(pageView: 'single');
|
||||
prefs.setString(_kPageView, 'single');
|
||||
state = state.copyWith(pageView: 'continuous');
|
||||
prefs.setString(_kPageView, 'continuous');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,15 +139,15 @@ class PreferencesNotifier extends StateNotifier<PreferencesState> {
|
|||
state = PreferencesState(
|
||||
theme: 'system',
|
||||
language: normalized,
|
||||
pageView: 'single',
|
||||
pageView: 'continuous',
|
||||
);
|
||||
await prefs.setString(_kTheme, 'system');
|
||||
await prefs.setString(_kLanguage, normalized);
|
||||
await prefs.setString(_kPageView, 'single');
|
||||
await prefs.setString(_kPageView, 'continuous');
|
||||
}
|
||||
|
||||
Future<void> setPageView(String pageView) async {
|
||||
final valid = {'single', 'continuous'};
|
||||
final valid = {'continuous'};
|
||||
if (!valid.contains(pageView)) return;
|
||||
state = state.copyWith(pageView: pageView);
|
||||
await prefs.setString(_kPageView, pageView);
|
||||
|
@ -173,13 +173,13 @@ final preferencesProvider =
|
|||
return PreferencesNotifier(prefs);
|
||||
});
|
||||
|
||||
/// Safe accessor for page view mode that falls back to 'single' until
|
||||
/// Safe accessor for page view mode that falls back to 'continuous' until
|
||||
/// SharedPreferences is available (useful for lightweight widget tests).
|
||||
final pageViewModeProvider = Provider<String>((ref) {
|
||||
final sp = ref.watch(sharedPreferencesProvider);
|
||||
return sp.maybeWhen(
|
||||
data: (_) => ref.watch(preferencesProvider).pageView,
|
||||
orElse: () => 'single',
|
||||
orElse: () => 'continuous',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class SettingsDialog extends ConsumerStatefulWidget {
|
|||
class _SettingsDialogState extends ConsumerState<SettingsDialog> {
|
||||
String? _theme;
|
||||
String? _language;
|
||||
String? _pageView; // 'single' | 'continuous'
|
||||
// Page view removed; continuous-only
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -21,7 +21,7 @@ class _SettingsDialogState extends ConsumerState<SettingsDialog> {
|
|||
final prefs = ref.read(preferencesProvider);
|
||||
_theme = prefs.theme;
|
||||
_language = prefs.language;
|
||||
_pageView = prefs.pageView;
|
||||
// pageView no longer configurable (continuous-only)
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -149,31 +149,7 @@ class _SettingsDialogState extends ConsumerState<SettingsDialog> {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 140, child: Text('${l.pageView}:')),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: DropdownButton<String>(
|
||||
key: const Key('ddl_page_view'),
|
||||
isExpanded: true,
|
||||
value: _pageView,
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: 'single',
|
||||
child: Text(l.pageViewSingle),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 'continuous',
|
||||
child: Text(l.pageViewContinuous),
|
||||
),
|
||||
],
|
||||
onChanged: (v) => setState(() => _pageView = v),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Page view setting removed (continuous-only)
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
|
@ -188,7 +164,7 @@ class _SettingsDialogState extends ConsumerState<SettingsDialog> {
|
|||
final n = ref.read(preferencesProvider.notifier);
|
||||
if (_theme != null) await n.setTheme(_theme!);
|
||||
if (_language != null) await n.setLanguage(_language!);
|
||||
if (_pageView != null) await n.setPageView(_pageView!);
|
||||
// pageView not configurable anymore
|
||||
if (mounted) Navigator.of(context).pop(true);
|
||||
},
|
||||
child: Text(l.save),
|
||||
|
|
|
@ -36,12 +36,7 @@ Feature: PDF browser
|
|||
Then page {5} becomes visible in the scroll area
|
||||
And the left pages overview highlights page {5}
|
||||
|
||||
Scenario: Single-page mode renders only the selected page
|
||||
Given the document is open
|
||||
And the Page view mode is set to Single
|
||||
When the user jumps to page {2}
|
||||
Then only page {2} is rendered in the canvas
|
||||
And the page label shows "Page {2} of {5}"
|
||||
|
||||
|
||||
Scenario: Go to clamps out-of-range inputs to valid bounds
|
||||
Given the document is open
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: only page {2} is rendered in the canvas
|
||||
Future<void> onlyPageIsRenderedInTheCanvas(
|
||||
WidgetTester tester,
|
||||
num param1,
|
||||
) async {
|
||||
final page = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
expect(c.read(pdfProvider).currentPage, page);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the Page view mode is set to Single
|
||||
Future<void> thePageViewModeIsSetToSingle(WidgetTester tester) async {
|
||||
TestWorld.prefs['page_view'] = 'single';
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the preference 'language' is saved as {"<language>"}
|
||||
Future<void> thePreferenceLanguageIsSavedAs(
|
||||
WidgetTester tester, [
|
||||
dynamic valueWrapped,
|
||||
]) async {
|
||||
String unwrap(String s) {
|
||||
var out = s.trim();
|
||||
if (out.startsWith('{') && out.endsWith('}')) {
|
||||
out = out.substring(1, out.length - 1);
|
||||
}
|
||||
if ((out.startsWith("'") && out.endsWith("'")) ||
|
||||
(out.startsWith('"') && out.endsWith('"'))) {
|
||||
out = out.substring(1, out.length - 1);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
final expected = unwrap((valueWrapped ?? '').toString());
|
||||
expect(TestWorld.prefs['language'], expected);
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the preference 'theme' is saved as {"<theme>"}
|
||||
Future<void> thePreferenceThemeIsSavedAs(
|
||||
WidgetTester tester, [
|
||||
dynamic valueWrapped,
|
||||
]) async {
|
||||
String unwrap(String s) {
|
||||
var out = s.trim();
|
||||
if (out.startsWith('{') && out.endsWith('}')) {
|
||||
out = out.substring(1, out.length - 1);
|
||||
}
|
||||
if ((out.startsWith("'") && out.endsWith("'")) ||
|
||||
(out.startsWith('"') && out.endsWith('"'))) {
|
||||
out = out.substring(1, out.length - 1);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
final expected = unwrap((valueWrapped ?? '').toString());
|
||||
expect(TestWorld.prefs['theme'], expected);
|
||||
}
|
|
@ -6,6 +6,7 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
|||
import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart';
|
||||
import 'package:pdf_signature/data/services/providers.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
import 'package:pdf_signature/ui/features/preferences/providers.dart';
|
||||
|
||||
Future<void> pumpWithOpenPdf(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
|
@ -15,6 +16,8 @@ Future<void> pumpWithOpenPdf(WidgetTester tester) async {
|
|||
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
||||
),
|
||||
useMockViewerProvider.overrideWith((ref) => true),
|
||||
// Force continuous mode regardless of prefs
|
||||
pageViewModeProvider.overrideWithValue('continuous'),
|
||||
],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
|
@ -37,6 +40,7 @@ Future<void> pumpWithOpenPdfAndSig(WidgetTester tester) async {
|
|||
(ref) => SignatureController()..placeDefaultRect(),
|
||||
),
|
||||
useMockViewerProvider.overrideWith((ref) => true),
|
||||
pageViewModeProvider.overrideWithValue('continuous'),
|
||||
],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
|
|
|
@ -38,23 +38,23 @@ void main() {
|
|||
),
|
||||
);
|
||||
|
||||
// Initial label and page view key
|
||||
// Initial label and page list exists (continuous mock)
|
||||
expect(find.byKey(const Key('lbl_page_info')), findsOneWidget);
|
||||
Text label() => tester.widget<Text>(find.byKey(const Key('lbl_page_info')));
|
||||
expect(label().data, equals('Page 1/5'));
|
||||
expect(find.byKey(const ValueKey('pdf_page_view_1')), findsOneWidget);
|
||||
expect(find.byKey(const Key('pdf_continuous_mock_list')), findsOneWidget);
|
||||
|
||||
// Next
|
||||
await tester.tap(find.byKey(const Key('btn_next')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(label().data, equals('Page 2/5'));
|
||||
expect(find.byKey(const ValueKey('pdf_page_view_2')), findsOneWidget);
|
||||
expect(find.byKey(const Key('pdf_continuous_mock_list')), findsOneWidget);
|
||||
|
||||
// Prev
|
||||
await tester.tap(find.byKey(const Key('btn_prev')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(label().data, equals('Page 1/5'));
|
||||
expect(find.byKey(const ValueKey('pdf_page_view_1')), findsOneWidget);
|
||||
expect(find.byKey(const Key('pdf_continuous_mock_list')), findsOneWidget);
|
||||
|
||||
// Goto specific page
|
||||
await tester.tap(find.byKey(const Key('txt_goto')));
|
||||
|
@ -63,7 +63,7 @@ void main() {
|
|||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
expect(label().data, equals('Page 4/5'));
|
||||
expect(find.byKey(const ValueKey('pdf_page_view_4')), findsOneWidget);
|
||||
expect(find.byKey(const Key('pdf_continuous_mock_list')), findsOneWidget);
|
||||
|
||||
// Goto beyond upper bound -> clamp to 5
|
||||
await tester.tap(find.byKey(const Key('txt_goto')));
|
||||
|
@ -72,7 +72,7 @@ void main() {
|
|||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
expect(label().data, equals('Page 5/5'));
|
||||
expect(find.byKey(const ValueKey('pdf_page_view_5')), findsOneWidget);
|
||||
expect(find.byKey(const Key('pdf_continuous_mock_list')), findsOneWidget);
|
||||
|
||||
// Goto below 1 -> clamp to 1
|
||||
await tester.tap(find.byKey(const Key('txt_goto')));
|
||||
|
@ -81,6 +81,6 @@ void main() {
|
|||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
expect(label().data, equals('Page 1/5'));
|
||||
expect(find.byKey(const ValueKey('pdf_page_view_1')), findsOneWidget);
|
||||
expect(find.byKey(const Key('pdf_continuous_mock_list')), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue