test: resolve error for `flutter test` after upgrade to riverpod3

This commit is contained in:
insleker 2025-12-15 11:55:19 +08:00
parent 0587e50360
commit d6bb64b3bc
19 changed files with 306 additions and 179 deletions

View File

@ -90,12 +90,17 @@ String _normalizeLanguageTag(String tag) {
}
class PreferencesStateNotifier extends Notifier<PreferencesState> {
late final SharedPreferences _prefs;
SharedPreferences? _prefs;
final Completer<void> _ready = Completer<void>();
@override
PreferencesState build() {
// Initialize with defaults
// If _prefs was already set by initWithPrefs (for testing), use it
if (_prefs != null) {
return _buildFromPrefs(_prefs!);
}
// Initialize with defaults for production
final defaultState = PreferencesState(
theme: 'system',
language: _normalizeLanguageTag(
@ -115,11 +120,24 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
_ready.complete();
}
// For testing - can be called with mock SharedPreferences
// For testing - can be called with mock SharedPreferences BEFORE build
void initWithPrefs(SharedPreferences prefs) {
_prefs = prefs;
_load();
_ready.complete();
}
PreferencesState _buildFromPrefs(SharedPreferences prefs) {
final loaded = PreferencesState(
theme: prefs.getString(_kTheme) ?? 'system',
language: _normalizeLanguageTag(
prefs.getString(_kLanguage) ??
WidgetsBinding.instance.platformDispatcher.locale.toLanguageTag(),
),
exportDpi: _readDpi(prefs),
theme_color: prefs.getString(_kThemeColor) ?? '#FF2196F3',
);
// Complete ready immediately for tests
if (!_ready.isCompleted) _ready.complete();
return loaded;
}
static Color? _tryParseColor(String? s) {
@ -193,15 +211,16 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
}
Future<void> _load() async {
if (_prefs == null) return;
// Load persisted values (with sane defaults)
final loaded = PreferencesState(
theme: _prefs.getString(_kTheme) ?? 'system',
theme: _prefs!.getString(_kTheme) ?? 'system',
language: _normalizeLanguageTag(
_prefs.getString(_kLanguage) ??
_prefs!.getString(_kLanguage) ??
WidgetsBinding.instance.platformDispatcher.locale.toLanguageTag(),
),
exportDpi: _readDpi(_prefs),
theme_color: _prefs.getString(_kThemeColor) ?? '#FF2196F3',
exportDpi: _readDpi(_prefs!),
theme_color: _prefs!.getString(_kThemeColor) ?? '#FF2196F3',
);
state = loaded;
_ensureValid();
@ -222,21 +241,22 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
}
void _ensureValid() {
if (_prefs == null) return;
final themeValid = {'light', 'dark', 'system'};
if (!themeValid.contains(state.theme)) {
state = state.copyWith(theme: 'system');
_prefs.setString(_kTheme, 'system');
_prefs!.setString(_kTheme, 'system');
}
final normalized = _normalizeLanguageTag(state.language);
if (normalized != state.language) {
state = state.copyWith(language: normalized);
_prefs.setString(_kLanguage, normalized);
_prefs!.setString(_kLanguage, normalized);
}
// Ensure DPI is one of allowed values
const allowed = [96.0, 144.0, 200.0, 300.0];
if (!allowed.contains(state.exportDpi)) {
state = state.copyWith(exportDpi: 144.0);
_prefs.setDouble(_kExportDpi, 144.0);
_prefs!.setDouble(_kExportDpi, 144.0);
}
// Ensure theme color is a valid hex or known name; normalize to hex
final parsed = _tryParseColor(state.theme_color);
@ -244,12 +264,12 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
final fallback = Colors.blue;
final hex = _toHex(fallback);
state = state.copyWith(theme_color: hex);
_prefs.setString(_kThemeColor, hex);
_prefs!.setString(_kThemeColor, hex);
} else {
final hex = _toHex(parsed);
if (state.theme_color != hex) {
state = state.copyWith(theme_color: hex);
_prefs.setString(_kThemeColor, hex);
_prefs!.setString(_kThemeColor, hex);
}
}
}
@ -259,14 +279,14 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
if (!valid.contains(theme)) return;
state = state.copyWith(theme: theme);
await _ensureReady();
await _prefs.setString(_kTheme, theme);
await _prefs!.setString(_kTheme, theme);
}
Future<void> setLanguage(String language) async {
final normalized = _normalizeLanguageTag(language);
state = state.copyWith(language: normalized);
await _ensureReady();
await _prefs.setString(_kLanguage, normalized);
await _prefs!.setString(_kLanguage, normalized);
}
Future<void> setThemeColor(String themeColor) async {
@ -275,7 +295,7 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
final hex = _toHex(c);
state = state.copyWith(theme_color: hex);
await _ensureReady();
await _prefs.setString(_kThemeColor, hex);
await _prefs!.setString(_kThemeColor, hex);
}
Future<void> resetToDefaults() async {
@ -289,11 +309,11 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
theme_color: '#FF2196F3',
);
await _ensureReady();
await _prefs.setString(_kTheme, 'system');
await _prefs.setString(_kLanguage, normalized);
await _prefs.setString(_kPageView, 'continuous');
await _prefs.setDouble(_kExportDpi, 144.0);
await _prefs.setString(_kThemeColor, '#FF2196F3');
await _prefs!.setString(_kTheme, 'system');
await _prefs!.setString(_kLanguage, normalized);
await _prefs!.setString(_kPageView, 'continuous');
await _prefs!.setDouble(_kExportDpi, 144.0);
await _prefs!.setString(_kThemeColor, '#FF2196F3');
}
Future<void> setExportDpi(double dpi) async {
@ -301,7 +321,7 @@ class PreferencesStateNotifier extends Notifier<PreferencesState> {
if (!allowed.contains(dpi)) return;
state = state.copyWith(exportDpi: dpi);
await _ensureReady();
await _prefs.setDouble(_kExportDpi, dpi);
await _prefs!.setDouble(_kExportDpi, dpi);
}
}

View File

@ -40,12 +40,12 @@ class PdfViewModel extends Notifier<PdfViewState> {
// Get current document source name for PdfDocumentRefData
String get documentSourceName {
// Ensure document version is up to date, but only update if really needed
_updateDocumentVersionIfNeeded();
// Return the current source name without updating state
// State updates should be done explicitly via updateDocumentVersionIfNeeded()
return state.documentVersion.sourceName;
}
void _updateDocumentVersionIfNeeded() {
void updateDocumentVersionIfNeeded() {
final document = ref.read(documentRepositoryProvider);
if (!identical(state.documentVersion.lastBytes, document.pickedPdfBytes)) {
state = state.copyWith(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:pdf_signature/ui/features/pdf/view_model/document_version.dart';
import 'package:pdfrx/pdfrx.dart';
@ -21,12 +22,12 @@ class PdfViewState {
});
factory PdfViewState.initial({bool? useMockViewer}) {
// Default to false (no mocking) - tests should explicitly pass true if they want mock viewer
final defaultUseMock = useMockViewer ?? false;
return PdfViewState(
controller: PdfViewerController(),
currentPage: 1,
useMockViewer:
useMockViewer ??
const bool.fromEnvironment('FLUTTER_TEST', defaultValue: false),
useMockViewer: defaultUseMock,
activeRect: null,
lockedPlacements: const {},
documentVersion: DocumentVersion.initial(),

View File

@ -52,6 +52,10 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
if (!identical(bytes, _lastBytes)) {
_lastBytes = bytes;
final viewModel = ref.read(pdfViewModelProvider.notifier);
// Update document version outside of build
Future.microtask(() {
viewModel.updateDocumentVersionIfNeeded();
});
debugPrint(
'[PdfViewerWidget] New PDF bytes detected -> ${viewModel.documentSourceName}',
);

View File

@ -118,9 +118,11 @@ class SignatureOverlay extends ConsumerWidget {
},
// Keep default handles; you can customize later if needed
contentBuilder: (context, boxRect, flip) {
final isLocked = ref
.read(pdfViewModelProvider.notifier)
.isPlacementLocked(page: pageNumber, index: placedIndex);
// Watch the provider state to rebuild when lock state changes
final pdfViewState = ref.watch(pdfViewModelProvider);
final isLocked = pdfViewState.lockedPlacements.contains(
'${pageNumber}_$placedIndex',
);
return DecoratedBox(
decoration: BoxDecoration(
border: Border.all(

View File

@ -34,6 +34,19 @@ class FakeExportService extends ExportService {
}
}
class _TestDocumentStateNotifier extends DocumentStateNotifier {
@override
Document build() {
// Initialize with sample document for tests, bypassing the parent build
return Document.initial().copyWith(
loaded: true,
pageCount: 5,
pickedPdfBytes: null,
placementsByPage: <int, List<SignaturePlacement>>{},
);
}
}
Future<ProviderContainer> pumpApp(
WidgetTester tester, {
Map<String, Object> initialPrefs = const {},
@ -42,18 +55,16 @@ Future<ProviderContainer> pumpApp(
final prefs = await SharedPreferences.getInstance();
final container = ProviderContainer(
overrides: [
preferencesRepositoryProvider.overrideWith(
(ref) => PreferencesStateNotifier(prefs),
),
preferencesRepositoryProvider.overrideWith(() {
final notifier = PreferencesStateNotifier();
notifier.initWithPrefs(prefs);
return notifier;
}),
documentRepositoryProvider.overrideWith(
(ref) => DocumentStateNotifier()..openSample(),
),
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
pdfExportViewModelProvider.overrideWith(
(ref) => PdfExportViewModel(ref, savePathPicker: () async => 'out.pdf'),
() => _TestDocumentStateNotifier(),
),
pdfViewModelProvider.overrideWith(() => PdfViewModel()),
pdfExportViewModelProvider.overrideWith(() => PdfExportViewModel()),
],
);
await tester.pumpWidget(

View File

@ -99,8 +99,9 @@ class MockSignatureState {
}) : strokes = strokes ?? [];
}
class MockSignatureNotifier extends StateNotifier<MockSignatureState> {
MockSignatureNotifier() : super(MockSignatureState());
class MockSignatureNotifier extends Notifier<MockSignatureState> {
@override
MockSignatureState build() => MockSignatureState();
void setStrokes(List<List<Offset>> strokes) {
state = MockSignatureState(
@ -174,11 +175,32 @@ class MockSignatureNotifier extends StateNotifier<MockSignatureState> {
}
final signatureProvider =
StateNotifierProvider<MockSignatureNotifier, MockSignatureState>(
(ref) => MockSignatureNotifier(),
NotifierProvider<MockSignatureNotifier, MockSignatureState>(
() => MockSignatureNotifier(),
);
// Mock other providers
final currentRectProvider = StateProvider<Rect?>((ref) => null);
final editingEnabledProvider = StateProvider<bool>((ref) => false);
final aspectLockedProvider = StateProvider<bool>((ref) => false);
// Mock other providers using NotifierProvider instead of StateProvider
class _CurrentRectNotifier extends Notifier<Rect?> {
@override
Rect? build() => null;
}
class _EditingEnabledNotifier extends Notifier<bool> {
@override
bool build() => false;
}
class _AspectLockedNotifier extends Notifier<bool> {
@override
bool build() => false;
}
final currentRectProvider = NotifierProvider<_CurrentRectNotifier, Rect?>(
() => _CurrentRectNotifier(),
);
final editingEnabledProvider = NotifierProvider<_EditingEnabledNotifier, bool>(
() => _EditingEnabledNotifier(),
);
final aspectLockedProvider = NotifierProvider<_AspectLockedNotifier, bool>(
() => _AspectLockedNotifier(),
);

View File

@ -9,8 +9,9 @@ Future<void> aSignaturePlacementAppearsOnThePageBasedOnTheSignatureCard(
) async {
final container = TestWorld.container!;
final pdf = container.read(documentRepositoryProvider);
final page = container.read(pdfViewModelProvider);
final placements = pdf.placementsByPage[page] ?? const [];
final pdfView = container.read(pdfViewModelProvider);
final currentPage = pdfView.currentPage;
final placements = pdf.placementsByPage[currentPage] ?? const [];
expect(
placements.isNotEmpty,
true,

View File

@ -10,7 +10,8 @@ Future<void> onlyTheSelectedSignaturePlacementIsRemoved(
) async {
final container = TestWorld.container ?? ProviderContainer();
final pdf = container.read(documentRepositoryProvider);
final page = container.read(pdfViewModelProvider);
final placements = pdf.placementsByPage[page] ?? const [];
final pdfView = container.read(pdfViewModelProvider);
final currentPage = pdfView.currentPage;
final placements = pdf.placementsByPage[currentPage] ?? const [];
expect(placements.length, 2); // Started with 3, removed 1, should have 2
}

View File

@ -32,38 +32,19 @@ Future<void> theAppLaunches(WidgetTester tester) async {
final container = ProviderContainer(
overrides: [
preferencesRepositoryProvider.overrideWith(
(ref) => PreferencesStateNotifier(prefs),
),
documentRepositoryProvider.overrideWith(
(ref) => DocumentStateNotifier()..openSample(),
),
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
preferencesRepositoryProvider.overrideWith(() {
final notifier = PreferencesStateNotifier();
notifier.initWithPrefs(prefs);
return notifier;
}),
documentRepositoryProvider.overrideWith(() => DocumentStateNotifier()),
pdfViewModelProvider.overrideWith(() => PdfViewModel()),
// Bridge: automatically mirror assets into signature cards so legacy
// feature steps that expect SignatureCard widgets keep working even
// though the production UI currently only stores raw assets.
signatureCardRepositoryProvider.overrideWith((ref) {
final notifier = _BridgedSignatureCardStateNotifier();
ref.listen<List<SignatureAsset>>(signatureAssetRepositoryProvider, (
prev,
next,
) {
for (final asset in next) {
if (!notifier.state.any((c) => identical(c.asset, asset))) {
notifier.add(SignatureCard(asset: asset, rotationDeg: 0.0));
}
}
// Remove cards whose assets were removed
final remaining =
notifier.state.where((c) => next.contains(c.asset)).toList();
if (remaining.length != notifier.state.length) {
notifier.setAll(remaining);
}
});
return notifier;
}),
signatureCardRepositoryProvider.overrideWith(
() => _BridgedSignatureCardStateNotifier(),
),
],
);
TestWorld.container = container;

View File

@ -9,7 +9,8 @@ Future<void> theOtherSignaturePlacementsRemainUnchanged(
) async {
final container = TestWorld.container!;
final pdf = container.read(documentRepositoryProvider);
final page = container.read(pdfViewModelProvider);
final placements = pdf.placementsByPage[page] ?? const [];
final pdfView = container.read(pdfViewModelProvider);
final currentPage = pdfView.currentPage;
final placements = pdf.placementsByPage[currentPage] ?? const [];
expect(placements.length, 2); // Should have 2 remaining after deleting 1
}

View File

@ -38,6 +38,6 @@ Future<void> theUserOpensADifferentDocumentWithPages(
}
}
// Moving to a new document should show page 1.
container.read(pdfViewModelProvider).currentPage = 1;
container.read(pdfViewModelProvider.notifier).jumpToPage(1);
await tester.pumpAndSettle();
}

View File

@ -13,14 +13,17 @@ import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
import 'package:pdf_signature/domain/models/model.dart';
// A fake export VM that always reports success, so this widget test doesn't
// depend on PDF validity or platform specifics.
bool exported = false;
class _FakePdfExportViewModel extends PdfExportViewModel {
_FakePdfExportViewModel(Ref ref)
: super(ref, savePathPicker: () async => 'C:/tmp/output.pdf');
@override
Future<String?> pickSavePathWithSuggestedName(String suggestedName) async {
return '/fake/path/output.pdf'; // Return a fake path
}
@override
Future<bool> exportToPath({
@ -34,6 +37,18 @@ class _FakePdfExportViewModel extends PdfExportViewModel {
}
}
class _TestDocumentStateNotifier extends DocumentStateNotifier {
@override
Document build() {
return Document.initial().copyWith(
loaded: true,
pageCount: 5,
pickedPdfBytes: Uint8List(0),
placementsByPage: <int, List<SignaturePlacement>>{},
);
}
}
void main() {
testWidgets('Save uses file selector (via provider) and injected exporter', (
tester,
@ -43,22 +58,17 @@ void main() {
await tester.pumpWidget(
ProviderScope(
overrides: [
preferencesRepositoryProvider.overrideWith(
(ref) => PreferencesStateNotifier(prefs),
),
preferencesRepositoryProvider.overrideWith(() {
final notifier = PreferencesStateNotifier();
notifier.initWithPrefs(prefs);
return notifier;
}),
documentRepositoryProvider.overrideWith(
(ref) =>
DocumentStateNotifier()..openDocument(
bytes: Uint8List(0),
pageCount: 5,
knownPageCount: true,
),
),
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
() => _TestDocumentStateNotifier(),
),
pdfViewModelProvider.overrideWith(() => PdfViewModel()),
pdfExportViewModelProvider.overrideWith(
(ref) => _FakePdfExportViewModel(ref),
() => _FakePdfExportViewModel(),
),
],
child: MaterialApp(

View File

@ -7,28 +7,102 @@ import 'package:image/image.dart' as img;
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_export_view_model.dart';
import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
import 'package:pdf_signature/data/repositories/signature_card_repository.dart';
import 'package:pdf_signature/domain/models/signature_asset.dart';
import 'package:pdf_signature/domain/models/model.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
// preferences_providers.dart no longer exports pageViewModeProvider
// Test helper classes
class TestPdfViewModel extends PdfViewModel {
@override
PdfViewState build() {
return PdfViewState.initial(useMockViewer: true);
}
}
class TestDocumentStateNotifier extends DocumentStateNotifier {
@override
Document build() {
// Initialize with sample document for tests, bypassing the parent build
return Document.initial().copyWith(
loaded: true,
pageCount: 5,
pickedPdfBytes: null,
placementsByPage: <int, List<SignaturePlacement>>{},
);
}
}
class TestDocumentStateNotifierWithPlacements extends DocumentStateNotifier {
final Uint8List pdfBytes;
final List<int> signatureBytes;
TestDocumentStateNotifierWithPlacements(this.pdfBytes, this.signatureBytes);
@override
Document build() {
final image = img.decodeImage(Uint8List.fromList(signatureBytes))!;
final asset = SignatureAsset(sigImage: image);
return Document.initial().copyWith(
loaded: true,
pageCount: 5,
pickedPdfBytes: pdfBytes,
placementsByPage: {
1: [
SignaturePlacement(
rect: const Rect.fromLTWH(0.1, 0.1, 0.3, 0.2),
asset: asset,
),
],
},
);
}
}
// Test notifier for SignatureCardRepository with pre-initialized card
class TestSignatureCardStateNotifier extends SignatureCardStateNotifier {
final List<int> signatureBytes;
TestSignatureCardStateNotifier(this.signatureBytes);
@override
List<SignatureCard> build() {
// Initialize with a card already added
final image = img.decodeImage(Uint8List.fromList(signatureBytes))!;
final asset = SignatureAsset(sigImage: image, name: 'test');
return [SignatureCard(asset: asset, rotationDeg: 0.0)];
}
}
// Test notifier for SignatureAssetRepository with pre-loaded asset
class TestSignatureAssetRepository extends SignatureAssetRepository {
final List<int> signatureBytes;
TestSignatureAssetRepository(this.signatureBytes);
@override
List<SignatureAsset> build() {
// Initialize with an asset already added
final image = img.decodeImage(Uint8List.fromList(signatureBytes))!;
return [SignatureAsset(sigImage: image, name: 'test')];
}
}
Future<void> pumpWithOpenPdf(WidgetTester tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
documentRepositoryProvider.overrideWith(
(ref) => DocumentStateNotifier()..openSample(),
),
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
pdfExportViewModelProvider.overrideWith(
(ref) => PdfExportViewModel(ref),
() => TestDocumentStateNotifier(),
),
pdfViewModelProvider.overrideWith(() => TestPdfViewModel()),
pdfExportViewModelProvider.overrideWith(() => PdfExportViewModel()),
],
child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
@ -370,42 +444,18 @@ Future<void> pumpWithOpenPdfAndSig(WidgetTester tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
documentRepositoryProvider.overrideWith((ref) {
final notifier = DocumentStateNotifier()..openSample();
// Set PDF bytes so the viewer can display something
notifier.state = notifier.state.copyWith(pickedPdfBytes: pdfBytes);
// Add a signature placement on page 1
notifier.addPlacement(
page: 1,
rect: const Rect.fromLTWH(0.1, 0.1, 0.3, 0.2),
asset: SignatureAsset(
sigImage: img.decodeImage(Uint8List.fromList(bytes))!,
),
);
return notifier;
}),
signatureAssetRepositoryProvider.overrideWith((ref) {
final repo = SignatureAssetRepository();
final image = img.decodeImage(Uint8List.fromList(bytes))!;
repo.addImage(image, name: 'test');
return repo;
}),
signatureCardRepositoryProvider.overrideWith((ref) {
final cardRepo = SignatureCardStateNotifier();
final asset = SignatureAsset(
sigImage: img.decodeImage(Uint8List.fromList(bytes))!,
name: 'test',
);
cardRepo.addWithAsset(asset, 0.0);
return cardRepo;
}),
documentRepositoryProvider.overrideWith(
() => TestDocumentStateNotifierWithPlacements(pdfBytes, bytes),
),
signatureAssetRepositoryProvider.overrideWith(
() => TestSignatureAssetRepository(bytes),
),
signatureCardRepositoryProvider.overrideWith(
() => TestSignatureCardStateNotifier(bytes),
),
// In new model, interactive overlay not implemented; keep library empty
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
pdfExportViewModelProvider.overrideWith(
(ref) => PdfExportViewModel(ref),
),
pdfViewModelProvider.overrideWith(() => TestPdfViewModel()),
pdfExportViewModelProvider.overrideWith(() => PdfExportViewModel()),
],
child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@ -5,15 +5,24 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart';
import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/domain/models/model.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
class _TestPdfController extends DocumentStateNotifier {
_TestPdfController() : super() {
@override
Document build() {
// Start with a loaded multi-page doc, page 1 of 5
state = Document.initial().copyWith(loaded: true, pageCount: 5);
return Document.initial().copyWith(loaded: true, pageCount: 5);
}
}
class _TestPdfViewModel extends PdfViewModel {
@override
PdfViewState build() {
return PdfViewState.initial(useMockViewer: true);
}
}
@ -24,12 +33,8 @@ void main() {
await tester.pumpWidget(
ProviderScope(
overrides: [
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
documentRepositoryProvider.overrideWith(
(ref) => _TestPdfController(),
),
pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()),
documentRepositoryProvider.overrideWith(() => _TestPdfController()),
],
child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@ -7,13 +7,22 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart';
import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
import 'package:pdf_signature/domain/models/model.dart';
class _TestPdfController extends DocumentStateNotifier {
_TestPdfController() : super() {
state = Document.initial().copyWith(loaded: true, pageCount: 6);
@override
Document build() {
return Document.initial().copyWith(loaded: true, pageCount: 6);
}
}
class _TestPdfViewModel extends PdfViewModel {
@override
PdfViewState build() {
return PdfViewState.initial(useMockViewer: true);
}
}
@ -26,10 +35,8 @@ void main() {
await tester.pumpWidget(
ProviderScope(
overrides: [
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
documentRepositoryProvider.overrideWith((ref) => ctrl),
pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()),
documentRepositoryProvider.overrideWith(() => ctrl),
],
child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@ -7,13 +7,22 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart';
import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
import 'package:pdf_signature/domain/models/model.dart';
class _TestPdfController extends DocumentStateNotifier {
_TestPdfController() : super() {
state = Document.initial().copyWith(loaded: true, pageCount: 6);
@override
Document build() {
return Document.initial().copyWith(loaded: true, pageCount: 6);
}
}
class _TestPdfViewModel extends PdfViewModel {
@override
PdfViewState build() {
return PdfViewState.initial(useMockViewer: true);
}
}
@ -26,11 +35,9 @@ void main() {
await tester.pumpWidget(
ProviderScope(
overrides: [
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()),
// Continuous mode is always-on; no page view override needed
documentRepositoryProvider.overrideWith((ref) => ctrl),
documentRepositoryProvider.overrideWith(() => ctrl),
],
child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@ -7,14 +7,24 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart';
import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_state.dart';
import 'package:pdfrx/pdfrx.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
import 'package:pdf_signature/domain/models/model.dart';
import 'helpers.dart';
class _TestPdfController extends DocumentStateNotifier {
_TestPdfController() : super() {
state = Document.initial().copyWith(loaded: true, pageCount: 6);
@override
Document build() {
return Document.initial().copyWith(loaded: true, pageCount: 6);
}
}
class _TestPdfViewModel extends PdfViewModel {
@override
PdfViewState build() {
return PdfViewState.initial(useMockViewer: true);
}
}
@ -25,12 +35,8 @@ void main() {
await tester.pumpWidget(
ProviderScope(
overrides: [
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
documentRepositoryProvider.overrideWith(
(ref) => _TestPdfController(),
),
pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()),
documentRepositoryProvider.overrideWith(() => _TestPdfController()),
],
child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
@ -65,11 +71,9 @@ void main() {
// Use a persistent container across rebuilds
final container = ProviderContainer(
overrides: [
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
),
pdfViewModelProvider.overrideWith(() => _TestPdfViewModel()),
documentRepositoryProvider.overrideWith(
(ref) => DocumentStateNotifier()..openSample(),
() => TestDocumentStateNotifier(),
),
],
);

View File

@ -12,6 +12,8 @@ import 'package:pdf_signature/data/repositories/document_repository.dart';
import 'package:pdf_signature/domain/models/model.dart';
import 'package:pdf_signature/l10n/app_localizations.dart';
import 'helpers.dart';
void main() {
late ProviderContainer container;
late SignatureAsset testAsset;
@ -37,11 +39,9 @@ void main() {
container = ProviderContainer(
overrides: [
documentRepositoryProvider.overrideWith(
(ref) => DocumentStateNotifier()..openSample(),
),
pdfViewModelProvider.overrideWith(
(ref) => PdfViewModel(ref, useMockViewer: true),
() => TestDocumentStateNotifier(),
),
pdfViewModelProvider.overrideWith(() => PdfViewModel()),
],
);
});