feat: remove currentPage in Document model
This commit is contained in:
parent
545d3ad688
commit
c46aca1331
|
|
@ -4,12 +4,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
import 'package:image/image.dart' as img;
|
import 'package:image/image.dart' as img;
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:pdf_signature/data/services/export_service.dart';
|
import 'package:pdf_signature/data/services/export_service.dart';
|
||||||
|
|
||||||
import 'package:pdf_signature/data/repositories/signature_asset_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/data/repositories/document_repository.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/domain/models/model.dart';
|
||||||
|
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
|
||||||
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_providers.dart';
|
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_providers.dart';
|
||||||
import 'package:pdf_signature/ui/features/pdf/widgets/ui_services.dart';
|
import 'package:pdf_signature/ui/features/pdf/widgets/ui_services.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
@ -34,6 +37,8 @@ void main() {
|
||||||
final fake = RecordingExporter();
|
final fake = RecordingExporter();
|
||||||
SharedPreferences.setMockInitialValues({});
|
SharedPreferences.setMockInitialValues({});
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
// For this test, we don't need the PDF bytes since it's not loaded
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
overrides: [
|
overrides: [
|
||||||
|
|
@ -44,7 +49,7 @@ void main() {
|
||||||
(ref) =>
|
(ref) =>
|
||||||
DocumentStateNotifier()..openPicked(
|
DocumentStateNotifier()..openPicked(
|
||||||
path: 'integration_test/data/sample-local-pdf.pdf',
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
pageCount: 5,
|
pageCount: 1, // Initial value, will be updated by viewer
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
useMockViewerProvider.overrideWith((ref) => false),
|
useMockViewerProvider.overrideWith((ref) => false),
|
||||||
|
|
@ -90,6 +95,8 @@ void main() {
|
||||||
tester,
|
tester,
|
||||||
) async {
|
) async {
|
||||||
final sigBytes = _makeSig();
|
final sigBytes = _makeSig();
|
||||||
|
final pdfBytes =
|
||||||
|
await File('integration_test/data/sample-local-pdf.pdf').readAsBytes();
|
||||||
|
|
||||||
SharedPreferences.setMockInitialValues({});
|
SharedPreferences.setMockInitialValues({});
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
@ -103,7 +110,8 @@ void main() {
|
||||||
(ref) =>
|
(ref) =>
|
||||||
DocumentStateNotifier()..openPicked(
|
DocumentStateNotifier()..openPicked(
|
||||||
path: 'integration_test/data/sample-local-pdf.pdf',
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
pageCount: 5,
|
pageCount: 1, // Initial value, will be updated by viewer
|
||||||
|
bytes: pdfBytes,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
signatureAssetRepositoryProvider.overrideWith((ref) {
|
signatureAssetRepositoryProvider.overrideWith((ref) {
|
||||||
|
|
@ -111,6 +119,12 @@ void main() {
|
||||||
c.add(sigBytes, name: 'image');
|
c.add(sigBytes, name: 'image');
|
||||||
return c;
|
return c;
|
||||||
}),
|
}),
|
||||||
|
signatureCardRepositoryProvider.overrideWith((ref) {
|
||||||
|
final cardRepo = SignatureCardStateNotifier();
|
||||||
|
final asset = SignatureAsset(bytes: sigBytes, name: 'image');
|
||||||
|
cardRepo.addWithAsset(asset, 0.0);
|
||||||
|
return cardRepo;
|
||||||
|
}),
|
||||||
useMockViewerProvider.overrideWithValue(false),
|
useMockViewerProvider.overrideWithValue(false),
|
||||||
],
|
],
|
||||||
child: const MaterialApp(
|
child: const MaterialApp(
|
||||||
|
|
@ -139,10 +153,10 @@ void main() {
|
||||||
final r = container.read(activeRectProvider)!;
|
final r = container.read(activeRectProvider)!;
|
||||||
final lib = container.read(signatureAssetRepositoryProvider);
|
final lib = container.read(signatureAssetRepositoryProvider);
|
||||||
final asset = lib.isNotEmpty ? lib.first : null;
|
final asset = lib.isNotEmpty ? lib.first : null;
|
||||||
final pdf = container.read(documentRepositoryProvider);
|
final currentPage = container.read(pdfViewModelProvider);
|
||||||
container
|
container
|
||||||
.read(documentRepositoryProvider.notifier)
|
.read(documentRepositoryProvider.notifier)
|
||||||
.addPlacement(page: pdf.currentPage, rect: r, asset: asset);
|
.addPlacement(page: currentPage, rect: r, asset: asset);
|
||||||
// Clear active overlay by hiding signatures temporarily
|
// Clear active overlay by hiding signatures temporarily
|
||||||
container.read(signatureVisibilityProvider.notifier).state = false;
|
container.read(signatureVisibilityProvider.notifier).state = false;
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
||||||
|
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_providers.dart';
|
||||||
|
import 'package:pdf_signature/ui/features/pdf/widgets/pages_sidebar.dart';
|
||||||
|
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:pdf_signature/data/repositories/preferences_repository.dart';
|
||||||
|
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
||||||
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
/// It has known that sample-local-pdf.pdf has 3 pages.
|
||||||
|
void main() {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
testWidgets('PDF View: wheel scroll (page down)', (tester) async {
|
||||||
|
final pdfBytes =
|
||||||
|
await File('integration_test/data/sample-local-pdf.pdf').readAsBytes();
|
||||||
|
SharedPreferences.setMockInitialValues({});
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
preferencesRepositoryProvider.overrideWith(
|
||||||
|
(ref) => PreferencesStateNotifier(prefs),
|
||||||
|
),
|
||||||
|
documentRepositoryProvider.overrideWith(
|
||||||
|
(ref) =>
|
||||||
|
DocumentStateNotifier()..openPicked(
|
||||||
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
|
pageCount: 1,
|
||||||
|
bytes: pdfBytes,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
useMockViewerProvider.overrideWithValue(false),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
locale: Locale('en'),
|
||||||
|
home: PdfSignatureHomePage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Find the PDF viewer area
|
||||||
|
final pdfViewer = find.byKey(const ValueKey('pdf_page_area'));
|
||||||
|
expect(pdfViewer, findsOneWidget);
|
||||||
|
|
||||||
|
// Get initial state
|
||||||
|
final ctx = tester.element(find.byType(PdfSignatureHomePage));
|
||||||
|
final container = ProviderScope.containerOf(ctx);
|
||||||
|
final initialPage = container.read(pdfViewModelProvider);
|
||||||
|
expect(initialPage, 1);
|
||||||
|
|
||||||
|
// Simulate wheel scroll down (PageDown) to reach the last page
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
await tester.sendKeyEvent(LogicalKeyboardKey.pageDown);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that we reached the last page by checking the actual viewer state
|
||||||
|
final pdfViewerState = tester.state<_PdfViewerWidgetState>(
|
||||||
|
find.byType(PdfViewerWidget),
|
||||||
|
);
|
||||||
|
final actualPage = pdfViewerState.viewerCurrentPage;
|
||||||
|
expect(actualPage, 3); // Should be on last page (3 pages total)
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('PDF View: zoom in/out', (tester) async {
|
||||||
|
final pdfBytes =
|
||||||
|
await File('integration_test/data/sample-local-pdf.pdf').readAsBytes();
|
||||||
|
SharedPreferences.setMockInitialValues({});
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
preferencesRepositoryProvider.overrideWith(
|
||||||
|
(ref) => PreferencesStateNotifier(prefs),
|
||||||
|
),
|
||||||
|
documentRepositoryProvider.overrideWith(
|
||||||
|
(ref) =>
|
||||||
|
DocumentStateNotifier()..openPicked(
|
||||||
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
|
pageCount: 1,
|
||||||
|
bytes: pdfBytes,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
useMockViewerProvider.overrideWithValue(false),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
locale: Locale('en'),
|
||||||
|
home: PdfSignatureHomePage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Find the PDF viewer
|
||||||
|
final pdfViewer = find.byKey(const ValueKey('pdf_page_area'));
|
||||||
|
expect(pdfViewer, findsOneWidget);
|
||||||
|
|
||||||
|
// Perform pinch to zoom in
|
||||||
|
final center = tester.getCenter(pdfViewer);
|
||||||
|
// Simulate pinch zoom
|
||||||
|
final gesture1 = await tester.createGesture();
|
||||||
|
final gesture2 = await tester.createGesture();
|
||||||
|
await gesture1.down(center - const Offset(10, 0));
|
||||||
|
await gesture2.down(center + const Offset(10, 0));
|
||||||
|
await gesture1.moveTo(center - const Offset(20, 0));
|
||||||
|
await gesture2.moveTo(center + const Offset(20, 0));
|
||||||
|
await gesture1.up();
|
||||||
|
await gesture2.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify zoom worked (this might be hard to verify directly)
|
||||||
|
// We can check if the viewer is still there
|
||||||
|
expect(pdfViewer, findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('PDF View: jump to page by clicking thumbnail', (tester) async {
|
||||||
|
final pdfBytes =
|
||||||
|
await File('integration_test/data/sample-local-pdf.pdf').readAsBytes();
|
||||||
|
SharedPreferences.setMockInitialValues({});
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
preferencesRepositoryProvider.overrideWith(
|
||||||
|
(ref) => PreferencesStateNotifier(prefs),
|
||||||
|
),
|
||||||
|
documentRepositoryProvider.overrideWith(
|
||||||
|
(ref) =>
|
||||||
|
DocumentStateNotifier()..openPicked(
|
||||||
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
|
pageCount: 1,
|
||||||
|
bytes: pdfBytes,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
useMockViewerProvider.overrideWithValue(false),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
locale: Locale('en'),
|
||||||
|
home: PdfSignatureHomePage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify initial page
|
||||||
|
final ctx = tester.element(find.byType(PdfSignatureHomePage));
|
||||||
|
final container = ProviderScope.containerOf(ctx);
|
||||||
|
final initialPdf = container.read(documentRepositoryProvider);
|
||||||
|
final initialPage = container.read(pdfViewModelProvider);
|
||||||
|
expect(initialPage, 1);
|
||||||
|
|
||||||
|
// Click on page 3 thumbnail (last page)
|
||||||
|
final page3Thumbnail = find.text('3');
|
||||||
|
expect(page3Thumbnail, findsOneWidget);
|
||||||
|
await tester.tap(page3Thumbnail);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify current page is 3 and page view actually jumped
|
||||||
|
final finalPage = container.read(pdfViewModelProvider);
|
||||||
|
expect(finalPage, 3);
|
||||||
|
expect(finalPage, isNot(equals(1)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('PDF View: scroll thumbnails', (tester) async {
|
||||||
|
final pdfBytes =
|
||||||
|
await File('integration_test/data/sample-local-pdf.pdf').readAsBytes();
|
||||||
|
SharedPreferences.setMockInitialValues({});
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
preferencesRepositoryProvider.overrideWith(
|
||||||
|
(ref) => PreferencesStateNotifier(prefs),
|
||||||
|
),
|
||||||
|
documentRepositoryProvider.overrideWith(
|
||||||
|
(ref) =>
|
||||||
|
DocumentStateNotifier()..openPicked(
|
||||||
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
|
pageCount: 1,
|
||||||
|
bytes: pdfBytes,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
useMockViewerProvider.overrideWithValue(false),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
locale: Locale('en'),
|
||||||
|
home: PdfSignatureHomePage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Get initial page
|
||||||
|
final ctx = tester.element(find.byType(PdfSignatureHomePage));
|
||||||
|
final container = ProviderScope.containerOf(ctx);
|
||||||
|
final initialPage = container.read(pdfViewModelProvider);
|
||||||
|
expect(initialPage, 1);
|
||||||
|
|
||||||
|
// Find the pages sidebar
|
||||||
|
final pagesSidebar = find.byType(PagesSidebar);
|
||||||
|
expect(pagesSidebar, findsOneWidget);
|
||||||
|
|
||||||
|
// Scroll the thumbnails vertically
|
||||||
|
await tester.drag(pagesSidebar, const Offset(0, -200));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify scrolling worked (thumbnails are still there)
|
||||||
|
final page1Thumbnail = find.text('1');
|
||||||
|
expect(page1Thumbnail, findsOneWidget);
|
||||||
|
|
||||||
|
// Check if page view changed (it shouldn't for vertical scroll of thumbs)
|
||||||
|
final afterScrollPage = container.read(pdfViewModelProvider);
|
||||||
|
expect(afterScrollPage, initialPage);
|
||||||
|
|
||||||
|
// Now test horizontal scroll of PDF viewer
|
||||||
|
final pdfViewer = find.byKey(const ValueKey('pdf_page_area'));
|
||||||
|
expect(pdfViewer, findsOneWidget);
|
||||||
|
|
||||||
|
// Scroll horizontally (might not change page for fitted PDF)
|
||||||
|
await tester.drag(pdfViewer, const Offset(-100, 0)); // Scroll left
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify horizontal scroll (page might stay the same for portrait PDF)
|
||||||
|
final afterHorizontalPage = container.read(pdfViewModelProvider);
|
||||||
|
expect(afterHorizontalPage, greaterThan(1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -12,12 +12,7 @@ class DocumentStateNotifier extends StateNotifier<Document> {
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
void openSample() {
|
void openSample() {
|
||||||
state = state.copyWith(
|
state = state.copyWith(loaded: true, pageCount: 5, placementsByPage: {});
|
||||||
loaded: true,
|
|
||||||
pageCount: 5,
|
|
||||||
currentPage: 1,
|
|
||||||
placementsByPage: {},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void openPicked({
|
void openPicked({
|
||||||
|
|
@ -28,23 +23,20 @@ class DocumentStateNotifier extends StateNotifier<Document> {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
loaded: true,
|
loaded: true,
|
||||||
pageCount: pageCount,
|
pageCount: pageCount,
|
||||||
currentPage: 1,
|
|
||||||
pickedPdfBytes: bytes,
|
pickedPdfBytes: bytes,
|
||||||
placementsByPage: {},
|
placementsByPage: {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void jumpTo(int page) {
|
|
||||||
if (!state.loaded) return;
|
|
||||||
final clamped = page.clamp(1, state.pageCount);
|
|
||||||
state = state.copyWith(currentPage: clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPageCount(int count) {
|
void setPageCount(int count) {
|
||||||
if (!state.loaded) return;
|
if (!state.loaded) return;
|
||||||
state = state.copyWith(pageCount: count.clamp(1, 9999));
|
state = state.copyWith(pageCount: count.clamp(1, 9999));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void jumpTo(int page) {
|
||||||
|
// currentPage is now in view model, so jumpTo does nothing here
|
||||||
|
}
|
||||||
|
|
||||||
// Multiple-signature helpers (rects are stored in normalized fractions 0..1
|
// Multiple-signature helpers (rects are stored in normalized fractions 0..1
|
||||||
// relative to the page size: left/top/width/height are all 0..1)
|
// relative to the page size: left/top/width/height are all 0..1)
|
||||||
void addPlacement({
|
void addPlacement({
|
||||||
|
|
@ -52,6 +44,7 @@ class DocumentStateNotifier extends StateNotifier<Document> {
|
||||||
required Rect rect,
|
required Rect rect,
|
||||||
SignatureAsset? asset,
|
SignatureAsset? asset,
|
||||||
double rotationDeg = 0.0,
|
double rotationDeg = 0.0,
|
||||||
|
GraphicAdjust? graphicAdjust,
|
||||||
}) {
|
}) {
|
||||||
if (!state.loaded) return;
|
if (!state.loaded) return;
|
||||||
final p = page.clamp(1, state.pageCount);
|
final p = page.clamp(1, state.pageCount);
|
||||||
|
|
@ -62,6 +55,7 @@ class DocumentStateNotifier extends StateNotifier<Document> {
|
||||||
rect: rect,
|
rect: rect,
|
||||||
asset: asset ?? SignatureAsset(bytes: Uint8List(0)),
|
asset: asset ?? SignatureAsset(bytes: Uint8List(0)),
|
||||||
rotationDeg: rotationDeg,
|
rotationDeg: rotationDeg,
|
||||||
|
graphicAdjust: graphicAdjust ?? const GraphicAdjust(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
map[p] = list;
|
map[p] = list;
|
||||||
|
|
|
||||||
|
|
@ -5,34 +5,29 @@ import 'signature_placement.dart';
|
||||||
class Document {
|
class Document {
|
||||||
final bool loaded;
|
final bool loaded;
|
||||||
final int pageCount;
|
final int pageCount;
|
||||||
final int currentPage;
|
|
||||||
final Uint8List? pickedPdfBytes;
|
final Uint8List? pickedPdfBytes;
|
||||||
// Multiple signature placements per page, each combines geometry and asset.
|
// Multiple signature placements per page, each combines geometry and asset.
|
||||||
final Map<int, List<SignaturePlacement>> placementsByPage;
|
final Map<int, List<SignaturePlacement>> placementsByPage;
|
||||||
const Document({
|
const Document({
|
||||||
required this.loaded,
|
required this.loaded,
|
||||||
required this.pageCount,
|
required this.pageCount,
|
||||||
required this.currentPage,
|
|
||||||
this.pickedPdfBytes,
|
this.pickedPdfBytes,
|
||||||
this.placementsByPage = const {},
|
this.placementsByPage = const {},
|
||||||
});
|
});
|
||||||
factory Document.initial() => const Document(
|
factory Document.initial() => const Document(
|
||||||
loaded: false,
|
loaded: false,
|
||||||
pageCount: 0,
|
pageCount: 0,
|
||||||
currentPage: 1,
|
|
||||||
pickedPdfBytes: null,
|
pickedPdfBytes: null,
|
||||||
placementsByPage: {},
|
placementsByPage: {},
|
||||||
);
|
);
|
||||||
Document copyWith({
|
Document copyWith({
|
||||||
bool? loaded,
|
bool? loaded,
|
||||||
int? pageCount,
|
int? pageCount,
|
||||||
int? currentPage,
|
|
||||||
Uint8List? pickedPdfBytes,
|
Uint8List? pickedPdfBytes,
|
||||||
Map<int, List<SignaturePlacement>>? placementsByPage,
|
Map<int, List<SignaturePlacement>>? placementsByPage,
|
||||||
}) => Document(
|
}) => Document(
|
||||||
loaded: loaded ?? this.loaded,
|
loaded: loaded ?? this.loaded,
|
||||||
pageCount: pageCount ?? this.pageCount,
|
pageCount: pageCount ?? this.pageCount,
|
||||||
currentPage: currentPage ?? this.currentPage,
|
|
||||||
pickedPdfBytes: pickedPdfBytes ?? this.pickedPdfBytes,
|
pickedPdfBytes: pickedPdfBytes ?? this.pickedPdfBytes,
|
||||||
placementsByPage: placementsByPage ?? this.placementsByPage,
|
placementsByPage: placementsByPage ?? this.placementsByPage,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,15 @@ import 'package:pdf_signature/data/repositories/signature_card_repository.dart';
|
||||||
import 'package:pdf_signature/domain/models/model.dart';
|
import 'package:pdf_signature/domain/models/model.dart';
|
||||||
import 'package:pdfrx/pdfrx.dart';
|
import 'package:pdfrx/pdfrx.dart';
|
||||||
|
|
||||||
class PdfViewModel {
|
class PdfViewModel extends StateNotifier<int> {
|
||||||
final Ref ref;
|
final Ref ref;
|
||||||
|
|
||||||
PdfViewModel(this.ref);
|
PdfViewModel(this.ref) : super(1);
|
||||||
|
|
||||||
Document get document => ref.read(documentRepositoryProvider);
|
Document get document => ref.read(documentRepositoryProvider);
|
||||||
|
|
||||||
void jumpToPage(int page) {
|
void jumpToPage(int page) {
|
||||||
ref.read(documentRepositoryProvider.notifier).jumpTo(page);
|
state = page.clamp(1, document.pageCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> openPdf({required String path, Uint8List? bytes}) async {
|
Future<void> openPdf({required String path, Uint8List? bytes}) async {
|
||||||
|
|
@ -31,6 +31,7 @@ class PdfViewModel {
|
||||||
.read(documentRepositoryProvider.notifier)
|
.read(documentRepositoryProvider.notifier)
|
||||||
.openPicked(path: path, pageCount: pageCount, bytes: bytes);
|
.openPicked(path: path, pageCount: pageCount, bytes: bytes);
|
||||||
ref.read(signatureCardRepositoryProvider.notifier).clearAll();
|
ref.read(signatureCardRepositoryProvider.notifier).clearAll();
|
||||||
|
state = 1; // Reset current page to 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List?> loadSignatureFromFile() async {
|
Future<Uint8List?> loadSignatureFromFile() async {
|
||||||
|
|
@ -60,6 +61,6 @@ class PdfViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final pdfViewModelProvider = Provider<PdfViewModel>((ref) {
|
final pdfViewModelProvider = StateNotifierProvider<PdfViewModel, int>((ref) {
|
||||||
return PdfViewModel(ref);
|
return PdfViewModel(ref);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ class _PdfMockContinuousListState extends ConsumerState<PdfMockContinuousList> {
|
||||||
final clearPending = widget.clearPending;
|
final clearPending = widget.clearPending;
|
||||||
final visible = ref.watch(signatureVisibilityProvider);
|
final visible = ref.watch(signatureVisibilityProvider);
|
||||||
final assets = ref.watch(signatureAssetRepositoryProvider);
|
final assets = ref.watch(signatureAssetRepositoryProvider);
|
||||||
final aspectLocked = ref.watch(aspectLockedProvider);
|
|
||||||
if (pendingPage != null) {
|
if (pendingPage != null) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
final p = pendingPage;
|
final p = pendingPage;
|
||||||
|
|
@ -118,6 +117,7 @@ class _PdfMockContinuousListState extends ConsumerState<PdfMockContinuousList> {
|
||||||
rect: rect,
|
rect: rect,
|
||||||
asset: dragData.card?.asset,
|
asset: dragData.card?.asset,
|
||||||
rotationDeg: dragData.card?.rotationDeg ?? 0.0,
|
rotationDeg: dragData.card?.rotationDeg ?? 0.0,
|
||||||
|
graphicAdjust: dragData.card?.graphicAdjust,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -195,35 +195,7 @@ class _PdfMockContinuousListState extends ConsumerState<PdfMockContinuousList> {
|
||||||
height: height,
|
height: height,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
key: const Key('signature_overlay'),
|
key: const Key('signature_overlay'),
|
||||||
onPanUpdate: (d) {
|
// Removed onPanUpdate to allow scrolling
|
||||||
final dx =
|
|
||||||
d.delta.dx /
|
|
||||||
constraints.maxWidth;
|
|
||||||
final dy =
|
|
||||||
d.delta.dy /
|
|
||||||
constraints.maxHeight;
|
|
||||||
setState(() {
|
|
||||||
double l = (_activeRect.left + dx)
|
|
||||||
.clamp(0.0, 1.0);
|
|
||||||
double t = (_activeRect.top + dy)
|
|
||||||
.clamp(0.0, 1.0);
|
|
||||||
// clamp so it stays within page
|
|
||||||
l = l.clamp(
|
|
||||||
0.0,
|
|
||||||
1.0 - _activeRect.width,
|
|
||||||
);
|
|
||||||
t = t.clamp(
|
|
||||||
0.0,
|
|
||||||
1.0 - _activeRect.height,
|
|
||||||
);
|
|
||||||
_activeRect = Rect.fromLTWH(
|
|
||||||
l,
|
|
||||||
t,
|
|
||||||
_activeRect.width,
|
|
||||||
_activeRect.height,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: DecoratedBox(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
|
|
@ -243,48 +215,7 @@ class _PdfMockContinuousListState extends ConsumerState<PdfMockContinuousList> {
|
||||||
height: 14,
|
height: 14,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
key: const Key('signature_handle'),
|
key: const Key('signature_handle'),
|
||||||
onPanUpdate: (d) {
|
// Removed onPanUpdate to allow scrolling
|
||||||
final dx =
|
|
||||||
d.delta.dx /
|
|
||||||
constraints.maxWidth;
|
|
||||||
final dy =
|
|
||||||
d.delta.dy /
|
|
||||||
constraints.maxHeight;
|
|
||||||
setState(() {
|
|
||||||
double newW = (_activeRect.width +
|
|
||||||
dx)
|
|
||||||
.clamp(0.05, 1.0);
|
|
||||||
double newH =
|
|
||||||
(_activeRect.height + dy)
|
|
||||||
.clamp(0.05, 1.0);
|
|
||||||
if (aspectLocked) {
|
|
||||||
final ratio =
|
|
||||||
_activeRect.width /
|
|
||||||
_activeRect.height;
|
|
||||||
// keep ratio; prefer width change driving height
|
|
||||||
newH = (newW /
|
|
||||||
(ratio == 0
|
|
||||||
? 1
|
|
||||||
: ratio))
|
|
||||||
.clamp(0.05, 1.0);
|
|
||||||
}
|
|
||||||
// clamp to page bounds
|
|
||||||
newW = newW.clamp(
|
|
||||||
0.05,
|
|
||||||
1.0 - _activeRect.left,
|
|
||||||
);
|
|
||||||
newH = newH.clamp(
|
|
||||||
0.05,
|
|
||||||
1.0 - _activeRect.top,
|
|
||||||
);
|
|
||||||
_activeRect = Rect.fromLTWH(
|
|
||||||
_activeRect.left,
|
|
||||||
_activeRect.top,
|
|
||||||
newW,
|
|
||||||
newH,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: DecoratedBox(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import '../../../../domain/models/model.dart';
|
import '../../../../domain/models/model.dart';
|
||||||
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
||||||
import 'signature_overlay.dart';
|
import 'signature_overlay.dart';
|
||||||
|
import 'pdf_providers.dart';
|
||||||
|
|
||||||
/// Builds all overlays for a given page: placed signatures and the active one.
|
/// Builds all overlays for a given page: placed signatures and the active one.
|
||||||
class PdfPageOverlays extends ConsumerWidget {
|
class PdfPageOverlays extends ConsumerWidget {
|
||||||
|
|
@ -47,6 +48,42 @@ class PdfPageOverlays extends ConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add active overlay if present and not using mock (mock has its own)
|
||||||
|
final activeRect = ref.watch(activeRectProvider);
|
||||||
|
final useMock = ref.watch(useMockViewerProvider);
|
||||||
|
if (!useMock && activeRect != null) {
|
||||||
|
widgets.add(
|
||||||
|
LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final left = activeRect.left * constraints.maxWidth;
|
||||||
|
final top = activeRect.top * constraints.maxHeight;
|
||||||
|
final width = activeRect.width * constraints.maxWidth;
|
||||||
|
final height = activeRect.height * constraints.maxHeight;
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
left: left,
|
||||||
|
top: top,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
child: GestureDetector(
|
||||||
|
key: const Key('signature_overlay'),
|
||||||
|
// Removed onPanUpdate to allow scrolling
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: Colors.red, width: 2),
|
||||||
|
),
|
||||||
|
child: const SizedBox.expand(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Stack(children: widgets);
|
return Stack(children: widgets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'pdf_page_overlays.dart';
|
||||||
import 'pdf_providers.dart';
|
import 'pdf_providers.dart';
|
||||||
import './pdf_mock_continuous_list.dart';
|
import './pdf_mock_continuous_list.dart';
|
||||||
import '../../signature/widgets/signature_drag_data.dart';
|
import '../../signature/widgets/signature_drag_data.dart';
|
||||||
|
import '../view_model/pdf_view_model.dart';
|
||||||
|
|
||||||
class PdfViewerWidget extends ConsumerStatefulWidget {
|
class PdfViewerWidget extends ConsumerStatefulWidget {
|
||||||
const PdfViewerWidget({
|
const PdfViewerWidget({
|
||||||
|
|
@ -38,6 +39,9 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
PdfViewerController? _controller;
|
PdfViewerController? _controller;
|
||||||
PdfDocumentRef? _documentRef;
|
PdfDocumentRef? _documentRef;
|
||||||
|
|
||||||
|
// Public getter for testing the actual viewer page
|
||||||
|
int? get viewerCurrentPage => _controller?.pageNumber;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
@ -54,6 +58,8 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final document = ref.watch(documentRepositoryProvider);
|
final document = ref.watch(documentRepositoryProvider);
|
||||||
final useMock = ref.watch(useMockViewerProvider);
|
final useMock = ref.watch(useMockViewerProvider);
|
||||||
|
final activeRect = ref.watch(activeRectProvider);
|
||||||
|
final currentPage = ref.watch(pdfViewModelProvider);
|
||||||
|
|
||||||
// Update document ref when document changes
|
// Update document ref when document changes
|
||||||
if (document.loaded && document.pickedPdfBytes != null) {
|
if (document.loaded && document.pickedPdfBytes != null) {
|
||||||
|
|
@ -109,9 +115,9 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
.setPageCount(document.pages.length);
|
.setPageCount(document.pages.length);
|
||||||
},
|
},
|
||||||
onPageChanged: (page) {
|
onPageChanged: (page) {
|
||||||
// Update current page in repository
|
// Update current page in view model
|
||||||
if (page != null) {
|
if (page != null) {
|
||||||
ref.read(documentRepositoryProvider.notifier).jumpTo(page);
|
ref.read(pdfViewModelProvider.notifier).jumpToPage(page);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -125,8 +131,7 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
// For real PDF viewer, we need to calculate which page was dropped on
|
// For real PDF viewer, we need to calculate which page was dropped on
|
||||||
// This is a simplified implementation - in a real app you'd need to
|
// This is a simplified implementation - in a real app you'd need to
|
||||||
// determine the exact page and position within that page
|
// determine the exact page and position within that page
|
||||||
final currentPage =
|
final currentPage = ref.read(pdfViewModelProvider);
|
||||||
ref.read(documentRepositoryProvider).currentPage;
|
|
||||||
|
|
||||||
// Create a default rect for the signature (can be adjusted later)
|
// Create a default rect for the signature (can be adjusted later)
|
||||||
final rect = const Rect.fromLTWH(0.1, 0.1, 0.2, 0.1);
|
final rect = const Rect.fromLTWH(0.1, 0.1, 0.2, 0.1);
|
||||||
|
|
@ -139,6 +144,7 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
rect: rect,
|
rect: rect,
|
||||||
asset: dragData.card?.asset,
|
asset: dragData.card?.asset,
|
||||||
rotationDeg: dragData.card?.rotationDeg ?? 0.0,
|
rotationDeg: dragData.card?.rotationDeg ?? 0.0,
|
||||||
|
graphicAdjust: dragData.card?.graphicAdjust,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
builder: (context, candidateData, rejectedData) {
|
builder: (context, candidateData, rejectedData) {
|
||||||
|
|
@ -163,7 +169,7 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
// to handle overlays for each page properly
|
// to handle overlays for each page properly
|
||||||
return PdfPageOverlays(
|
return PdfPageOverlays(
|
||||||
pageSize: widget.pageSize,
|
pageSize: widget.pageSize,
|
||||||
pageNumber: document.currentPage,
|
pageNumber: ref.watch(pdfViewModelProvider),
|
||||||
onDragSignature: widget.onDragSignature,
|
onDragSignature: widget.onDragSignature,
|
||||||
onResizeSignature: widget.onResizeSignature,
|
onResizeSignature: widget.onResizeSignature,
|
||||||
onConfirmSignature: widget.onConfirmSignature,
|
onConfirmSignature: widget.onConfirmSignature,
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@ import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
// No direct model construction needed here
|
// No direct model construction needed here
|
||||||
|
|
||||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||||
|
import 'package:pdf_signature/data/repositories/signature_card_repository.dart';
|
||||||
import 'image_editor_dialog.dart';
|
import 'image_editor_dialog.dart';
|
||||||
import '../../signature/widgets/signature_card.dart';
|
import '../../signature/widgets/signature_card.dart';
|
||||||
|
import 'pdf_providers.dart';
|
||||||
|
|
||||||
/// Data for drag-and-drop is in signature_drag_data.dart
|
/// Data for drag-and-drop is in signature_drag_data.dart
|
||||||
|
|
||||||
|
|
@ -32,7 +34,7 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final l = AppLocalizations.of(context);
|
final l = AppLocalizations.of(context);
|
||||||
final library = ref.watch(signatureAssetRepositoryProvider);
|
final library = ref.watch(signatureCardRepositoryProvider);
|
||||||
// Exporting flag lives in ui_services; keep drawer interactive regardless here.
|
// Exporting flag lives in ui_services; keep drawer interactive regardless here.
|
||||||
final isExporting = false;
|
final isExporting = false;
|
||||||
final disabled = widget.disabled || isExporting;
|
final disabled = widget.disabled || isExporting;
|
||||||
|
|
@ -41,20 +43,21 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
if (library.isNotEmpty) ...[
|
if (library.isNotEmpty) ...[
|
||||||
for (final a in library) ...[
|
for (final card in library) ...[
|
||||||
Card(
|
Card(
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
child: SignatureCard(
|
child: SignatureCard(
|
||||||
key: ValueKey('sig_card_${library.indexOf(a)}'),
|
key: ValueKey('sig_card_${library.indexOf(card)}'),
|
||||||
asset: a,
|
asset: card.asset,
|
||||||
rotationDeg: 0.0,
|
rotationDeg: card.rotationDeg,
|
||||||
|
graphicAdjust: card.graphicAdjust,
|
||||||
disabled: disabled,
|
disabled: disabled,
|
||||||
onDelete:
|
onDelete:
|
||||||
() => ref
|
() => ref
|
||||||
.read(signatureAssetRepositoryProvider.notifier)
|
.read(signatureCardRepositoryProvider.notifier)
|
||||||
.remove(a),
|
.remove(card),
|
||||||
onAdjust: () async {
|
onAdjust: () async {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await showDialog(
|
await showDialog(
|
||||||
|
|
@ -62,7 +65,11 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
||||||
builder: (_) => const ImageEditorDialog(),
|
builder: (_) => const ImageEditorDialog(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onTap: () {},
|
onTap: () {
|
||||||
|
ref
|
||||||
|
.read(activeRectProvider.notifier)
|
||||||
|
.state = const Rect.fromLTWH(0.2, 0.2, 0.3, 0.15);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class SignatureCard extends StatelessWidget {
|
||||||
this.onAdjust,
|
this.onAdjust,
|
||||||
this.useCurrentBytesForDrag = false,
|
this.useCurrentBytesForDrag = false,
|
||||||
this.rotationDeg = 0.0,
|
this.rotationDeg = 0.0,
|
||||||
|
this.graphicAdjust = const domain.GraphicAdjust(),
|
||||||
});
|
});
|
||||||
final domain.SignatureAsset asset;
|
final domain.SignatureAsset asset;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
|
|
@ -22,6 +23,7 @@ class SignatureCard extends StatelessWidget {
|
||||||
final VoidCallback? onAdjust;
|
final VoidCallback? onAdjust;
|
||||||
final bool useCurrentBytesForDrag;
|
final bool useCurrentBytesForDrag;
|
||||||
final double rotationDeg;
|
final double rotationDeg;
|
||||||
|
final domain.GraphicAdjust graphicAdjust;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -146,6 +148,7 @@ class SignatureCard extends StatelessWidget {
|
||||||
card: domain.SignatureCard(
|
card: domain.SignatureCard(
|
||||||
asset: asset,
|
asset: asset,
|
||||||
rotationDeg: rotationDeg,
|
rotationDeg: rotationDeg,
|
||||||
|
graphicAdjust: graphicAdjust,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
feedback: Opacity(
|
feedback: Opacity(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
|
||||||
import '_world.dart';
|
import '_world.dart';
|
||||||
|
|
||||||
/// Usage: the first page is displayed
|
/// Usage: the first page is displayed
|
||||||
Future<void> theFirstPageIsDisplayed(WidgetTester tester) async {
|
Future<void> theFirstPageIsDisplayed(WidgetTester tester) async {
|
||||||
final container = TestWorld.container ?? ProviderContainer();
|
final container = TestWorld.container ?? ProviderContainer();
|
||||||
final pdf = container.read(documentRepositoryProvider);
|
final currentPage = container.read(pdfViewModelProvider);
|
||||||
expect(pdf.currentPage, 1);
|
expect(currentPage, 1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
||||||
import '_world.dart';
|
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
|
||||||
|
|
||||||
/// Usage: the signature placement rotates around its center in real time
|
/// Usage: the signature placement rotates around its center in real time
|
||||||
Future<void> theSignaturePlacementRotatesAroundItsCenterInRealTime(
|
Future<void> theSignaturePlacementRotatesAroundItsCenterInRealTime(
|
||||||
|
|
@ -9,8 +9,9 @@ Future<void> theSignaturePlacementRotatesAroundItsCenterInRealTime(
|
||||||
) async {
|
) async {
|
||||||
final container = TestWorld.container ?? ProviderContainer();
|
final container = TestWorld.container ?? ProviderContainer();
|
||||||
final pdf = container.read(documentRepositoryProvider);
|
final pdf = container.read(documentRepositoryProvider);
|
||||||
|
final currentPage = container.read(pdfViewModelProvider);
|
||||||
|
|
||||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
final placements = pdf.placementsByPage[currentPage] ?? [];
|
||||||
if (placements.isNotEmpty) {
|
if (placements.isNotEmpty) {
|
||||||
final placement = placements[0];
|
final placement = placements[0];
|
||||||
expect(placement.rotationDeg, 45.0);
|
expect(placement.rotationDeg, 45.0);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
||||||
import '_world.dart';
|
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
|
||||||
|
|
||||||
/// Usage: the user drags handles to resize and drags to reposition
|
/// Usage: the user drags handles to resize and drags to reposition
|
||||||
Future<void> theUserDragsHandlesToResizeAndDragsToReposition(
|
Future<void> theUserDragsHandlesToResizeAndDragsToReposition(
|
||||||
|
|
@ -12,8 +12,9 @@ Future<void> theUserDragsHandlesToResizeAndDragsToReposition(
|
||||||
TestWorld.container = container;
|
TestWorld.container = container;
|
||||||
final pdf = container.read(documentRepositoryProvider);
|
final pdf = container.read(documentRepositoryProvider);
|
||||||
final pdfN = container.read(documentRepositoryProvider.notifier);
|
final pdfN = container.read(documentRepositoryProvider.notifier);
|
||||||
|
final currentPage = container.read(pdfViewModelProvider);
|
||||||
|
|
||||||
final placements = pdfN.placementsOn(pdf.currentPage);
|
final placements = pdfN.placementsOn(currentPage);
|
||||||
if (placements.isNotEmpty) {
|
if (placements.isNotEmpty) {
|
||||||
final currentRect = placements[0].rect;
|
final currentRect = placements[0].rect;
|
||||||
TestWorld.prevCenter = currentRect.center;
|
TestWorld.prevCenter = currentRect.center;
|
||||||
|
|
@ -25,6 +26,6 @@ Future<void> theUserDragsHandlesToResizeAndDragsToReposition(
|
||||||
height: currentRect.height + 30,
|
height: currentRect.height + 30,
|
||||||
);
|
);
|
||||||
|
|
||||||
pdfN.updatePlacementRect(page: pdf.currentPage, index: 0, rect: newRect);
|
pdfN.updatePlacementRect(page: currentPage, index: 0, rect: newRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,5 +55,6 @@ theUserDragsThisSignatureCardOnThePageOfTheDocumentToPlaceASignaturePlacement(
|
||||||
rect: Rect.fromLTWH(100, 100, 100, 50),
|
rect: Rect.fromLTWH(100, 100, 100, 50),
|
||||||
asset: drop_card.asset,
|
asset: drop_card.asset,
|
||||||
rotationDeg: drop_card.rotationDeg,
|
rotationDeg: drop_card.rotationDeg,
|
||||||
|
graphicAdjust: drop_card.graphicAdjust,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:pdf_signature/data/repositories/document_repository.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_asset_repository.dart';
|
||||||
import 'package:pdf_signature/data/repositories/signature_card_repository.dart';
|
import 'package:pdf_signature/data/repositories/signature_card_repository.dart';
|
||||||
import 'package:pdf_signature/domain/models/model.dart';
|
import 'package:pdf_signature/ui/features/pdf/view_model/pdf_view_model.dart';
|
||||||
import '_world.dart';
|
|
||||||
|
|
||||||
/// Usage: three signature placements are placed on the current page
|
/// Usage: three signature placements are placed on the current page
|
||||||
Future<void> threeSignaturePlacementsArePlacedOnTheCurrentPage(
|
Future<void> threeSignaturePlacementsArePlacedOnTheCurrentPage(
|
||||||
|
|
@ -24,8 +23,7 @@ Future<void> threeSignaturePlacementsArePlacedOnTheCurrentPage(
|
||||||
.read(documentRepositoryProvider.notifier)
|
.read(documentRepositoryProvider.notifier)
|
||||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||||
final pdfN = container.read(documentRepositoryProvider.notifier);
|
final pdfN = container.read(documentRepositoryProvider.notifier);
|
||||||
final pdf = container.read(documentRepositoryProvider);
|
final page = container.read(pdfViewModelProvider);
|
||||||
final page = pdf.currentPage;
|
|
||||||
pdfN.addPlacement(
|
pdfN.addPlacement(
|
||||||
page: page,
|
page: page,
|
||||||
rect: Rect.fromLTWH(10, 10, 50, 50),
|
rect: Rect.fromLTWH(10, 10, 50, 50),
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_providers.dart';
|
||||||
import 'package:pdf_signature/ui/features/pdf/widgets/ui_services.dart';
|
import 'package:pdf_signature/ui/features/pdf/widgets/ui_services.dart';
|
||||||
import 'package:pdf_signature/data/repositories/document_repository.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_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/signature_asset.dart';
|
||||||
|
|
||||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
|
|
@ -377,6 +378,15 @@ Future<void> pumpWithOpenPdfAndSig(WidgetTester tester) async {
|
||||||
repo.add(Uint8List.fromList(bytes), name: 'test');
|
repo.add(Uint8List.fromList(bytes), name: 'test');
|
||||||
return repo;
|
return repo;
|
||||||
}),
|
}),
|
||||||
|
signatureCardRepositoryProvider.overrideWith((ref) {
|
||||||
|
final cardRepo = SignatureCardStateNotifier();
|
||||||
|
final asset = SignatureAsset(
|
||||||
|
bytes: Uint8List.fromList(bytes),
|
||||||
|
name: 'test',
|
||||||
|
);
|
||||||
|
cardRepo.addWithAsset(asset, 0.0);
|
||||||
|
return cardRepo;
|
||||||
|
}),
|
||||||
// In new model, interactive overlay not implemented; keep library empty
|
// In new model, interactive overlay not implemented; keep library empty
|
||||||
useMockViewerProvider.overrideWithValue(true),
|
useMockViewerProvider.overrideWithValue(true),
|
||||||
exportingProvider.overrideWith((ref) => false),
|
exportingProvider.overrideWith((ref) => false),
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,7 @@ import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
class _TestPdfController extends DocumentStateNotifier {
|
class _TestPdfController extends DocumentStateNotifier {
|
||||||
_TestPdfController() : super() {
|
_TestPdfController() : super() {
|
||||||
// Start with a loaded multi-page doc, page 1 of 5
|
// Start with a loaded multi-page doc, page 1 of 5
|
||||||
state = Document.initial().copyWith(
|
state = Document.initial().copyWith(loaded: true, pageCount: 5);
|
||||||
loaded: true,
|
|
||||||
pageCount: 5,
|
|
||||||
currentPage: 1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,7 @@ import 'package:pdf_signature/domain/models/model.dart';
|
||||||
|
|
||||||
class _TestPdfController extends DocumentStateNotifier {
|
class _TestPdfController extends DocumentStateNotifier {
|
||||||
_TestPdfController() : super() {
|
_TestPdfController() : super() {
|
||||||
state = Document.initial().copyWith(
|
state = Document.initial().copyWith(loaded: true, pageCount: 6);
|
||||||
loaded: true,
|
|
||||||
pageCount: 6,
|
|
||||||
currentPage: 1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,7 @@ import 'package:pdf_signature/domain/models/model.dart';
|
||||||
|
|
||||||
class _TestPdfController extends DocumentStateNotifier {
|
class _TestPdfController extends DocumentStateNotifier {
|
||||||
_TestPdfController() : super() {
|
_TestPdfController() : super() {
|
||||||
state = Document.initial().copyWith(
|
state = Document.initial().copyWith(loaded: true, pageCount: 6);
|
||||||
loaded: true,
|
|
||||||
pageCount: 6,
|
|
||||||
currentPage: 1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue