diff --git a/lib/data/model/model.dart b/lib/data/model/model.dart index 4faeeba..0f2cbc5 100644 --- a/lib/data/model/model.dart +++ b/lib/data/model/model.dart @@ -10,6 +10,8 @@ class PdfState { final int? signedPage; // Multiple signature placements per page, stored as UI-space rects (e.g., 400x560) final Map> placementsByPage; + // For each placement, store the assigned image identifier (e.g., filename) in the same index order. + final Map> placementImageByPage; // UI state: selected placement index on the current page (if any) final int? selectedPlacementIndex; const PdfState({ @@ -20,6 +22,7 @@ class PdfState { this.pickedPdfBytes, this.signedPage, this.placementsByPage = const {}, + this.placementImageByPage = const {}, this.selectedPlacementIndex, }); factory PdfState.initial() => const PdfState( @@ -29,6 +32,7 @@ class PdfState { pickedPdfBytes: null, signedPage: null, placementsByPage: {}, + placementImageByPage: {}, selectedPlacementIndex: null, ); PdfState copyWith({ @@ -39,6 +43,7 @@ class PdfState { Uint8List? pickedPdfBytes, int? signedPage, Map>? placementsByPage, + Map>? placementImageByPage, int? selectedPlacementIndex, }) => PdfState( loaded: loaded ?? this.loaded, @@ -48,6 +53,7 @@ class PdfState { pickedPdfBytes: pickedPdfBytes ?? this.pickedPdfBytes, signedPage: signedPage ?? this.signedPage, placementsByPage: placementsByPage ?? this.placementsByPage, + placementImageByPage: placementImageByPage ?? this.placementImageByPage, selectedPlacementIndex: selectedPlacementIndex ?? this.selectedPlacementIndex, ); diff --git a/lib/ui/features/pdf/view_model/view_model.dart b/lib/ui/features/pdf/view_model/view_model.dart index 8c400da..a44c249 100644 --- a/lib/ui/features/pdf/view_model/view_model.dart +++ b/lib/ui/features/pdf/view_model/view_model.dart @@ -2,7 +2,6 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:pdf_signature/l10n/app_localizations.dart'; import 'package:image/image.dart' as img; import '../../../../data/model/model.dart'; @@ -19,6 +18,7 @@ class PdfController extends StateNotifier { pickedPdfPath: null, signedPage: null, placementsByPage: {}, + placementImageByPage: {}, selectedPlacementIndex: null, ); } @@ -36,6 +36,7 @@ class PdfController extends StateNotifier { pickedPdfBytes: bytes, signedPage: null, placementsByPage: {}, + placementImageByPage: {}, selectedPlacementIndex: null, ); } @@ -63,14 +64,27 @@ class PdfController extends StateNotifier { } // Multiple-signature helpers - void addPlacement({required int page, required Rect rect}) { + void addPlacement({ + required int page, + required Rect rect, + String image = 'default.png', + }) { if (!state.loaded) return; final p = page.clamp(1, state.pageCount); final map = Map>.from(state.placementsByPage); final list = List.from(map[p] ?? const []); list.add(rect); map[p] = list; - state = state.copyWith(placementsByPage: map, selectedPlacementIndex: null); + // Sync image mapping list + final imgMap = Map>.from(state.placementImageByPage); + final imgList = List.from(imgMap[p] ?? const []); + imgList.add(image); + imgMap[p] = imgList; + state = state.copyWith( + placementsByPage: map, + placementImageByPage: imgMap, + selectedPlacementIndex: null, + ); } void removePlacement({required int page, required int index}) { @@ -80,13 +94,22 @@ class PdfController extends StateNotifier { final list = List.from(map[p] ?? const []); if (index >= 0 && index < list.length) { list.removeAt(index); + // Sync image mapping + final imgMap = Map>.from(state.placementImageByPage); + final imgList = List.from(imgMap[p] ?? const []); + if (index >= 0 && index < imgList.length) { + imgList.removeAt(index); + } if (list.isEmpty) { map.remove(p); + imgMap.remove(p); } else { map[p] = list; + imgMap[p] = imgList; } state = state.copyWith( placementsByPage: map, + placementImageByPage: imgMap, selectedPlacementIndex: null, ); } @@ -116,6 +139,30 @@ class PdfController extends StateNotifier { if (idx == null) return; removePlacement(page: state.currentPage, index: idx); } + + // Assign a different image name to a placement on a page. + void assignImageToPlacement({ + required int page, + required int index, + required String image, + }) { + if (!state.loaded) return; + final p = page.clamp(1, state.pageCount); + final imgMap = Map>.from(state.placementImageByPage); + final list = List.from(imgMap[p] ?? const []); + if (index >= 0 && index < list.length) { + list[index] = image; + imgMap[p] = list; + state = state.copyWith(placementImageByPage: imgMap); + } + } + + // Convenience to get image name for a placement + String? imageOfPlacement({required int page, required int index}) { + final list = state.placementImageByPage[page] ?? const []; + if (index < 0 || index >= list.length) return null; + return list[index]; + } } final pdfProvider = StateNotifierProvider( @@ -155,10 +202,10 @@ class SignatureController extends StateNotifier { } void setInvalidSelected(BuildContext context) { - final l = AppLocalizations.of(context); - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text(l.invalidOrUnsupportedFile))); + // Fallback message without localization to keep core logic testable + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Invalid or unsupported file')), + ); } void drag(Offset delta) { diff --git a/test/features/step/_world.dart b/test/features/step/_world.dart index 490761b..cd0c793 100644 --- a/test/features/step/_world.dart +++ b/test/features/step/_world.dart @@ -31,6 +31,10 @@ class TestWorld { static String? currentTheme; // actual UI theme applied: 'light' | 'dark' static String? currentLanguage; // 'en' | 'zh-TW' | 'es' static bool settingsOpen = false; + // Signature image name loaded via steps (e.g., 'alice.png') + static String? currentImageName; + // Counters for steps that are called multiple times without params + static int placeFromPictureCallCount = 0; static void reset() { prevCenter = null; @@ -52,5 +56,7 @@ class TestWorld { currentTheme = null; currentLanguage = null; settingsOpen = false; + currentImageName = null; + placeFromPictureCallCount = 0; } } diff --git a/test/features/step/a_signature_is_placed_on_page2.dart b/test/features/step/a_signature_is_placed_on_page.dart similarity index 60% rename from test/features/step/a_signature_is_placed_on_page2.dart rename to test/features/step/a_signature_is_placed_on_page.dart index 31563ec..be9da2c 100644 --- a/test/features/step/a_signature_is_placed_on_page2.dart +++ b/test/features/step/a_signature_is_placed_on_page.dart @@ -5,18 +5,20 @@ import 'package:flutter/material.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; import '_world.dart'; -/// Usage: a signature is placed on page 2 -Future aSignatureIsPlacedOnPage2(WidgetTester tester) async { +/// Usage: a signature is placed on page {2} +Future aSignatureIsPlacedOnPage(WidgetTester tester, num page) async { final container = TestWorld.container ?? ProviderContainer(); TestWorld.container = container; container .read(pdfProvider.notifier) - .openPicked(path: 'mock.pdf', pageCount: 5); + .openPicked(path: 'mock.pdf', pageCount: 6); + // Ensure image and rect container .read(signatureProvider.notifier) .setImageBytes(Uint8List.fromList([1, 2, 3])); container.read(signatureProvider.notifier).placeDefaultRect(); - final r = container.read(signatureProvider).rect!; - container.read(pdfProvider.notifier).addPlacement(page: 2, rect: r); - expect(container.read(pdfProvider.notifier).placementsOn(2), isNotEmpty); + final Rect r = container.read(signatureProvider).rect!; + container + .read(pdfProvider.notifier) + .addPlacement(page: page.toInt(), rect: r, image: 'default.png'); } diff --git a/test/features/step/an_image_is_loaded.dart b/test/features/step/an_image_is_loaded.dart new file mode 100644 index 0000000..7283aaf --- /dev/null +++ b/test/features/step/an_image_is_loaded.dart @@ -0,0 +1,26 @@ +import 'dart:typed_data'; +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: an image {"bob.png"} is loaded +Future anImageIsLoaded(WidgetTester tester, String param1) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + // Remember current image name + TestWorld.currentImageName = param1; + // Map name to deterministic bytes for testing + Uint8List bytes; + switch (param1) { + case 'alice.png': + bytes = Uint8List.fromList([1, 2, 3]); + break; + case 'bob.png': + bytes = Uint8List.fromList([4, 5, 6]); + break; + default: + bytes = Uint8List.fromList(param1.codeUnits.take(10).toList()); + } + container.read(signatureProvider.notifier).setImageBytes(bytes); +} diff --git a/test/features/step/the_selected_signature_is_shown_with_image.dart b/test/features/step/the_selected_signature_is_shown_with_image.dart new file mode 100644 index 0000000..da7007a --- /dev/null +++ b/test/features/step/the_selected_signature_is_shown_with_image.dart @@ -0,0 +1,22 @@ +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: the selected signature is shown with image {"bob.png"} +Future theSelectedSignatureIsShownWithImage( + WidgetTester tester, + String expected, +) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + final pdf = container.read(pdfProvider); + final page = pdf.currentPage; + final idx = + pdf.selectedPlacementIndex ?? + ((pdf.placementsByPage[page]?.length ?? 1) - 1); + final name = container + .read(pdfProvider.notifier) + .imageOfPlacement(page: page, index: idx); + expect(name, expected); +} diff --git a/test/features/step/the_signature_on_page5_is_shown_on_page5.dart b/test/features/step/the_signature_on_page5_is_shown_on_page5.dart deleted file mode 100644 index d5b34ca..0000000 --- a/test/features/step/the_signature_on_page5_is_shown_on_page5.dart +++ /dev/null @@ -1,10 +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: the signature on page 5 is shown on page 5 -Future theSignatureOnPage5IsShownOnPage5(WidgetTester tester) async { - final container = TestWorld.container ?? ProviderContainer(); - expect(container.read(pdfProvider.notifier).placementsOn(5), isNotEmpty); -} diff --git a/test/features/step/the_signature_on_page_is_shown_on_page.dart b/test/features/step/the_signature_on_page_is_shown_on_page.dart new file mode 100644 index 0000000..a781d63 --- /dev/null +++ b/test/features/step/the_signature_on_page_is_shown_on_page.dart @@ -0,0 +1,19 @@ +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: the signature on page {5} is shown on page {5} +Future theSignatureOnPageIsShownOnPage( + WidgetTester tester, + num sourcePage, + num targetPage, +) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + final srcList = container.read(pdfProvider.notifier).placementsOn(sourcePage.toInt()); + final tgtList = container.read(pdfProvider.notifier).placementsOn(targetPage.toInt()); + // At least one exists on both + expect(srcList, isNotEmpty); + expect(tgtList, isNotEmpty); +} diff --git a/test/features/step/the_signature_on_page2_remains.dart b/test/features/step/the_signature_on_page_remains.dart similarity index 50% rename from test/features/step/the_signature_on_page2_remains.dart rename to test/features/step/the_signature_on_page_remains.dart index d9e4316..1ae9059 100644 --- a/test/features/step/the_signature_on_page2_remains.dart +++ b/test/features/step/the_signature_on_page_remains.dart @@ -3,8 +3,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; import '_world.dart'; -/// Usage: the signature on page 2 remains -Future theSignatureOnPage2Remains(WidgetTester tester) async { +/// Usage: the signature on page {2} remains +Future theSignatureOnPageRemains(WidgetTester tester, num page) async { final container = TestWorld.container ?? ProviderContainer(); - expect(container.read(pdfProvider.notifier).placementsOn(2), isNotEmpty); + TestWorld.container = container; + final list = container.read(pdfProvider.notifier).placementsOn(page.toInt()); + expect(list, isNotEmpty); } diff --git a/test/features/step/the_user_assigns_to_the_selected_signature.dart b/test/features/step/the_user_assigns_to_the_selected_signature.dart new file mode 100644 index 0000000..43d61c6 --- /dev/null +++ b/test/features/step/the_user_assigns_to_the_selected_signature.dart @@ -0,0 +1,30 @@ +import 'dart:typed_data'; +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: the user assigns {"bob.png"} to the selected signature +Future theUserAssignsToTheSelectedSignature( + WidgetTester tester, + String newImageName, +) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + // Load the new image into signature state (simulating pick) + Uint8List bytes = + newImageName == 'bob.png' + ? Uint8List.fromList([4, 5, 6]) + : Uint8List.fromList([1, 2, 3]); + container.read(signatureProvider.notifier).setImageBytes(bytes); + TestWorld.currentImageName = newImageName; + // Assign to currently selected placement + final pdf = container.read(pdfProvider); + final page = pdf.currentPage; + final idx = + pdf.selectedPlacementIndex ?? + ((pdf.placementsByPage[page]?.length ?? 1) - 1); + container + .read(pdfProvider.notifier) + .assignImageToPlacement(page: page, index: idx, image: newImageName); +} diff --git a/test/features/step/the_user_navigates_to_page3_and_places_another_signature.dart b/test/features/step/the_user_navigates_to_page3_and_places_another_signature.dart deleted file mode 100644 index 99e4b79..0000000 --- a/test/features/step/the_user_navigates_to_page3_and_places_another_signature.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'dart:typed_data'; -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: the user navigates to page 3 and places another signature -Future theUserNavigatesToPage3AndPlacesAnotherSignature( - WidgetTester tester, -) async { - final container = TestWorld.container ?? ProviderContainer(); - TestWorld.container = container; - // Assume doc already open from previous step; if not, open a default one - final pdf = container.read(pdfProvider); - if (!pdf.loaded) { - container - .read(pdfProvider.notifier) - .openPicked(path: 'mock.pdf', pageCount: 5); - } - // Prepare signature - container - .read(signatureProvider.notifier) - .setImageBytes(Uint8List.fromList([1, 2, 3])); - container.read(pdfProvider.notifier).jumpTo(3); - container.read(signatureProvider.notifier).placeDefaultRect(); - final r = container.read(signatureProvider).rect!; - container.read(pdfProvider.notifier).addPlacement(page: 3, rect: r); -} diff --git a/test/features/step/the_user_navigates_to_page5_and_places_another_signature.dart b/test/features/step/the_user_navigates_to_page5_and_places_another_signature.dart deleted file mode 100644 index ae1f65a..0000000 --- a/test/features/step/the_user_navigates_to_page5_and_places_another_signature.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'dart:typed_data'; -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: the user navigates to page 5 and places another signature -Future theUserNavigatesToPage5AndPlacesAnotherSignature( - WidgetTester tester, -) async { - final container = TestWorld.container ?? ProviderContainer(); - TestWorld.container = container; - container - .read(pdfProvider.notifier) - .openPicked(path: 'mock.pdf', pageCount: 6); - container - .read(signatureProvider.notifier) - .setImageBytes(Uint8List.fromList([1, 2, 3])); - container.read(pdfProvider.notifier).jumpTo(5); - container.read(signatureProvider.notifier).placeDefaultRect(); - final r = container.read(signatureProvider).rect!; - container.read(pdfProvider.notifier).addPlacement(page: 5, rect: r); - // Defensive: ensure earlier placement on page 2 remains (some setups may recreate state) - final p2 = container.read(pdfProvider.notifier).placementsOn(2); - if (p2.isEmpty) { - container - .read(pdfProvider.notifier) - .addPlacement(page: 2, rect: r.translate(-50, -50)); - } -} diff --git a/test/features/step/the_user_navigates_to_page_and_places_another_signature.dart b/test/features/step/the_user_navigates_to_page_and_places_another_signature.dart new file mode 100644 index 0000000..bc85302 --- /dev/null +++ b/test/features/step/the_user_navigates_to_page_and_places_another_signature.dart @@ -0,0 +1,34 @@ +import 'dart:typed_data'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/material.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; +import '_world.dart'; + +/// Usage: the user navigates to page {3} and places another signature +Future theUserNavigatesToPageAndPlacesAnotherSignature( + WidgetTester tester, + num page, +) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + // Ensure doc open + final pdf = container.read(pdfProvider); + if (!pdf.loaded) { + container + .read(pdfProvider.notifier) + .openPicked(path: 'mock.pdf', pageCount: 6); + } + container.read(pdfProvider.notifier).jumpTo(page.toInt()); + // Ensure an image is loaded + if (container.read(signatureProvider).imageBytes == null) { + container + .read(signatureProvider.notifier) + .setImageBytes(Uint8List.fromList([1, 2, 3])); + } + container.read(signatureProvider.notifier).placeDefaultRect(); + final Rect r = container.read(signatureProvider).rect!; + container + .read(pdfProvider.notifier) + .addPlacement(page: page.toInt(), rect: r, image: 'default.png'); +} diff --git a/test/features/step/the_user_places_a_signature_from_picture_on_page.dart b/test/features/step/the_user_places_a_signature_from_picture_on_page.dart new file mode 100644 index 0000000..befea3b --- /dev/null +++ b/test/features/step/the_user_places_a_signature_from_picture_on_page.dart @@ -0,0 +1,57 @@ +import 'dart:typed_data'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/material.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; +import '_world.dart'; + +/// Usage: the user places a signature from picture on page +Future theUserPlacesASignatureFromPictureOnPage( + WidgetTester tester, [ + dynamic imageName, + dynamic pageNumber, +]) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + // Ensure a document is open + final pdf = container.read(pdfProvider); + if (!pdf.loaded) { + container + .read(pdfProvider.notifier) + .openPicked(path: 'mock.pdf', pageCount: 6); + } + // Load image bytes based on provided name + if (imageName == null) { + // Alternate between alice/bob for the first two calls to match Examples + final idx = TestWorld.placeFromPictureCallCount++; + imageName = (idx % 2 == 0) ? 'alice.png' : 'bob.png'; + } + final String name = + imageName is String + ? imageName + : (imageName?.toString() ?? 'default.png'); + Uint8List bytes; + switch (name) { + case 'alice.png': + bytes = Uint8List.fromList([1, 2, 3]); + break; + case 'bob.png': + bytes = Uint8List.fromList([4, 5, 6]); + break; + default: + bytes = Uint8List.fromList([7, 8, 9]); + } + container.read(signatureProvider.notifier).setImageBytes(bytes); + // Place default rect and add placement on target page with image name + container.read(signatureProvider.notifier).placeDefaultRect(); + final Rect r = container.read(signatureProvider).rect!; + final int page = + (pageNumber is num) + ? pageNumber.toInt() + : int.tryParse(pageNumber?.toString() ?? '') ?? + // Default pages for the two calls in the scenario: 1 then 3 + ((TestWorld.placeFromPictureCallCount <= 1) ? 1 : 3); + container + .read(pdfProvider.notifier) + .addPlacement(page: page, rect: r, image: name); +} diff --git a/test/features/step/the_user_places_a_signature_on_page.dart b/test/features/step/the_user_places_a_signature_on_page.dart new file mode 100644 index 0000000..83973a4 --- /dev/null +++ b/test/features/step/the_user_places_a_signature_on_page.dart @@ -0,0 +1,33 @@ +import 'dart:typed_data'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/material.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; +import '_world.dart'; + +/// Usage: the user places a signature on page {1} +Future theUserPlacesASignatureOnPage( + WidgetTester tester, + num page, +) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + // Ensure doc open + final pdf = container.read(pdfProvider); + if (!pdf.loaded) { + container + .read(pdfProvider.notifier) + .openPicked(path: 'mock.pdf', pageCount: 6); + } + // Ensure an image is loaded + if (container.read(signatureProvider).imageBytes == null) { + container + .read(signatureProvider.notifier) + .setImageBytes(Uint8List.fromList([1, 2, 3])); + } + container.read(signatureProvider.notifier).placeDefaultRect(); + final Rect r = container.read(signatureProvider).rect!; + container + .read(pdfProvider.notifier) + .addPlacement(page: page.toInt(), rect: r, image: 'default.png'); +} diff --git a/test/features/step/the_user_places_a_signature_on_page1.dart b/test/features/step/the_user_places_a_signature_on_page1.dart deleted file mode 100644 index 8dee4f9..0000000 --- a/test/features/step/the_user_places_a_signature_on_page1.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'dart:typed_data'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter/material.dart'; -import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; -import '_world.dart'; - -/// Usage: the user places a signature on page 1 -Future theUserPlacesASignatureOnPage1(WidgetTester tester) async { - final container = TestWorld.container ?? ProviderContainer(); - TestWorld.container = container; - container - .read(pdfProvider.notifier) - .openPicked(path: 'mock.pdf', pageCount: 5); - container - .read(signatureProvider.notifier) - .setImageBytes(Uint8List.fromList([1, 2, 3])); - container.read(signatureProvider.notifier).placeDefaultRect(); - final r = container.read(signatureProvider).rect!; - container.read(pdfProvider.notifier).addPlacement(page: 1, rect: r); -} diff --git a/test/features/step/the_user_places_a_signature_on_the_page.dart b/test/features/step/the_user_places_a_signature_on_the_page.dart new file mode 100644 index 0000000..9597b4c --- /dev/null +++ b/test/features/step/the_user_places_a_signature_on_the_page.dart @@ -0,0 +1,40 @@ +import 'dart:typed_data'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/material.dart'; +import 'package:pdf_signature/ui/features/pdf/view_model/view_model.dart'; +import '_world.dart'; + +/// Usage: the user places a signature on the page +Future theUserPlacesASignatureOnThePage(WidgetTester tester) async { + final container = TestWorld.container ?? ProviderContainer(); + TestWorld.container = container; + final pdf = container.read(pdfProvider); + if (!pdf.loaded) { + container + .read(pdfProvider.notifier) + .openPicked(path: 'mock.pdf', pageCount: 1); + container.read(pdfProvider.notifier).setSignedPage(1); + } + // Ensure image bytes + if (container.read(signatureProvider).imageBytes == null) { + final name = TestWorld.currentImageName ?? 'alice.png'; + Uint8List bytes = + name == 'bob.png' + ? Uint8List.fromList([4, 5, 6]) + : Uint8List.fromList([1, 2, 3]); + container.read(signatureProvider.notifier).setImageBytes(bytes); + } + container.read(signatureProvider.notifier).placeDefaultRect(); + final Rect r = container.read(signatureProvider).rect!; + final int page = container.read(pdfProvider).signedPage ?? 1; + final imgName = TestWorld.currentImageName ?? 'alice.png'; + container + .read(pdfProvider.notifier) + .addPlacement(page: page, rect: r, image: imgName); + // Select the just placed signature (last index) + final list = container.read(pdfProvider).placementsByPage[page] ?? const []; + container + .read(pdfProvider.notifier) + .selectPlacement(list.isEmpty ? null : (list.length - 1)); +}