fix: signature card repository wrong API
This commit is contained in:
parent
4d2cd09adf
commit
545d3ad688
Binary file not shown.
|
|
@ -42,10 +42,12 @@ void main() {
|
||||||
),
|
),
|
||||||
documentRepositoryProvider.overrideWith(
|
documentRepositoryProvider.overrideWith(
|
||||||
(ref) =>
|
(ref) =>
|
||||||
DocumentStateNotifier()
|
DocumentStateNotifier()..openPicked(
|
||||||
..openPicked(path: 'test.pdf', pageCount: 5),
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
|
pageCount: 5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
useMockViewerProvider.overrideWith((ref) => true),
|
useMockViewerProvider.overrideWith((ref) => false),
|
||||||
exportServiceProvider.overrideWith((_) => fake),
|
exportServiceProvider.overrideWith((_) => fake),
|
||||||
savePathPickerProvider.overrideWith(
|
savePathPickerProvider.overrideWith(
|
||||||
(_) => () async => 'C:/tmp/output.pdf',
|
(_) => () async => 'C:/tmp/output.pdf',
|
||||||
|
|
@ -99,16 +101,17 @@ void main() {
|
||||||
),
|
),
|
||||||
documentRepositoryProvider.overrideWith(
|
documentRepositoryProvider.overrideWith(
|
||||||
(ref) =>
|
(ref) =>
|
||||||
DocumentStateNotifier()
|
DocumentStateNotifier()..openPicked(
|
||||||
..openPicked(path: 'test.pdf', pageCount: 5),
|
path: 'integration_test/data/sample-local-pdf.pdf',
|
||||||
|
pageCount: 5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
signatureAssetRepositoryProvider.overrideWith((ref) {
|
signatureAssetRepositoryProvider.overrideWith((ref) {
|
||||||
final c = SignatureAssetRepository();
|
final c = SignatureAssetRepository();
|
||||||
c.add(sigBytes, name: 'image');
|
c.add(sigBytes, name: 'image');
|
||||||
return c;
|
return c;
|
||||||
}),
|
}),
|
||||||
// Keep mock viewer for determinism on CI/desktop devices
|
useMockViewerProvider.overrideWithValue(false),
|
||||||
useMockViewerProvider.overrideWithValue(true),
|
|
||||||
],
|
],
|
||||||
child: const MaterialApp(
|
child: const MaterialApp(
|
||||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,20 @@ import '../../domain/models/model.dart';
|
||||||
class SignatureCardStateNotifier extends StateNotifier<List<SignatureCard>> {
|
class SignatureCardStateNotifier extends StateNotifier<List<SignatureCard>> {
|
||||||
SignatureCardStateNotifier() : super(const []);
|
SignatureCardStateNotifier() : super(const []);
|
||||||
|
|
||||||
add({required SignatureAsset asset, double rotationDeg = 0.0}) {
|
void add(SignatureCard card) {
|
||||||
|
state = List.of(state)..add(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addWithAsset(SignatureAsset asset, double rotationDeg) {
|
||||||
state = List.of(state)
|
state = List.of(state)
|
||||||
..add(SignatureCard(asset: asset, rotationDeg: rotationDeg));
|
..add(SignatureCard(asset: asset, rotationDeg: rotationDeg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void update({
|
void update(
|
||||||
required SignatureCard card,
|
SignatureCard card,
|
||||||
double? rotationDeg,
|
double? rotationDeg,
|
||||||
GraphicAdjust? graphicAdjust,
|
GraphicAdjust? graphicAdjust,
|
||||||
}) {
|
) {
|
||||||
final list = List<SignatureCard>.of(state);
|
final list = List<SignatureCard>.of(state);
|
||||||
for (var i = 0; i < list.length; i++) {
|
for (var i = 0; i < list.length; i++) {
|
||||||
final c = list[i];
|
final c = list[i];
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import 'pdf_page_overlays.dart';
|
||||||
import 'pdf_providers.dart';
|
import 'pdf_providers.dart';
|
||||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||||
// using only adjusted overlay, no direct model imports needed
|
// using only adjusted overlay, no direct model imports needed
|
||||||
|
import '../../signature/widgets/signature_drag_data.dart';
|
||||||
|
import 'package:pdf_signature/data/repositories/document_repository.dart';
|
||||||
|
|
||||||
/// Mocked continuous viewer for tests or platforms without real viewer.
|
/// Mocked continuous viewer for tests or platforms without real viewer.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
|
|
@ -81,29 +83,73 @@ class _PdfMockContinuousListState extends ConsumerState<PdfMockContinuousList> {
|
||||||
child: Stack(
|
child: Stack(
|
||||||
key: ValueKey('page_stack_$pageNum'),
|
key: ValueKey('page_stack_$pageNum'),
|
||||||
children: [
|
children: [
|
||||||
Container(
|
DragTarget<SignatureDragData>(
|
||||||
color: Colors.grey.shade200,
|
onAcceptWithDetails: (details) {
|
||||||
child: Center(
|
final dragData = details.data;
|
||||||
child: Builder(
|
final offset = details.offset;
|
||||||
builder: (ctx) {
|
final renderBox =
|
||||||
String label;
|
context.findRenderObject() as RenderBox?;
|
||||||
try {
|
if (renderBox != null) {
|
||||||
label = AppLocalizations.of(
|
final localPosition = renderBox.globalToLocal(offset);
|
||||||
ctx,
|
final normalizedX =
|
||||||
).pageInfo(pageNum, count);
|
localPosition.dx / renderBox.size.width;
|
||||||
} catch (_) {
|
final normalizedY =
|
||||||
label = 'Page $pageNum of $count';
|
localPosition.dy / renderBox.size.height;
|
||||||
}
|
|
||||||
return Text(
|
// Create a default rect for the signature (can be adjusted later)
|
||||||
label,
|
final rect = Rect.fromLTWH(
|
||||||
style: const TextStyle(
|
(normalizedX - 0.1).clamp(
|
||||||
fontSize: 24,
|
0.0,
|
||||||
color: Colors.black54,
|
0.8,
|
||||||
),
|
), // Center horizontally with some margin
|
||||||
);
|
(normalizedY - 0.05).clamp(
|
||||||
},
|
0.0,
|
||||||
),
|
0.9,
|
||||||
),
|
), // Center vertically with some margin
|
||||||
|
0.2, // Default width
|
||||||
|
0.1, // Default height
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add placement to the document
|
||||||
|
ref
|
||||||
|
.read(documentRepositoryProvider.notifier)
|
||||||
|
.addPlacement(
|
||||||
|
page: pageNum,
|
||||||
|
rect: rect,
|
||||||
|
asset: dragData.card?.asset,
|
||||||
|
rotationDeg: dragData.card?.rotationDeg ?? 0.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
builder: (context, candidateData, rejectedData) {
|
||||||
|
return Container(
|
||||||
|
color:
|
||||||
|
candidateData.isNotEmpty
|
||||||
|
? Colors.blue.withOpacity(0.3)
|
||||||
|
: Colors.grey.shade200,
|
||||||
|
child: Center(
|
||||||
|
child: Builder(
|
||||||
|
builder: (ctx) {
|
||||||
|
String label;
|
||||||
|
try {
|
||||||
|
label = AppLocalizations.of(
|
||||||
|
ctx,
|
||||||
|
).pageInfo(pageNum, count);
|
||||||
|
} catch (_) {
|
||||||
|
label = 'Page $pageNum of $count';
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
visible
|
visible
|
||||||
? Stack(
|
? Stack(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
import 'pdf_page_overlays.dart';
|
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';
|
||||||
|
|
||||||
class PdfViewerWidget extends ConsumerStatefulWidget {
|
class PdfViewerWidget extends ConsumerStatefulWidget {
|
||||||
const PdfViewerWidget({
|
const PdfViewerWidget({
|
||||||
|
|
@ -115,6 +116,41 @@ class _PdfViewerWidgetState extends ConsumerState<PdfViewerWidget> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// Drag target for dropping signatures
|
||||||
|
Positioned.fill(
|
||||||
|
child: DragTarget<SignatureDragData>(
|
||||||
|
onAcceptWithDetails: (details) {
|
||||||
|
final dragData = details.data;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// determine the exact page and position within that page
|
||||||
|
final currentPage =
|
||||||
|
ref.read(documentRepositoryProvider).currentPage;
|
||||||
|
|
||||||
|
// Create a default rect for the signature (can be adjusted later)
|
||||||
|
final rect = const Rect.fromLTWH(0.1, 0.1, 0.2, 0.1);
|
||||||
|
|
||||||
|
// Add placement to the document
|
||||||
|
ref
|
||||||
|
.read(documentRepositoryProvider.notifier)
|
||||||
|
.addPlacement(
|
||||||
|
page: currentPage,
|
||||||
|
rect: rect,
|
||||||
|
asset: dragData.card?.asset,
|
||||||
|
rotationDeg: dragData.card?.rotationDeg ?? 0.0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
builder: (context, candidateData, rejectedData) {
|
||||||
|
return Container(
|
||||||
|
color:
|
||||||
|
candidateData.isNotEmpty
|
||||||
|
? Colors.blue.withOpacity(0.1)
|
||||||
|
: Colors.transparent,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
// Add signature overlays on top
|
// Add signature overlays on top
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Consumer(
|
child: Consumer(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pdf_signature/domain/models/model.dart';
|
import 'package:pdf_signature/domain/models/model.dart' as domain;
|
||||||
import 'signature_drag_data.dart';
|
import 'signature_drag_data.dart';
|
||||||
import 'rotated_signature_image.dart';
|
import 'rotated_signature_image.dart';
|
||||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
|
|
@ -15,7 +15,7 @@ class SignatureCard extends StatelessWidget {
|
||||||
this.useCurrentBytesForDrag = false,
|
this.useCurrentBytesForDrag = false,
|
||||||
this.rotationDeg = 0.0,
|
this.rotationDeg = 0.0,
|
||||||
});
|
});
|
||||||
final SignatureAsset asset;
|
final domain.SignatureAsset asset;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
final VoidCallback onDelete;
|
final VoidCallback onDelete;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
|
@ -142,7 +142,12 @@ class SignatureCard extends StatelessWidget {
|
||||||
data:
|
data:
|
||||||
useCurrentBytesForDrag
|
useCurrentBytesForDrag
|
||||||
? const SignatureDragData()
|
? const SignatureDragData()
|
||||||
: SignatureDragData(asset: asset),
|
: SignatureDragData(
|
||||||
|
card: domain.SignatureCard(
|
||||||
|
asset: asset,
|
||||||
|
rotationDeg: rotationDeg,
|
||||||
|
),
|
||||||
|
),
|
||||||
feedback: Opacity(
|
feedback: Opacity(
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:pdf_signature/domain/models/model.dart';
|
import 'package:pdf_signature/domain/models/model.dart';
|
||||||
|
|
||||||
class SignatureDragData {
|
class SignatureDragData {
|
||||||
final SignatureAsset? asset; // null means use current processed signature
|
final SignatureCard? card; // null means use current processed signature
|
||||||
const SignatureDragData({this.asset});
|
const SignatureDragData({this.card});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ 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 '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/model.dart';
|
import 'package:pdf_signature/domain/models/model.dart';
|
||||||
import '_world.dart';
|
import '_world.dart';
|
||||||
|
|
||||||
|
|
@ -37,6 +38,14 @@ theUserDragsThisSignatureCardOnThePageOfTheDocumentToPlaceASignaturePlacement(
|
||||||
.firstWhere((a) => a.name == 'placement.png');
|
.firstWhere((a) => a.name == 'placement.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create a signature card
|
||||||
|
final temp_card = SignatureCard(asset: asset, rotationDeg: 0);
|
||||||
|
container
|
||||||
|
.read(signatureCardRepositoryProvider.notifier)
|
||||||
|
.addWithAsset(temp_card.asset, temp_card.rotationDeg);
|
||||||
|
// drag and drop (DragTarget<SignatureCard>, `onAccept`) it on document page
|
||||||
|
final drop_card = temp_card;
|
||||||
|
|
||||||
// Place it on the current page
|
// Place it on the current page
|
||||||
final pdf = container.read(documentRepositoryProvider);
|
final pdf = container.read(documentRepositoryProvider);
|
||||||
container
|
container
|
||||||
|
|
@ -44,6 +53,7 @@ theUserDragsThisSignatureCardOnThePageOfTheDocumentToPlaceASignaturePlacement(
|
||||||
.addPlacement(
|
.addPlacement(
|
||||||
page: pdf.currentPage,
|
page: pdf.currentPage,
|
||||||
rect: Rect.fromLTWH(100, 100, 100, 50),
|
rect: Rect.fromLTWH(100, 100, 100, 50),
|
||||||
asset: asset,
|
asset: drop_card.asset,
|
||||||
|
rotationDeg: drop_card.rotationDeg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ 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 '_world.dart';
|
import '_world.dart';
|
||||||
|
|
||||||
/// Usage: the user places a signature placement from asset <second_asset> on page <second_page>
|
/// Usage: the user places a signature placement from asset <secondAsset> on page <secondPage>
|
||||||
Future<void> theUserPlacesASignaturePlacementFromAssetOnPage(
|
Future<void> theUserPlacesASignaturePlacementFromAssetOnPage(
|
||||||
WidgetTester tester,
|
WidgetTester tester,
|
||||||
String assetName,
|
String assetName,
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,11 @@ Feature: support multiple signature assets
|
||||||
|
|
||||||
Scenario: Place signature placements on different pages with different assets
|
Scenario: Place signature placements on different pages with different assets
|
||||||
Given a multi-page document is open
|
Given a multi-page document is open
|
||||||
When the user places a signature placement from asset <first_asset> on page <first_page>
|
When the user places a signature placement from asset <firstAsset> on page <firstPage>.
|
||||||
And the user places a signature placement from asset <second_asset> on page <second_page>
|
And the user places a signature placement from asset <secondAsset> on page <secondPage>.
|
||||||
Then both signature placements are shown on their respective pages
|
Then both signature placements are shown on their respective pages
|
||||||
Examples:
|
Examples:
|
||||||
# Same page, same asset
|
| firstAsset | firstPage | secondAsset | secondPage |
|
||||||
# Same page, different assets
|
|
||||||
# Different pages, same asset
|
|
||||||
# Different pages, different assets
|
|
||||||
| first_asset | first_page | second_asset | second_page |
|
|
||||||
| 'alice.png' | 1 | 'alice.png' | 1 |
|
| 'alice.png' | 1 | 'alice.png' | 1 |
|
||||||
| 'alice.png' | 1 | 'bob.png' | 1 |
|
| 'alice.png' | 1 | 'bob.png' | 1 |
|
||||||
| 'alice.png' | 1 | 'bob.png' | 3 |
|
| 'alice.png' | 1 | 'bob.png' | 3 |
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue