feat: move `model.dart` to `/lib/domain/models/`
This commit is contained in:
parent
c1b7824cbd
commit
948999fe8e
|
@ -7,7 +7,52 @@
|
|||
|
||||
## Package structure
|
||||
|
||||
The repo structure follows official [Package structure](https://docs.flutter.dev/app-architecture/case-study#package-structure) with slight modifications.
|
||||
The repo structure follows official [Package structure](https://docs.flutter.dev/app-architecture/case-study#package-structure).
|
||||
|
||||
```
|
||||
lib
|
||||
├─┬─ ui
|
||||
│ ├─┬─ core
|
||||
│ │ ├─┬─ ui
|
||||
│ │ │ └─── <shared widgets>
|
||||
│ │ └─── themes
|
||||
│ └─┬─ <FEATURE NAME>
|
||||
│ ├─┬─ view_model
|
||||
│ │ └─── <view_model class>.dart
|
||||
│ └─┬─ widgets
|
||||
│ ├── <feature name>_screen.dart
|
||||
│ └── <other widgets>
|
||||
├─┬─ domain
|
||||
│ └─┬─ models
|
||||
│ └─── <model name>.dart
|
||||
├─┬─ data
|
||||
│ ├─┬─ repositories
|
||||
│ │ └─── <repository class>.dart
|
||||
│ ├─┬─ services
|
||||
│ │ └─── <service class>.dart
|
||||
│ └─┬─ model
|
||||
│ └─── <api model class>.dart
|
||||
├─── config
|
||||
├─── utils
|
||||
├─── routing
|
||||
├─── main_staging.dart
|
||||
├─── main_development.dart
|
||||
└─── main.dart
|
||||
|
||||
// The test folder contains unit and widget tests
|
||||
test
|
||||
├─── data
|
||||
├─── domain
|
||||
├─── ui
|
||||
└─── utils
|
||||
|
||||
// The testing folder contains mocks other classes need to execute tests
|
||||
testing
|
||||
├─── fakes
|
||||
└─── models
|
||||
```
|
||||
|
||||
But with slight modifications.
|
||||
|
||||
* put each `<FEATURE NAME>/`s in `features/` sub-directory under `ui/`.
|
||||
* `test/features/` contains BDD unit tests for each feature. It focuses on pure logic, therefore will not access `View` but `ViewModel` and `Model`.
|
||||
|
@ -21,15 +66,15 @@ Some rule of thumb:
|
|||
|
||||
### terminology
|
||||
|
||||
* signature asset
|
||||
* `signature asset`
|
||||
* image file of a signature, stored in the device or cloud storage
|
||||
* can drawing from canvas
|
||||
* signature card
|
||||
* `signature card`
|
||||
* template of signature placement
|
||||
* It will include modifications such as brightness, contrast, background removal, rotation of the signature asset.
|
||||
* signature placement
|
||||
* `signature placement`
|
||||
* placed modified signature asset from signature card on a specific position on a specific page of a specific PDF document
|
||||
* document
|
||||
* `document`
|
||||
* PDF document to be signed
|
||||
|
||||
## key dependencies
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:image/image.dart' as img;
|
|||
|
||||
import 'package:pdf_signature/data/services/export_service.dart';
|
||||
import 'package:pdf_signature/data/services/export_providers.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
||||
|
@ -32,8 +32,8 @@ void main() {
|
|||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
pdfProvider.overrideWith(
|
||||
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
||||
documentRepositoryProvider.overrideWith(
|
||||
(ref) => DocumentStateNotifier()..openPicked(path: 'test.pdf'),
|
||||
),
|
||||
signatureProvider.overrideWith(
|
||||
(ref) => SignatureController()..placeDefaultRect(),
|
||||
|
@ -85,11 +85,11 @@ void main() {
|
|||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
pdfProvider.overrideWith(
|
||||
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
||||
documentRepositoryProvider.overrideWith(
|
||||
(ref) => DocumentStateNotifier()..openPicked(path: 'test.pdf'),
|
||||
),
|
||||
signatureLibraryProvider.overrideWith((ref) {
|
||||
final c = SignatureLibraryController();
|
||||
signatureAssetRepositoryProvider.overrideWith((ref) {
|
||||
final c = SignatureAssetRepository();
|
||||
c.add(sigBytes, name: 'image');
|
||||
return c;
|
||||
}),
|
||||
|
@ -121,11 +121,11 @@ void main() {
|
|||
final container = ProviderScope.containerOf(ctx);
|
||||
final sigState = container.read(signatureProvider);
|
||||
final r = sigState.rect!;
|
||||
final lib = container.read(signatureLibraryProvider);
|
||||
final lib = container.read(signatureAssetRepositoryProvider);
|
||||
final asset = lib.isNotEmpty ? lib.first : null;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(page: pdf.currentPage, rect: r, asset: asset);
|
||||
container.read(signatureProvider.notifier).clearActiveOverlay();
|
||||
await tester.pumpAndSettle();
|
||||
|
|
|
@ -98,7 +98,7 @@ class _RootHomeSwitcher extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final pdf = ref.watch(pdfProvider);
|
||||
final pdf = ref.watch(documentRepositoryProvider);
|
||||
if (!pdf.loaded) {
|
||||
return const WelcomeScreen();
|
||||
}
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// A simple library of signature images available to the user in the sidebar.
|
||||
class SignatureAsset {
|
||||
final String id; // unique id
|
||||
final Uint8List bytes;
|
||||
// List<List<Offset>>? strokes;
|
||||
final String? name; // optional display name (e.g., filename)
|
||||
const SignatureAsset({required this.id, required this.bytes, this.name});
|
||||
}
|
||||
|
||||
class GraphicAdjust {
|
||||
final double contrast;
|
||||
final double brightness;
|
||||
final bool bgRemoval;
|
||||
|
||||
const GraphicAdjust({
|
||||
this.contrast = 1.0,
|
||||
this.brightness = 0.0,
|
||||
this.bgRemoval = false,
|
||||
});
|
||||
|
||||
GraphicAdjust copyWith({
|
||||
double? contrast,
|
||||
double? brightness,
|
||||
bool? bgRemoval,
|
||||
}) => GraphicAdjust(
|
||||
contrast: contrast ?? this.contrast,
|
||||
brightness: brightness ?? this.brightness,
|
||||
bgRemoval: bgRemoval ?? this.bgRemoval,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* signature card is template of signature placement
|
||||
*/
|
||||
class SignatureCard {
|
||||
final double rotationDeg;
|
||||
final SignatureAsset asset;
|
||||
final GraphicAdjust graphicAdjust;
|
||||
|
||||
const SignatureCard({
|
||||
required this.rotationDeg,
|
||||
required this.asset,
|
||||
this.graphicAdjust = const GraphicAdjust(),
|
||||
});
|
||||
|
||||
SignatureCard copyWith({
|
||||
double? rotationDeg,
|
||||
SignatureAsset? asset,
|
||||
GraphicAdjust? graphicAdjust,
|
||||
}) => SignatureCard(
|
||||
rotationDeg: rotationDeg ?? this.rotationDeg,
|
||||
asset: asset ?? this.asset,
|
||||
graphicAdjust: graphicAdjust ?? this.graphicAdjust,
|
||||
);
|
||||
}
|
||||
|
||||
/// Represents a single signature placement on a page combining both the
|
||||
/// geometric rectangle (UI coordinate space) and the signature asset
|
||||
/// assigned to that placement.
|
||||
class SignaturePlacement {
|
||||
// The bounding box of this placement in UI coordinate space, implies scaling and position.
|
||||
final Rect rect;
|
||||
|
||||
/// Rotation in degrees to apply when rendering/exporting this placement.
|
||||
final double rotationDeg;
|
||||
final GraphicAdjust graphicAdjust;
|
||||
final SignatureAsset asset;
|
||||
|
||||
const SignaturePlacement({
|
||||
required this.rect,
|
||||
required this.asset,
|
||||
this.rotationDeg = 0.0,
|
||||
this.graphicAdjust = const GraphicAdjust(),
|
||||
});
|
||||
|
||||
SignaturePlacement copyWith({
|
||||
Rect? rect,
|
||||
SignatureAsset? asset,
|
||||
double? rotationDeg,
|
||||
GraphicAdjust? graphicAdjust,
|
||||
}) => SignaturePlacement(
|
||||
rect: rect ?? this.rect,
|
||||
asset: asset ?? this.asset,
|
||||
rotationDeg: rotationDeg ?? this.rotationDeg,
|
||||
graphicAdjust: graphicAdjust ?? this.graphicAdjust,
|
||||
);
|
||||
}
|
||||
|
||||
class PdfState {
|
||||
final bool loaded;
|
||||
final int pageCount;
|
||||
final int currentPage;
|
||||
final String? pickedPdfPath;
|
||||
final Uint8List? pickedPdfBytes;
|
||||
final int? signedPage;
|
||||
// Multiple signature placements per page, each combines geometry and asset.
|
||||
final Map<int, List<SignaturePlacement>> placementsByPage;
|
||||
// UI state: selected placement index on the current page (if any)
|
||||
final int? selectedPlacementIndex;
|
||||
const PdfState({
|
||||
required this.loaded,
|
||||
required this.pageCount,
|
||||
required this.currentPage,
|
||||
this.pickedPdfPath,
|
||||
this.pickedPdfBytes,
|
||||
this.signedPage,
|
||||
this.placementsByPage = const {},
|
||||
this.selectedPlacementIndex,
|
||||
});
|
||||
factory PdfState.initial() => const PdfState(
|
||||
loaded: false,
|
||||
pageCount: 0,
|
||||
currentPage: 1,
|
||||
pickedPdfBytes: null,
|
||||
signedPage: null,
|
||||
placementsByPage: {},
|
||||
selectedPlacementIndex: null,
|
||||
);
|
||||
PdfState copyWith({
|
||||
bool? loaded,
|
||||
int? pageCount,
|
||||
int? currentPage,
|
||||
String? pickedPdfPath,
|
||||
Uint8List? pickedPdfBytes,
|
||||
int? signedPage,
|
||||
Map<int, List<SignaturePlacement>>? placementsByPage,
|
||||
int? selectedPlacementIndex,
|
||||
}) => PdfState(
|
||||
loaded: loaded ?? this.loaded,
|
||||
pageCount: pageCount ?? this.pageCount,
|
||||
currentPage: currentPage ?? this.currentPage,
|
||||
pickedPdfPath: pickedPdfPath ?? this.pickedPdfPath,
|
||||
pickedPdfBytes: pickedPdfBytes ?? this.pickedPdfBytes,
|
||||
signedPage: signedPage ?? this.signedPage,
|
||||
placementsByPage: placementsByPage ?? this.placementsByPage,
|
||||
selectedPlacementIndex:
|
||||
selectedPlacementIndex ?? this.selectedPlacementIndex,
|
||||
);
|
||||
}
|
||||
|
||||
class SignatureState {
|
||||
final Rect? rect;
|
||||
final bool aspectLocked;
|
||||
final bool bgRemoval;
|
||||
final double contrast;
|
||||
final double brightness;
|
||||
// Rotation in degrees applied to the signature image when rendering/exporting
|
||||
final double rotation;
|
||||
final List<List<Offset>> strokes;
|
||||
final Uint8List? imageBytes;
|
||||
// The signature asset the current overlay is based on (from library)
|
||||
final SignatureAsset? asset;
|
||||
// When true, the active signature overlay is movable/resizable and should not be exported.
|
||||
// When false, the overlay is confirmed (unmovable) and eligible for export.
|
||||
final bool editingEnabled;
|
||||
const SignatureState({
|
||||
required this.rect,
|
||||
required this.aspectLocked,
|
||||
required this.bgRemoval,
|
||||
required this.contrast,
|
||||
required this.brightness,
|
||||
this.rotation = 0.0,
|
||||
required this.strokes,
|
||||
this.imageBytes,
|
||||
this.asset,
|
||||
this.editingEnabled = false,
|
||||
});
|
||||
factory SignatureState.initial() => const SignatureState(
|
||||
rect: null,
|
||||
aspectLocked: false,
|
||||
bgRemoval: false,
|
||||
contrast: 1.0,
|
||||
brightness: 0.0,
|
||||
rotation: 0.0,
|
||||
strokes: [],
|
||||
imageBytes: null,
|
||||
asset: null,
|
||||
editingEnabled: false,
|
||||
);
|
||||
SignatureState copyWith({
|
||||
Rect? rect,
|
||||
bool? aspectLocked,
|
||||
bool? bgRemoval,
|
||||
double? contrast,
|
||||
double? brightness,
|
||||
double? rotation,
|
||||
List<List<Offset>>? strokes,
|
||||
Uint8List? imageBytes,
|
||||
SignatureAsset? asset,
|
||||
bool? editingEnabled,
|
||||
}) => SignatureState(
|
||||
rect: rect ?? this.rect,
|
||||
aspectLocked: aspectLocked ?? this.aspectLocked,
|
||||
bgRemoval: bgRemoval ?? this.bgRemoval,
|
||||
contrast: contrast ?? this.contrast,
|
||||
brightness: brightness ?? this.brightness,
|
||||
rotation: rotation ?? this.rotation,
|
||||
strokes: strokes ?? this.strokes,
|
||||
imageBytes: imageBytes ?? this.imageBytes,
|
||||
asset: asset ?? this.asset,
|
||||
editingEnabled: editingEnabled ?? this.editingEnabled,
|
||||
);
|
||||
}
|
|
@ -2,57 +2,39 @@ import 'dart:typed_data';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../../data/model/model.dart';
|
||||
import '../../domain/models/model.dart';
|
||||
|
||||
class PdfController extends StateNotifier<PdfState> {
|
||||
PdfController() : super(PdfState.initial());
|
||||
static const int samplePageCount = 5;
|
||||
class DocumentStateNotifier extends StateNotifier<Document> {
|
||||
DocumentStateNotifier() : super(Document.initial());
|
||||
|
||||
@visibleForTesting
|
||||
void openSample() {
|
||||
state = state.copyWith(
|
||||
loaded: true,
|
||||
pageCount: samplePageCount,
|
||||
pageCount: 5,
|
||||
currentPage: 1,
|
||||
pickedPdfPath: null,
|
||||
signedPage: null,
|
||||
placementsByPage: {},
|
||||
selectedPlacementIndex: null,
|
||||
);
|
||||
}
|
||||
|
||||
void openPicked({
|
||||
required String path,
|
||||
int pageCount = samplePageCount,
|
||||
required int pageCount,
|
||||
Uint8List? bytes,
|
||||
}) {
|
||||
state = state.copyWith(
|
||||
loaded: true,
|
||||
pageCount: pageCount,
|
||||
currentPage: 1,
|
||||
pickedPdfPath: path,
|
||||
pickedPdfBytes: bytes,
|
||||
signedPage: null,
|
||||
placementsByPage: {},
|
||||
selectedPlacementIndex: null,
|
||||
);
|
||||
}
|
||||
|
||||
void jumpTo(int page) {
|
||||
if (!state.loaded) return;
|
||||
final clamped = page.clamp(1, state.pageCount);
|
||||
state = state.copyWith(currentPage: clamped, selectedPlacementIndex: null);
|
||||
}
|
||||
|
||||
// Set or clear the page that will receive the signature overlay.
|
||||
void setSignedPage(int? page) {
|
||||
if (!state.loaded) return;
|
||||
if (page == null) {
|
||||
state = state.copyWith(signedPage: null, selectedPlacementIndex: null);
|
||||
} else {
|
||||
final clamped = page.clamp(1, state.pageCount);
|
||||
state = state.copyWith(signedPage: clamped, selectedPlacementIndex: null);
|
||||
}
|
||||
state = state.copyWith(currentPage: clamped);
|
||||
}
|
||||
|
||||
void setPageCount(int count) {
|
||||
|
@ -80,7 +62,7 @@ class PdfController extends StateNotifier<PdfState> {
|
|||
),
|
||||
);
|
||||
map[p] = list;
|
||||
state = state.copyWith(placementsByPage: map, selectedPlacementIndex: null);
|
||||
state = state.copyWith(placementsByPage: map);
|
||||
}
|
||||
|
||||
void updatePlacementRotation({
|
||||
|
@ -111,10 +93,7 @@ class PdfController extends StateNotifier<PdfState> {
|
|||
} else {
|
||||
map[p] = list;
|
||||
}
|
||||
state = state.copyWith(
|
||||
placementsByPage: map,
|
||||
selectedPlacementIndex: null,
|
||||
);
|
||||
state = state.copyWith(placementsByPage: map);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,27 +121,6 @@ class PdfController extends StateNotifier<PdfState> {
|
|||
);
|
||||
}
|
||||
|
||||
void selectPlacement(int? index) {
|
||||
if (!state.loaded) return;
|
||||
// Only allow valid index on current page; otherwise clear
|
||||
if (index == null) {
|
||||
state = state.copyWith(selectedPlacementIndex: null);
|
||||
return;
|
||||
}
|
||||
final list = state.placementsByPage[state.currentPage] ?? const [];
|
||||
if (index >= 0 && index < list.length) {
|
||||
state = state.copyWith(selectedPlacementIndex: index);
|
||||
} else {
|
||||
state = state.copyWith(selectedPlacementIndex: null);
|
||||
}
|
||||
}
|
||||
|
||||
void deleteSelectedPlacement() {
|
||||
final idx = state.selectedPlacementIndex;
|
||||
if (idx == null) return;
|
||||
removePlacement(page: state.currentPage, index: idx);
|
||||
}
|
||||
|
||||
// NOTE: Programmatic reassignment of images has been removed.
|
||||
|
||||
// Convenience to get asset for a placement
|
||||
|
@ -173,6 +131,7 @@ class PdfController extends StateNotifier<PdfState> {
|
|||
}
|
||||
}
|
||||
|
||||
final pdfProvider = StateNotifierProvider<PdfController, PdfState>(
|
||||
(ref) => PdfController(),
|
||||
final documentRepositoryProvider =
|
||||
StateNotifierProvider<DocumentStateNotifier, Document>(
|
||||
(ref) => DocumentStateNotifier(),
|
||||
);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
|
||||
class SignatureLibraryController extends StateNotifier<List<SignatureAsset>> {
|
||||
SignatureLibraryController() : super(const []);
|
||||
///
|
||||
class SignatureAssetRepository extends StateNotifier<List<SignatureAsset>> {
|
||||
SignatureAssetRepository() : super(const []);
|
||||
|
||||
String add(Uint8List bytes, {String? name}) {
|
||||
// Always add a new asset (allow duplicates). This lets users create multiple cards
|
||||
|
@ -27,7 +28,7 @@ class SignatureLibraryController extends StateNotifier<List<SignatureAsset>> {
|
|||
}
|
||||
}
|
||||
|
||||
final signatureLibraryProvider =
|
||||
StateNotifierProvider<SignatureLibraryController, List<SignatureAsset>>(
|
||||
(ref) => SignatureLibraryController(),
|
||||
final signatureAssetRepositoryProvider =
|
||||
StateNotifierProvider<SignatureAssetRepository, List<SignatureAsset>>(
|
||||
(ref) => SignatureAssetRepository(),
|
||||
);
|
|
@ -6,15 +6,18 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:image/image.dart' as img;
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
|
||||
import '../../../../data/model/model.dart';
|
||||
import '../../domain/models/model.dart';
|
||||
import 'pdf_repository.dart';
|
||||
|
||||
class SignatureController extends StateNotifier<SignatureState> {
|
||||
SignatureController() : super(SignatureState.initial());
|
||||
class SignatureController extends StateNotifier<SignatureCard> {
|
||||
final Ref ref;
|
||||
SignatureController(this.ref) : super(SignatureCard.initial());
|
||||
static const Size pageSize = Size(400, 560);
|
||||
|
||||
void resetForNewPage() {
|
||||
state = SignatureState.initial();
|
||||
state = SignatureCard.initial();
|
||||
ref.read(currentRectProvider.notifier).setRect(null);
|
||||
ref.read(editingEnabledProvider.notifier).set(false);
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
|
@ -26,19 +29,22 @@ class SignatureController extends StateNotifier<SignatureState> {
|
|||
final cy = pageSize.height * (0.1 + rand.nextDouble() * 0.8);
|
||||
Rect r = Rect.fromCenter(center: Offset(cx, cy), width: w, height: h);
|
||||
r = _clampRectToPage(r);
|
||||
state = state.copyWith(rect: r, editingEnabled: true);
|
||||
ref.read(currentRectProvider.notifier).setRect(r);
|
||||
ref.read(editingEnabledProvider.notifier).set(true);
|
||||
}
|
||||
|
||||
void loadSample() {
|
||||
final w = 120.0, h = 60.0;
|
||||
state = state.copyWith(
|
||||
rect: Rect.fromCenter(
|
||||
ref
|
||||
.read(currentRectProvider.notifier)
|
||||
.setRect(
|
||||
Rect.fromCenter(
|
||||
center: Offset(pageSize.width / 2, pageSize.height * 0.75),
|
||||
width: w,
|
||||
height: h,
|
||||
),
|
||||
editingEnabled: true,
|
||||
);
|
||||
ref.read(editingEnabledProvider.notifier).set(true);
|
||||
}
|
||||
|
||||
void setInvalidSelected(BuildContext context) {
|
||||
|
@ -56,17 +62,19 @@ class SignatureController extends StateNotifier<SignatureState> {
|
|||
}
|
||||
|
||||
void drag(Offset delta) {
|
||||
if (state.rect == null || !state.editingEnabled) return;
|
||||
final moved = state.rect!.shift(delta);
|
||||
state = state.copyWith(rect: _clampRectToPage(moved));
|
||||
final currentRect = ref.read(currentRectProvider);
|
||||
if (currentRect == null || !ref.read(editingEnabledProvider)) return;
|
||||
final moved = currentRect.shift(delta);
|
||||
ref.read(currentRectProvider.notifier).setRect(_clampRectToPage(moved));
|
||||
}
|
||||
|
||||
void resize(Offset delta) {
|
||||
if (state.rect == null || !state.editingEnabled) return;
|
||||
final r = state.rect!;
|
||||
final currentRect = ref.read(currentRectProvider);
|
||||
if (currentRect == null || !ref.read(editingEnabledProvider)) return;
|
||||
final r = currentRect;
|
||||
double newW = r.width + delta.dx;
|
||||
double newH = r.height + delta.dy;
|
||||
if (state.aspectLocked) {
|
||||
if (ref.read(aspectLockedProvider)) {
|
||||
final aspect = r.width / r.height;
|
||||
// Keep ratio based on the dominant proportional delta
|
||||
final dxRel = (delta.dx / r.width).abs();
|
||||
|
@ -90,7 +98,7 @@ class SignatureController extends StateNotifier<SignatureState> {
|
|||
newH *= minScale;
|
||||
Rect resized = Rect.fromLTWH(r.left, r.top, newW, newH);
|
||||
resized = _clampRectPositionToPage(resized);
|
||||
state = state.copyWith(rect: resized);
|
||||
ref.read(currentRectProvider.notifier).setRect(resized);
|
||||
return;
|
||||
}
|
||||
// Unlocked aspect: clamp each dimension independently
|
||||
|
@ -98,7 +106,7 @@ class SignatureController extends StateNotifier<SignatureState> {
|
|||
newH = newH.clamp(20.0, pageSize.height);
|
||||
Rect resized = Rect.fromLTWH(r.left, r.top, newW, newH);
|
||||
resized = _clampRectToPage(resized);
|
||||
state = state.copyWith(rect: resized);
|
||||
ref.read(currentRectProvider.notifier).setRect(resized);
|
||||
}
|
||||
|
||||
Rect _clampRectToPage(Rect r) {
|
||||
|
@ -116,89 +124,98 @@ class SignatureController extends StateNotifier<SignatureState> {
|
|||
return Rect.fromLTWH(left, top, r.width, r.height);
|
||||
}
|
||||
|
||||
void toggleAspect(bool v) => state = state.copyWith(aspectLocked: v);
|
||||
void setBgRemoval(bool v) => state = state.copyWith(bgRemoval: v);
|
||||
void setContrast(double v) => state = state.copyWith(contrast: v);
|
||||
void setBrightness(double v) => state = state.copyWith(brightness: v);
|
||||
void setRotation(double deg) => state = state.copyWith(rotation: deg);
|
||||
|
||||
void setStrokes(List<List<Offset>> strokes) =>
|
||||
state = state.copyWith(strokes: strokes);
|
||||
void ensureRectForStrokes() {
|
||||
void toggleAspect(bool v) => ref.read(aspectLockedProvider.notifier).set(v);
|
||||
void setBgRemoval(bool v) =>
|
||||
state = state.copyWith(
|
||||
rect:
|
||||
state.rect ??
|
||||
graphicAdjust: state.graphicAdjust.copyWith(bgRemoval: v),
|
||||
);
|
||||
void setContrast(double v) =>
|
||||
state = state.copyWith(
|
||||
graphicAdjust: state.graphicAdjust.copyWith(contrast: v),
|
||||
);
|
||||
void setBrightness(double v) =>
|
||||
state = state.copyWith(
|
||||
graphicAdjust: state.graphicAdjust.copyWith(brightness: v),
|
||||
);
|
||||
void setRotation(double deg) => state = state.copyWith(rotationDeg: deg);
|
||||
|
||||
void ensureRectForStrokes() {
|
||||
if (ref.read(currentRectProvider) == null) {
|
||||
ref
|
||||
.read(currentRectProvider.notifier)
|
||||
.setRect(
|
||||
Rect.fromCenter(
|
||||
center: Offset(pageSize.width / 2, pageSize.height * 0.75),
|
||||
width: 140,
|
||||
height: 70,
|
||||
),
|
||||
editingEnabled: true,
|
||||
);
|
||||
ref.read(editingEnabledProvider.notifier).set(true);
|
||||
}
|
||||
}
|
||||
|
||||
void setImageBytes(Uint8List bytes) {
|
||||
state = state.copyWith(imageBytes: bytes, asset: null);
|
||||
if (state.rect == null) {
|
||||
final newAsset = SignatureAsset(id: 'drawn', bytes: bytes);
|
||||
state = state.copyWith(asset: newAsset);
|
||||
if (ref.read(currentRectProvider) == null) {
|
||||
placeDefaultRect();
|
||||
}
|
||||
// Mark as draft/editable when user just loaded image
|
||||
state = state.copyWith(editingEnabled: true);
|
||||
ref.read(editingEnabledProvider.notifier).set(true);
|
||||
}
|
||||
|
||||
// Select image from the shared signature library
|
||||
void setImageFromLibrary({required SignatureAsset asset}) {
|
||||
state = state.copyWith(asset: asset);
|
||||
if (state.rect == null) {
|
||||
if (ref.read(currentRectProvider) == null) {
|
||||
placeDefaultRect();
|
||||
}
|
||||
state = state.copyWith(editingEnabled: true);
|
||||
ref.read(editingEnabledProvider.notifier).set(true);
|
||||
}
|
||||
|
||||
void clearImage() {
|
||||
state = state.copyWith(imageBytes: null, rect: null, editingEnabled: false);
|
||||
state = SignatureCard.initial();
|
||||
ref.read(currentRectProvider.notifier).setRect(null);
|
||||
ref.read(editingEnabledProvider.notifier).set(false);
|
||||
}
|
||||
|
||||
void placeAtCenter(Offset center, {double width = 120, double height = 60}) {
|
||||
Rect r = Rect.fromCenter(center: center, width: width, height: height);
|
||||
r = _clampRectToPage(r);
|
||||
state = state.copyWith(rect: r, editingEnabled: true);
|
||||
ref.read(currentRectProvider.notifier).setRect(r);
|
||||
ref.read(editingEnabledProvider.notifier).set(true);
|
||||
}
|
||||
|
||||
// Confirm current signature: freeze editing and place it on the PDF as an immutable overlay.
|
||||
// Stores the placement rect in UI-space (SignatureController.pageSize units).
|
||||
// Returns the Rect placed, or null if no rect to confirm.
|
||||
Rect? confirmCurrentSignature(WidgetRef ref) {
|
||||
final r = state.rect;
|
||||
final r = ref.read(currentRectProvider);
|
||||
if (r == null) return null;
|
||||
// Place onto the current page
|
||||
final pdf = ref.read(pdfProvider);
|
||||
final pdf = ref.read(documentRepositoryProvider);
|
||||
if (!pdf.loaded) return null;
|
||||
// Bind the processed image at placement time (so placed preview matches adjustments).
|
||||
// If processed bytes exist, always create a new asset for this placement.
|
||||
// Prefer reusing an existing library asset when the active overlay is
|
||||
// based on a library item. If there is no library asset, do NOT create
|
||||
// a new library card here — keep the placement's asset empty so the
|
||||
// UI and exporter will fall back to using the processed/current bytes.
|
||||
// Store as UI-space rect (consistent with export and rendering paths)
|
||||
ref
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: pdf.currentPage,
|
||||
rect: r,
|
||||
asset: state.asset,
|
||||
rotationDeg: state.rotation,
|
||||
rotationDeg: state.rotationDeg,
|
||||
);
|
||||
// Newly placed index is the last one on the page
|
||||
final idx =
|
||||
(ref.read(pdfProvider).placementsByPage[pdf.currentPage]?.length ?? 1) -
|
||||
(ref
|
||||
.read(documentRepositoryProvider)
|
||||
.placementsByPage[pdf.currentPage]
|
||||
?.length ??
|
||||
1) -
|
||||
1;
|
||||
// Auto-select the newly placed item so the red box appears
|
||||
if (idx >= 0) {
|
||||
ref.read(pdfProvider.notifier).selectPlacement(idx);
|
||||
ref.read(documentRepositoryProvider.notifier).selectPlacement(idx);
|
||||
}
|
||||
// Freeze editing: keep rect for preview but disable interaction
|
||||
state = state.copyWith(editingEnabled: false);
|
||||
ref.read(editingEnabledProvider.notifier).set(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -206,76 +223,89 @@ class SignatureController extends StateNotifier<SignatureState> {
|
|||
// Useful in widget tests where obtaining a WidgetRef is not straightforward.
|
||||
@visibleForTesting
|
||||
Rect? confirmCurrentSignatureWithContainer(ProviderContainer container) {
|
||||
final r = state.rect;
|
||||
final r = container.read(currentRectProvider);
|
||||
if (r == null) return null;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
if (!pdf.loaded) return null;
|
||||
// Reuse existing library asset if present; otherwise leave empty so the
|
||||
// placement will reference the current bytes via fallback paths.
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: pdf.currentPage,
|
||||
rect: r,
|
||||
asset: state.asset,
|
||||
rotationDeg: state.rotation,
|
||||
rotationDeg: state.rotationDeg,
|
||||
);
|
||||
final idx =
|
||||
(container
|
||||
.read(pdfProvider)
|
||||
.read(documentRepositoryProvider)
|
||||
.placementsByPage[pdf.currentPage]
|
||||
?.length ??
|
||||
1) -
|
||||
1;
|
||||
// Auto-select the newly placed item so the red box appears
|
||||
if (idx >= 0) {
|
||||
container.read(pdfProvider.notifier).selectPlacement(idx);
|
||||
container.read(documentRepositoryProvider.notifier).selectPlacement(idx);
|
||||
}
|
||||
// Freeze editing: keep rect for preview but disable interaction
|
||||
state = state.copyWith(editingEnabled: false);
|
||||
container.read(editingEnabledProvider.notifier).set(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Remove the active overlay (draft or confirmed preview) but keep image settings intact
|
||||
void clearActiveOverlay() {
|
||||
state = state.copyWith(rect: null, editingEnabled: false);
|
||||
ref.read(currentRectProvider.notifier).setRect(null);
|
||||
ref.read(editingEnabledProvider.notifier).set(false);
|
||||
}
|
||||
}
|
||||
|
||||
final signatureProvider =
|
||||
StateNotifierProvider<SignatureController, SignatureState>(
|
||||
(ref) => SignatureController(),
|
||||
final signatureCardProvider =
|
||||
StateNotifierProvider<SignatureController, SignatureCard>(
|
||||
(ref) => SignatureController(ref),
|
||||
);
|
||||
|
||||
final currentRectProvider = StateNotifierProvider<RectNotifier, Rect?>(
|
||||
(ref) => RectNotifier(),
|
||||
);
|
||||
|
||||
class RectNotifier extends StateNotifier<Rect?> {
|
||||
RectNotifier() : super(null);
|
||||
|
||||
void setRect(Rect? r) => state = r;
|
||||
}
|
||||
|
||||
final editingEnabledProvider = StateNotifierProvider<BoolNotifier, bool>(
|
||||
(ref) => BoolNotifier(false),
|
||||
);
|
||||
|
||||
class BoolNotifier extends StateNotifier<bool> {
|
||||
BoolNotifier(bool initial) : super(initial);
|
||||
|
||||
void set(bool v) => state = v;
|
||||
}
|
||||
|
||||
final aspectLockedProvider = StateNotifierProvider<BoolNotifier, bool>(
|
||||
(ref) => BoolNotifier(false),
|
||||
);
|
||||
|
||||
/// Derived provider that returns processed signature image bytes according to
|
||||
/// current adjustment settings (contrast/brightness) and background removal.
|
||||
/// Returns null if no image is loaded. The output is a PNG to preserve alpha.
|
||||
final processedSignatureImageProvider = Provider<Uint8List?>((ref) {
|
||||
// Watch only the fields that affect pixel processing to avoid recompute on rotation.
|
||||
final SignatureAsset? asset = ref.watch(
|
||||
signatureProvider.select((s) => s.asset),
|
||||
);
|
||||
final Uint8List? directBytes = ref.watch(
|
||||
signatureProvider.select((s) => s.imageBytes),
|
||||
final SignatureAsset asset = ref.watch(
|
||||
signatureCardProvider.select((s) => s.asset),
|
||||
);
|
||||
final double contrast = ref.watch(
|
||||
signatureProvider.select((s) => s.contrast),
|
||||
signatureCardProvider.select((s) => s.graphicAdjust.contrast),
|
||||
);
|
||||
final double brightness = ref.watch(
|
||||
signatureProvider.select((s) => s.brightness),
|
||||
signatureCardProvider.select((s) => s.graphicAdjust.brightness),
|
||||
);
|
||||
final bool bgRemoval = ref.watch(
|
||||
signatureProvider.select((s) => s.bgRemoval),
|
||||
signatureCardProvider.select((s) => s.graphicAdjust.bgRemoval),
|
||||
);
|
||||
|
||||
// If active overlay is based on a library asset, pull its bytes
|
||||
Uint8List? bytes;
|
||||
if (asset != null) {
|
||||
bytes = asset.bytes;
|
||||
} else {
|
||||
bytes = directBytes;
|
||||
}
|
||||
if (bytes == null || bytes.isEmpty) return null;
|
||||
Uint8List? bytes = asset.bytes;
|
||||
if (bytes.isEmpty) return null;
|
||||
|
||||
// Decode (supports PNG/JPEG, etc.)
|
||||
final decoded = img.decodeImage(bytes);
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:pdf/widgets.dart' as pw;
|
|||
import 'package:pdf/pdf.dart' as pdf;
|
||||
import 'package:printing/printing.dart' as printing;
|
||||
import 'package:image/image.dart' as img;
|
||||
import '../model/model.dart';
|
||||
import '../../domain/models/model.dart';
|
||||
|
||||
// NOTE:
|
||||
// - This exporter uses a raster snapshot of the UI (RepaintBoundary) and embeds it into a new PDF.
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import 'dart:typed_data';
|
||||
import 'signature_placement.dart';
|
||||
|
||||
/// PDF document to be signed
|
||||
class Document {
|
||||
final bool loaded;
|
||||
final int pageCount;
|
||||
final int currentPage;
|
||||
final Uint8List? pickedPdfBytes;
|
||||
// Multiple signature placements per page, each combines geometry and asset.
|
||||
final Map<int, List<SignaturePlacement>> placementsByPage;
|
||||
const Document({
|
||||
required this.loaded,
|
||||
required this.pageCount,
|
||||
required this.currentPage,
|
||||
this.pickedPdfBytes,
|
||||
this.placementsByPage = const {},
|
||||
});
|
||||
factory Document.initial() => const Document(
|
||||
loaded: false,
|
||||
pageCount: 0,
|
||||
currentPage: 1,
|
||||
pickedPdfBytes: null,
|
||||
placementsByPage: {},
|
||||
);
|
||||
Document copyWith({
|
||||
bool? loaded,
|
||||
int? pageCount,
|
||||
int? currentPage,
|
||||
Uint8List? pickedPdfBytes,
|
||||
Map<int, List<SignaturePlacement>>? placementsByPage,
|
||||
}) => Document(
|
||||
loaded: loaded ?? this.loaded,
|
||||
pageCount: pageCount ?? this.pageCount,
|
||||
currentPage: currentPage ?? this.currentPage,
|
||||
pickedPdfBytes: pickedPdfBytes ?? this.pickedPdfBytes,
|
||||
placementsByPage: placementsByPage ?? this.placementsByPage,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
class GraphicAdjust {
|
||||
final double contrast;
|
||||
final double brightness;
|
||||
final bool bgRemoval;
|
||||
|
||||
const GraphicAdjust({
|
||||
this.contrast = 1.0,
|
||||
this.brightness = 0.0,
|
||||
this.bgRemoval = false,
|
||||
});
|
||||
|
||||
GraphicAdjust copyWith({
|
||||
double? contrast,
|
||||
double? brightness,
|
||||
bool? bgRemoval,
|
||||
}) => GraphicAdjust(
|
||||
contrast: contrast ?? this.contrast,
|
||||
brightness: brightness ?? this.brightness,
|
||||
bgRemoval: bgRemoval ?? this.bgRemoval,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export 'signature_asset.dart';
|
||||
export 'graphic_adjust.dart';
|
||||
export 'signature_card.dart';
|
||||
export 'signature_placement.dart';
|
||||
export 'document.dart';
|
|
@ -0,0 +1,10 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
/// SignatureAsset store image file of a signature, stored in the device or cloud storage
|
||||
class SignatureAsset {
|
||||
final String id; // unique id
|
||||
final Uint8List bytes;
|
||||
// List<List<Offset>>? strokes;
|
||||
final String? name; // optional display name (e.g., filename)
|
||||
const SignatureAsset({required this.id, required this.bytes, this.name});
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import 'dart:typed_data';
|
||||
import 'signature_asset.dart';
|
||||
import 'graphic_adjust.dart';
|
||||
|
||||
/**
|
||||
* signature card is template of signature placement
|
||||
* Use the [SignatureCardRepository] to obtain a full [SignatureCard]
|
||||
*/
|
||||
class SignatureCard {
|
||||
final double rotationDeg;
|
||||
final SignatureAsset asset;
|
||||
final GraphicAdjust graphicAdjust;
|
||||
|
||||
const SignatureCard({
|
||||
required this.rotationDeg,
|
||||
required this.asset,
|
||||
this.graphicAdjust = const GraphicAdjust(),
|
||||
});
|
||||
|
||||
SignatureCard copyWith({
|
||||
double? rotationDeg,
|
||||
SignatureAsset? asset,
|
||||
GraphicAdjust? graphicAdjust,
|
||||
}) => SignatureCard(
|
||||
rotationDeg: rotationDeg ?? this.rotationDeg,
|
||||
asset: asset ?? this.asset,
|
||||
graphicAdjust: graphicAdjust ?? this.graphicAdjust,
|
||||
);
|
||||
|
||||
factory SignatureCard.initial() => SignatureCard(
|
||||
rotationDeg: 0.0,
|
||||
asset: SignatureAsset(id: '', bytes: Uint8List(0)),
|
||||
graphicAdjust: const GraphicAdjust(),
|
||||
);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import 'dart:ui';
|
||||
import 'signature_asset.dart';
|
||||
import 'graphic_adjust.dart';
|
||||
|
||||
/// Represents a single signature placement on a page combining both the
|
||||
/// geometric rectangle (UI coordinate space) and the signature asset
|
||||
/// assigned to that placement.
|
||||
class SignaturePlacement {
|
||||
// The bounding box of this placement in UI coordinate space, implies scaling and position.
|
||||
final Rect rect;
|
||||
|
||||
/// Rotation in degrees to apply when rendering/exporting this placement.
|
||||
final double rotationDeg;
|
||||
final GraphicAdjust graphicAdjust;
|
||||
final SignatureAsset asset;
|
||||
|
||||
const SignaturePlacement({
|
||||
required this.rect,
|
||||
required this.asset,
|
||||
this.rotationDeg = 0.0,
|
||||
this.graphicAdjust = const GraphicAdjust(),
|
||||
});
|
||||
|
||||
SignaturePlacement copyWith({
|
||||
Rect? rect,
|
||||
SignatureAsset? asset,
|
||||
double? rotationDeg,
|
||||
GraphicAdjust? graphicAdjust,
|
||||
}) => SignaturePlacement(
|
||||
rect: rect ?? this.rect,
|
||||
asset: asset ?? this.asset,
|
||||
rotationDeg: rotationDeg ?? this.rotationDeg,
|
||||
graphicAdjust: graphicAdjust ?? this.graphicAdjust,
|
||||
);
|
||||
}
|
|
@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
|
||||
import '../../../../data/model/model.dart';
|
||||
import '../../../../domain/models/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
|
||||
class AdjustmentsPanel extends ConsumerWidget {
|
||||
const AdjustmentsPanel({super.key, required this.sig});
|
||||
|
||||
final SignatureState sig;
|
||||
final SignatureCard sig;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
@ -22,19 +22,20 @@ class AdjustmentsPanel extends ConsumerWidget {
|
|||
children: [
|
||||
Checkbox(
|
||||
key: const Key('chk_aspect_lock'),
|
||||
value: sig.aspectLocked,
|
||||
value: ref.watch(aspectLockedProvider),
|
||||
onChanged:
|
||||
(v) => ref
|
||||
.read(signatureProvider.notifier)
|
||||
.read(signatureCardProvider.notifier)
|
||||
.toggleAspect(v ?? false),
|
||||
),
|
||||
Text(AppLocalizations.of(context).lockAspectRatio),
|
||||
const SizedBox(width: 16),
|
||||
Switch(
|
||||
key: const Key('swt_bg_removal'),
|
||||
value: sig.bgRemoval,
|
||||
value: sig.graphicAdjust.bgRemoval,
|
||||
onChanged:
|
||||
(v) => ref.read(signatureProvider.notifier).setBgRemoval(v),
|
||||
(v) =>
|
||||
ref.read(signatureCardProvider.notifier).setBgRemoval(v),
|
||||
),
|
||||
Text(AppLocalizations.of(context).backgroundRemoval),
|
||||
],
|
||||
|
@ -47,15 +48,16 @@ class AdjustmentsPanel extends ConsumerWidget {
|
|||
Text(AppLocalizations.of(context).contrast),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(sig.contrast.toStringAsFixed(2)),
|
||||
child: Text(sig.graphicAdjust.contrast.toStringAsFixed(2)),
|
||||
),
|
||||
Slider(
|
||||
key: const Key('sld_contrast'),
|
||||
min: 0.0,
|
||||
max: 2.0,
|
||||
value: sig.contrast,
|
||||
value: sig.graphicAdjust.contrast,
|
||||
onChanged:
|
||||
(v) => ref.read(signatureProvider.notifier).setContrast(v),
|
||||
(v) =>
|
||||
ref.read(signatureCardProvider.notifier).setContrast(v),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -66,15 +68,16 @@ class AdjustmentsPanel extends ConsumerWidget {
|
|||
Text(AppLocalizations.of(context).brightness),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(sig.brightness.toStringAsFixed(2)),
|
||||
child: Text(sig.graphicAdjust.brightness.toStringAsFixed(2)),
|
||||
),
|
||||
Slider(
|
||||
key: const Key('sld_brightness'),
|
||||
min: -1.0,
|
||||
max: 1.0,
|
||||
value: sig.brightness,
|
||||
value: sig.graphicAdjust.brightness,
|
||||
onChanged:
|
||||
(v) => ref.read(signatureProvider.notifier).setBrightness(v),
|
||||
(v) =>
|
||||
ref.read(signatureCardProvider.notifier).setBrightness(v),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -51,7 +51,7 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
// is instructed to align to the provider's current page once ready.
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
final pdf = ref.read(pdfProvider);
|
||||
final pdf = ref.read(documentRepositoryProvider);
|
||||
if (pdf.pickedPdfPath != null && pdf.loaded) {
|
||||
_scrollToPage(pdf.currentPage);
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
void _scrollToPage(int page) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
final pdf = ref.read(pdfProvider);
|
||||
final pdf = ref.read(documentRepositoryProvider);
|
||||
const isContinuous = true;
|
||||
|
||||
// Real continuous: drive via PdfViewerController
|
||||
|
@ -156,11 +156,11 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pdf = ref.watch(pdfProvider);
|
||||
final pdf = ref.watch(documentRepositoryProvider);
|
||||
const pageViewMode = 'continuous';
|
||||
|
||||
// React to provider currentPage changes (e.g., user tapped overview)
|
||||
ref.listen(pdfProvider, (prev, next) {
|
||||
ref.listen(documentRepositoryProvider, (prev, next) {
|
||||
if (_suppressProviderListen) return;
|
||||
if ((prev?.currentPage != next.currentPage)) {
|
||||
final target = next.currentPage;
|
||||
|
@ -288,7 +288,9 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
],
|
||||
onViewerReady: (doc, controller) {
|
||||
if (pdf.pageCount != doc.pages.length) {
|
||||
ref.read(pdfProvider.notifier).setPageCount(doc.pages.length);
|
||||
ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.setPageCount(doc.pages.length);
|
||||
}
|
||||
final target = _pendingPage ?? pdf.currentPage;
|
||||
_pendingPage = null;
|
||||
|
@ -305,9 +307,9 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
// Programmatic navigation: wait until target reached
|
||||
if (_programmaticTargetPage != null) {
|
||||
if (n == _programmaticTargetPage) {
|
||||
if (n != ref.read(pdfProvider).currentPage) {
|
||||
if (n != ref.read(documentRepositoryProvider).currentPage) {
|
||||
_suppressProviderListen = true;
|
||||
ref.read(pdfProvider.notifier).jumpTo(n);
|
||||
ref.read(documentRepositoryProvider.notifier).jumpTo(n);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_suppressProviderListen = false;
|
||||
});
|
||||
|
@ -317,9 +319,9 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
return;
|
||||
}
|
||||
// User scroll -> reflect page to provider without re-triggering scroll
|
||||
if (n != ref.read(pdfProvider).currentPage) {
|
||||
if (n != ref.read(documentRepositoryProvider).currentPage) {
|
||||
_suppressProviderListen = true;
|
||||
ref.read(pdfProvider.notifier).jumpTo(n);
|
||||
ref.read(documentRepositoryProvider.notifier).jumpTo(n);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_suppressProviderListen = false;
|
||||
});
|
||||
|
@ -348,8 +350,8 @@ class _PdfPageAreaState extends ConsumerState<PdfPageArea> {
|
|||
}
|
||||
ref.read(signatureProvider.notifier).placeAtCenter(Offset(cx, cy));
|
||||
ref
|
||||
.read(pdfProvider.notifier)
|
||||
.setSignedPage(ref.read(pdfProvider).currentPage);
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.setSignedPage(ref.read(documentRepositoryProvider).currentPage);
|
||||
},
|
||||
builder:
|
||||
(context, candidateData, rejected) => Stack(
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import '../../../../data/model/model.dart';
|
||||
import '../../../../domain/models/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'signature_overlay.dart';
|
||||
|
||||
|
@ -29,8 +29,8 @@ class PdfPageOverlays extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final pdf = ref.watch(pdfProvider);
|
||||
final sig = ref.watch(signatureProvider);
|
||||
final pdf = ref.watch(documentRepositoryProvider);
|
||||
final sig = ref.watch(signatureCardProvider);
|
||||
final placed =
|
||||
pdf.placementsByPage[pageNumber] ?? const <SignaturePlacement>[];
|
||||
final widgets = <Widget>[];
|
||||
|
@ -44,16 +44,17 @@ class PdfPageOverlays extends ConsumerWidget {
|
|||
rect: uiRect,
|
||||
sig: sig,
|
||||
pageNumber: pageNumber,
|
||||
interactive: false,
|
||||
placedIndex: i,
|
||||
onSelectPlaced: onSelectPlaced,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final currentRect = ref.watch(currentRectProvider);
|
||||
final editingEnabled = ref.watch(editingEnabledProvider);
|
||||
final showActive =
|
||||
sig.rect != null &&
|
||||
sig.editingEnabled &&
|
||||
currentRect != null &&
|
||||
editingEnabled &&
|
||||
(pdf.signedPage == null || pdf.signedPage == pageNumber) &&
|
||||
pdf.currentPage == pageNumber;
|
||||
|
||||
|
@ -61,10 +62,9 @@ class PdfPageOverlays extends ConsumerWidget {
|
|||
widgets.add(
|
||||
SignatureOverlay(
|
||||
pageSize: pageSize,
|
||||
rect: sig.rect!,
|
||||
rect: currentRect,
|
||||
sig: sig,
|
||||
pageNumber: pageNumber,
|
||||
interactive: true,
|
||||
onDragSignature: onDragSignature,
|
||||
onResizeSignature: onResizeSignature,
|
||||
onConfirmSignature: onConfirmSignature,
|
||||
|
|
|
@ -10,7 +10,7 @@ class PdfPagesOverview extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final pdf = ref.watch(pdfProvider);
|
||||
final pdf = ref.watch(documentRepositoryProvider);
|
||||
final useMock = ref.watch(useMockViewerProvider);
|
||||
final theme = Theme.of(context);
|
||||
|
||||
|
@ -25,7 +25,10 @@ class PdfPagesOverview extends ConsumerWidget {
|
|||
final pageNumber = index + 1;
|
||||
final isSelected = pdf.currentPage == pageNumber;
|
||||
return InkWell(
|
||||
onTap: () => ref.read(pdfProvider.notifier).jumpTo(pageNumber),
|
||||
onTap:
|
||||
() => ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.jumpTo(pageNumber),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
|
@ -74,7 +77,9 @@ class PdfPagesOverview extends ConsumerWidget {
|
|||
final pages = document.pages;
|
||||
if (pdf.pageCount != pages.length) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(pdfProvider.notifier).setPageCount(pages.length);
|
||||
ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.setPageCount(pages.length);
|
||||
});
|
||||
}
|
||||
return buildList(
|
||||
|
|
|
@ -12,7 +12,7 @@ import '../../../../data/services/export_providers.dart';
|
|||
import 'package:image/image.dart' as img;
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'draw_canvas.dart';
|
||||
import 'pdf_toolbar.dart';
|
||||
import 'pdf_page_area.dart';
|
||||
|
@ -61,13 +61,15 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
} catch (_) {
|
||||
bytes = null;
|
||||
}
|
||||
ref.read(pdfProvider.notifier).openPicked(path: file.path, bytes: bytes);
|
||||
ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: file.path, bytes: bytes);
|
||||
ref.read(signatureProvider.notifier).resetForNewPage();
|
||||
}
|
||||
}
|
||||
|
||||
void _jumpToPage(int page) {
|
||||
ref.read(pdfProvider.notifier).jumpTo(page);
|
||||
ref.read(documentRepositoryProvider.notifier).jumpTo(page);
|
||||
}
|
||||
|
||||
Future<Uint8List?> _loadSignatureFromFile() async {
|
||||
|
@ -81,9 +83,11 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
final bytes = await file.readAsBytes();
|
||||
final sig = ref.read(signatureProvider.notifier);
|
||||
sig.setImageBytes(bytes);
|
||||
final p = ref.read(pdfProvider);
|
||||
final p = ref.read(documentRepositoryProvider);
|
||||
if (p.loaded) {
|
||||
ref.read(pdfProvider.notifier).setSignedPage(p.currentPage);
|
||||
ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.setSignedPage(p.currentPage);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
@ -101,7 +105,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
}
|
||||
|
||||
void _onSelectPlaced(int? index) {
|
||||
ref.read(pdfProvider.notifier).selectPlacement(index);
|
||||
ref.read(documentRepositoryProvider.notifier).selectPlacement(index);
|
||||
}
|
||||
|
||||
Future<Uint8List?> _openDrawCanvas() async {
|
||||
|
@ -113,9 +117,11 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
);
|
||||
if (result != null && result.isNotEmpty) {
|
||||
ref.read(signatureProvider.notifier).setImageBytes(result);
|
||||
final p = ref.read(pdfProvider);
|
||||
final p = ref.read(documentRepositoryProvider);
|
||||
if (p.loaded) {
|
||||
ref.read(pdfProvider.notifier).setSignedPage(p.currentPage);
|
||||
ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.setSignedPage(p.currentPage);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -124,7 +130,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
Future<void> _saveSignedPdf() async {
|
||||
ref.read(exportingProvider.notifier).state = true;
|
||||
try {
|
||||
final pdf = ref.read(pdfProvider);
|
||||
final pdf = ref.read(documentRepositoryProvider);
|
||||
final sig = ref.read(signatureProvider);
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
if (!pdf.loaded || sig.rect == null) {
|
||||
|
@ -175,7 +181,8 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
signatureImageBytes: rotated,
|
||||
placementsByPage: pdf.placementsByPage,
|
||||
libraryBytes: {
|
||||
for (final a in ref.read(signatureLibraryProvider)) a.id: a.bytes,
|
||||
for (final a in ref.read(signatureAssetRepositoryProvider))
|
||||
a.id: a.bytes,
|
||||
},
|
||||
targetDpi: targetDpi,
|
||||
);
|
||||
|
@ -211,7 +218,8 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
signatureImageBytes: rotated,
|
||||
placementsByPage: pdf.placementsByPage,
|
||||
libraryBytes: {
|
||||
for (final a in ref.read(signatureLibraryProvider)) a.id: a.bytes,
|
||||
for (final a in ref.read(signatureAssetRepositoryProvider))
|
||||
a.id: a.bytes,
|
||||
},
|
||||
targetDpi: targetDpi,
|
||||
);
|
||||
|
@ -241,7 +249,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
signatureImageBytes: rotated,
|
||||
placementsByPage: pdf.placementsByPage,
|
||||
libraryBytes: {
|
||||
for (final a in ref.read(signatureLibraryProvider))
|
||||
for (final a in ref.read(signatureAssetRepositoryProvider))
|
||||
a.id: a.bytes,
|
||||
},
|
||||
targetDpi: targetDpi,
|
||||
|
@ -411,7 +419,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
});
|
||||
},
|
||||
zoomLevel: _zoomLevel,
|
||||
fileName: ref.watch(pdfProvider).pickedPdfPath,
|
||||
fileName: ref.watch(documentRepositoryProvider).pickedPdfPath,
|
||||
showPagesSidebar: _showPagesSidebar,
|
||||
showSignaturesSidebar: _showSignaturesSidebar,
|
||||
onTogglePagesSidebar:
|
||||
|
|
|
@ -55,7 +55,7 @@ class _PdfToolbarState extends ConsumerState<PdfToolbar> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pdf = ref.watch(pdfProvider);
|
||||
final pdf = ref.watch(documentRepositoryProvider);
|
||||
final l = AppLocalizations.of(context);
|
||||
final pageInfo = l.pageInfo(pdf.currentPage, pdf.pageCount);
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ 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:pdf_signature/data/model/model.dart' as model;
|
||||
import 'package:pdf_signature/domain/models/model.dart' as model;
|
||||
|
||||
import '../../../../data/services/export_providers.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'image_editor_dialog.dart';
|
||||
import '../../signature/widgets/signature_card.dart';
|
||||
|
||||
|
@ -37,7 +37,7 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
|||
final sig = ref.watch(signatureProvider);
|
||||
final processed = ref.watch(processedSignatureImageProvider);
|
||||
final bytes = processed ?? sig.imageBytes;
|
||||
final library = ref.watch(signatureLibraryProvider);
|
||||
final library = ref.watch(signatureAssetRepositoryProvider);
|
||||
final isExporting = ref.watch(exportingProvider);
|
||||
final disabled = widget.disabled || isExporting;
|
||||
|
||||
|
@ -64,7 +64,7 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
|||
disabled: disabled,
|
||||
onDelete:
|
||||
() => ref
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.remove(a.id),
|
||||
onAdjust: () async {
|
||||
ref
|
||||
|
@ -151,10 +151,16 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
|||
ref.read(signatureProvider).imageBytes;
|
||||
if (b != null) {
|
||||
final id = ref
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(
|
||||
signatureAssetRepositoryProvider
|
||||
.notifier,
|
||||
)
|
||||
.add(b, name: 'image');
|
||||
final asset = ref
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(
|
||||
signatureAssetRepositoryProvider
|
||||
.notifier,
|
||||
)
|
||||
.byId(id);
|
||||
if (asset != null) {
|
||||
ref
|
||||
|
@ -179,10 +185,16 @@ class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
|||
ref.read(signatureProvider).imageBytes;
|
||||
if (b != null) {
|
||||
final id = ref
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(
|
||||
signatureAssetRepositoryProvider
|
||||
.notifier,
|
||||
)
|
||||
.add(b, name: 'drawing');
|
||||
final asset = ref
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(
|
||||
signatureAssetRepositoryProvider
|
||||
.notifier,
|
||||
)
|
||||
.byId(id);
|
||||
if (asset != null) {
|
||||
ref
|
||||
|
|
|
@ -4,10 +4,10 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
|
||||
import '../../../../data/model/model.dart';
|
||||
import '../../../../domain/models/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'image_editor_dialog.dart';
|
||||
import '../../signature/widgets/rotated_signature_image.dart';
|
||||
|
||||
|
@ -19,7 +19,6 @@ class SignatureOverlay extends ConsumerWidget {
|
|||
required this.rect,
|
||||
required this.sig,
|
||||
required this.pageNumber,
|
||||
this.interactive = true,
|
||||
this.placedIndex,
|
||||
this.onDragSignature,
|
||||
this.onResizeSignature,
|
||||
|
@ -30,9 +29,8 @@ class SignatureOverlay extends ConsumerWidget {
|
|||
|
||||
final Size pageSize;
|
||||
final Rect rect;
|
||||
final SignatureState sig;
|
||||
final SignatureCard sig;
|
||||
final int pageNumber;
|
||||
final bool interactive;
|
||||
final int? placedIndex;
|
||||
|
||||
// Callbacks used by interactive overlay
|
||||
|
@ -75,7 +73,8 @@ class SignatureOverlay extends ConsumerWidget {
|
|||
double scaleX,
|
||||
double scaleY,
|
||||
) {
|
||||
final selectedIdx = ref.read(pdfProvider).selectedPlacementIndex;
|
||||
final selectedIdx =
|
||||
ref.read(documentRepositoryProvider).selectedPlacementIndex;
|
||||
final bool isPlaced = placedIndex != null;
|
||||
final bool isSelected = isPlaced && selectedIdx == placedIndex;
|
||||
final Color borderColor = isPlaced ? Colors.red : Colors.indigo;
|
||||
|
@ -92,7 +91,7 @@ class SignatureOverlay extends ConsumerWidget {
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
0.05 + math.min(0.25, (sig.contrast - 1.0).abs()),
|
||||
0.05 + math.min(0.25, (sig.graphicAdjust.contrast - 1.0).abs()),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -210,7 +209,7 @@ class SignatureOverlay extends ConsumerWidget {
|
|||
onClearActiveOverlay?.call();
|
||||
} else {
|
||||
ref
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.removePlacement(page: pageNumber, index: placedIndex);
|
||||
}
|
||||
} else if (choice == 'adjust') {
|
||||
|
@ -231,23 +230,24 @@ class _SignatureImage extends ConsumerWidget {
|
|||
final bool interactive;
|
||||
final int? placedIndex;
|
||||
final int pageNumber;
|
||||
final SignatureState sig;
|
||||
final SignatureCard sig;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
Uint8List? bytes;
|
||||
if (interactive) {
|
||||
final processed = ref.watch(processedSignatureImageProvider);
|
||||
bytes = processed ?? sig.imageBytes;
|
||||
bytes = processed ?? sig.asset.bytes;
|
||||
} else if (placedIndex != null) {
|
||||
final placementList = ref.read(pdfProvider).placementsByPage[pageNumber];
|
||||
final placementList =
|
||||
ref.read(documentRepositoryProvider).placementsByPage[pageNumber];
|
||||
final placement =
|
||||
(placementList != null && placedIndex! < placementList.length)
|
||||
? placementList[placedIndex!]
|
||||
: null;
|
||||
final imgId = (placement?.asset)?.id;
|
||||
if (imgId != null && imgId.isNotEmpty) {
|
||||
final lib = ref.watch(signatureLibraryProvider);
|
||||
final lib = ref.watch(signatureAssetRepositoryProvider);
|
||||
for (final a in lib) {
|
||||
if (a.id == imgId) {
|
||||
bytes = a.bytes;
|
||||
|
@ -255,7 +255,7 @@ class _SignatureImage extends ConsumerWidget {
|
|||
}
|
||||
}
|
||||
}
|
||||
bytes ??= ref.read(processedSignatureImageProvider) ?? sig.imageBytes;
|
||||
bytes ??= ref.read(processedSignatureImageProvider) ?? sig.asset.bytes;
|
||||
}
|
||||
|
||||
if (bytes == null) {
|
||||
|
@ -271,9 +271,10 @@ class _SignatureImage extends ConsumerWidget {
|
|||
// Use live rotation for interactive overlay; stored rotation for placed
|
||||
double rotationDeg = 0.0;
|
||||
if (interactive) {
|
||||
rotationDeg = sig.rotation;
|
||||
rotationDeg = sig.rotationDeg;
|
||||
} else if (placedIndex != null) {
|
||||
final placementList = ref.read(pdfProvider).placementsByPage[pageNumber];
|
||||
final placementList =
|
||||
ref.read(documentRepositoryProvider).placementsByPage[pageNumber];
|
||||
if (placementList != null && placedIndex! < placementList.length) {
|
||||
rotationDeg = placementList[placedIndex!].rotationDeg;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import 'signature_drag_data.dart';
|
||||
import 'rotated_signature_image.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
|
||||
class SignatureDragData {
|
||||
final SignatureAsset? asset; // null means use current processed signature
|
||||
|
|
|
@ -50,7 +50,9 @@ Future<void> handleDroppedFiles(
|
|||
bytes = null;
|
||||
}
|
||||
final String path = pdf.path ?? pdf.name;
|
||||
read(pdfProvider.notifier).openPicked(path: path, bytes: bytes);
|
||||
read(
|
||||
documentRepositoryProvider.notifier,
|
||||
).openPicked(path: path, bytes: bytes);
|
||||
read(signatureProvider.notifier).resetForNewPage();
|
||||
}
|
||||
|
||||
|
@ -74,7 +76,9 @@ class _WelcomeScreenState extends ConsumerState<WelcomeScreen> {
|
|||
} catch (_) {
|
||||
bytes = null;
|
||||
}
|
||||
ref.read(pdfProvider.notifier).openPicked(path: file.path, bytes: bytes);
|
||||
ref
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: file.path, bytes: bytes);
|
||||
ref.read(signatureProvider.notifier).resetForNewPage();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,11 @@ dependencies:
|
|||
flutter_localized_locales: ^2.0.5
|
||||
desktop_drop: ^0.5.0
|
||||
multi_split_view: ^3.6.1
|
||||
freezed_annotation: ^3.1.0
|
||||
json_annotation: ^4.9.0
|
||||
share_plus: ^11.1.0
|
||||
logging: ^1.3.0
|
||||
riverpod_annotation: ^2.6.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -61,6 +66,8 @@ dev_dependencies:
|
|||
build_runner: ^2.4.12
|
||||
build: ^3.0.2
|
||||
bdd_widget_test: ^2.0.1
|
||||
mocktail: ^1.0.4
|
||||
freezed: ^3.0.0
|
||||
custom_lint: ^0.7.6
|
||||
riverpod_lint: ^2.6.5
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a created signature card
|
||||
|
@ -15,5 +15,5 @@ Future<void> aCreatedSignatureCard(WidgetTester tester) async {
|
|||
bytes: Uint8List(100),
|
||||
name: 'Test Card',
|
||||
);
|
||||
container.read(signatureLibraryProvider.notifier).state = [asset];
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [asset];
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a document is open and contains at least one signature placement
|
||||
|
@ -13,10 +13,10 @@ Future<void> aDocumentIsOpenAndContainsAtLeastOneSignaturePlacement(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'test.pdf', pageCount: 5);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 1,
|
||||
rect: Rect.fromLTWH(10, 10, 100, 50),
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a document is open and contains multiple placed signature placements across pages
|
||||
|
@ -14,24 +14,24 @@ aDocumentIsOpenAndContainsMultiplePlacedSignaturePlacementsAcrossPages(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'multi.pdf', pageCount: 5);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 1,
|
||||
rect: Rect.fromLTWH(10, 10, 100, 50),
|
||||
asset: SignatureAsset(id: 'sig1.png', bytes: Uint8List(0)),
|
||||
);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 2,
|
||||
rect: Rect.fromLTWH(20, 20, 100, 50),
|
||||
asset: SignatureAsset(id: 'sig2.png', bytes: Uint8List(0)),
|
||||
);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 3,
|
||||
rect: Rect.fromLTWH(30, 30, 100, 50),
|
||||
|
|
|
@ -10,7 +10,7 @@ Future<void> aDocumentIsOpenWithNoSignaturePlacementsPlaced(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'empty.pdf', pageCount: 5);
|
||||
// No placements added
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ import '_world.dart';
|
|||
Future<void> aDocumentPageIsSelectedForSigning(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container.read(pdfProvider.notifier).setSignedPage(1);
|
||||
container.read(pdfProvider.notifier).jumpTo(1);
|
||||
container.read(documentRepositoryProvider.notifier).setSignedPage(1);
|
||||
container.read(documentRepositoryProvider.notifier).jumpTo(1);
|
||||
}
|
||||
|
|
|
@ -2,18 +2,23 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a multi-page document is open
|
||||
Future<void> aMultipageDocumentIsOpen(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container.read(signatureLibraryProvider.notifier).state = [];
|
||||
container.read(pdfProvider.notifier).state = PdfState.initial();
|
||||
container.read(signatureProvider.notifier).state = SignatureState.initial();
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [];
|
||||
container.read(documentRepositoryProvider.notifier).state =
|
||||
Document.initial();
|
||||
container.read(signatureCardProvider.notifier).state =
|
||||
SignatureCard.initial();
|
||||
container.read(currentRectProvider.notifier).state = null;
|
||||
container.read(editingEnabledProvider.notifier).state = false;
|
||||
container.read(aspectLockedProvider.notifier).state = false;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ Future<void> aSampleMultipageDocument5PagesIsAvailable(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'sample.pdf', pageCount: 5);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature asset is created
|
||||
|
@ -13,9 +13,9 @@ Future<void> aSignatureAssetIsCreated(WidgetTester tester) async {
|
|||
TestWorld.container = container;
|
||||
|
||||
// Ensure PDF is open
|
||||
if (!container.read(pdfProvider).loaded) {
|
||||
if (!container.read(documentRepositoryProvider).loaded) {
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,12 @@ Future<void> aSignatureAssetIsCreated(WidgetTester tester) async {
|
|||
bytes: Uint8List(100),
|
||||
name: 'Test Asset',
|
||||
);
|
||||
container.read(signatureLibraryProvider.notifier).state = [asset];
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [asset];
|
||||
|
||||
// Place it on the current page
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: pdf.currentPage,
|
||||
rect: Rect.fromLTWH(50, 50, 100, 50),
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature asset is loaded or drawn
|
||||
Future<void> aSignatureAssetIsLoadedOrDrawn(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container.read(signatureLibraryProvider.notifier).state = [];
|
||||
container.read(pdfProvider.notifier).state = PdfState.initial();
|
||||
container.read(signatureProvider.notifier).state = SignatureState.initial();
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [];
|
||||
container.read(documentRepositoryProvider.notifier).state =
|
||||
Document.initial();
|
||||
container.read(signatureCardProvider.notifier).state =
|
||||
SignatureCard.initial();
|
||||
container.read(currentRectProvider.notifier).state = null;
|
||||
container.read(editingEnabledProvider.notifier).state = false;
|
||||
container.read(aspectLockedProvider.notifier).state = false;
|
||||
final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
|
||||
container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(bytes, name: 'test.png');
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature asset is placed on the page
|
||||
|
@ -13,31 +13,31 @@ Future<void> aSignatureAssetIsPlacedOnThePage(WidgetTester tester) async {
|
|||
TestWorld.container = container;
|
||||
|
||||
// Ensure PDF is open
|
||||
if (!container.read(pdfProvider).loaded) {
|
||||
if (!container.read(documentRepositoryProvider).loaded) {
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||
}
|
||||
|
||||
// Get or create an asset
|
||||
var library = container.read(signatureLibraryProvider);
|
||||
var library = container.read(signatureAssetRepositoryProvider);
|
||||
SignatureAsset asset;
|
||||
if (library.isNotEmpty) {
|
||||
asset = library.first;
|
||||
} else {
|
||||
final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
|
||||
final id = container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(bytes, name: 'test.png');
|
||||
asset = container
|
||||
.read(signatureLibraryProvider)
|
||||
.read(signatureAssetRepositoryProvider)
|
||||
.firstWhere((a) => a.id == id);
|
||||
}
|
||||
|
||||
// Place it on the current page
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: pdf.currentPage,
|
||||
rect: Rect.fromLTWH(50, 50, 100, 50),
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature asset is selected
|
||||
Future<void> aSignatureAssetIsSelected(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
var library = container.read(signatureLibraryProvider);
|
||||
var library = container.read(signatureAssetRepositoryProvider);
|
||||
|
||||
// If library is empty, add a dummy asset
|
||||
if (library.isEmpty) {
|
||||
|
@ -18,9 +18,9 @@ Future<void> aSignatureAssetIsSelected(WidgetTester tester) async {
|
|||
bytes: Uint8List(100),
|
||||
name: 'Selected Asset',
|
||||
);
|
||||
container.read(signatureLibraryProvider.notifier).state = [asset];
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [asset];
|
||||
// Re-read the library
|
||||
library = container.read(signatureLibraryProvider);
|
||||
library = container.read(signatureAssetRepositoryProvider);
|
||||
}
|
||||
|
||||
expect(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature asset loaded or drawn is wrapped in a signature card
|
||||
|
@ -13,11 +13,16 @@ Future<void> aSignatureAssetLoadedOrDrawnIsWrappedInASignatureCard(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container.read(signatureLibraryProvider.notifier).state = [];
|
||||
container.read(pdfProvider.notifier).state = PdfState.initial();
|
||||
container.read(signatureProvider.notifier).state = SignatureState.initial();
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [];
|
||||
container.read(documentRepositoryProvider.notifier).state =
|
||||
Document.initial();
|
||||
container.read(signatureCardProvider.notifier).state =
|
||||
SignatureCard.initial();
|
||||
container.read(currentRectProvider.notifier).state = null;
|
||||
container.read(editingEnabledProvider.notifier).state = false;
|
||||
container.read(aspectLockedProvider.notifier).state = false;
|
||||
final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
|
||||
container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(bytes, name: 'test.png');
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ Future<void> aSignaturePlacementAppearsOnThePageBasedOnTheSignatureCard(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
expect(
|
||||
placements.isNotEmpty,
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature placement is placed on page {2}
|
||||
|
@ -15,7 +15,7 @@ Future<void> aSignaturePlacementIsPlacedOnPage(
|
|||
TestWorld.container = container;
|
||||
final page = param1.toInt();
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: page,
|
||||
rect: Rect.fromLTWH(20, 20, 100, 50),
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: a signature placement is placed with a position and size relative to the page
|
||||
|
@ -12,9 +12,9 @@ Future<void> aSignaturePlacementIsPlacedWithAPositionAndSizeRelativeToThePage(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: pdf.currentPage,
|
||||
rect: Rect.fromLTWH(50, 50, 200, 100),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: adjusting one instance does not affect the others
|
||||
|
@ -9,13 +9,19 @@ Future<void> adjustingOneInstanceDoesNotAffectTheOthers(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final before = container.read(pdfProvider.notifier).placementsOn(2);
|
||||
final before = container
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.placementsOn(2);
|
||||
expect(before.length, greaterThanOrEqualTo(2));
|
||||
final modified = before[0].rect.translate(5, 0).inflate(3);
|
||||
container.read(pdfProvider.notifier).removePlacement(page: 2, index: 0);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.removePlacement(page: 2, index: 0);
|
||||
container
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(page: 2, rect: modified, asset: before[0].asset);
|
||||
final after = container.read(pdfProvider.notifier).placementsOn(2);
|
||||
final after = container
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.placementsOn(2);
|
||||
expect(after.any((p) => p.rect == before[1].rect), isTrue);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ Future<void> adjustingOneOfTheSignaturePlacementsDoesNotAffectTheOthers(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final placements =
|
||||
pdf.placementsByPage.values.expand((list) => list).toList();
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ allPlacedSignaturePlacementsAppearOnTheirCorrespondingPagesInTheOutput(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final totalPlacements = pdf.placementsByPage.values.fold(
|
||||
0,
|
||||
(sum, list) => sum + list.length,
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> bothSignaturePlacementsAreShownOnTheirRespectivePages(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
expect(pdf.placementsByPage[1], isNotEmpty);
|
||||
expect(pdf.placementsByPage[3], isNotEmpty);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:ui';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: dragging or resizing one does not change the other
|
||||
|
@ -10,20 +10,26 @@ Future<void> draggingOrResizingOneDoesNotChangeTheOther(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final list = container.read(pdfProvider.notifier).placementsOn(1);
|
||||
final list = container
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.placementsOn(1);
|
||||
expect(list.length, greaterThanOrEqualTo(2));
|
||||
final before = List<Rect>.from(list.take(2).map((p) => p.rect));
|
||||
// Simulate changing the first only
|
||||
final changed = before[0].inflate(5);
|
||||
container.read(pdfProvider.notifier).removePlacement(page: 1, index: 0);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.removePlacement(page: 1, index: 0);
|
||||
container
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 1,
|
||||
rect: changed,
|
||||
asset: list[1].asset,
|
||||
rotationDeg: list[1].rotationDeg,
|
||||
);
|
||||
final after = container.read(pdfProvider.notifier).placementsOn(1);
|
||||
final after = container
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.placementsOn(1);
|
||||
expect(after.any((p) => p.rect == before[1]), isTrue);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> eachSignaturePlacementCanBeDraggedAndResizedIndependently(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
expect(placements.length, greaterThan(1));
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ Future<void> identicalSignatureInstancesAppearInEachLocation(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final state = container.read(pdfProvider);
|
||||
final state = container.read(documentRepositoryProvider);
|
||||
final p2 = state.placementsByPage[2] ?? const [];
|
||||
final p4 = state.placementsByPage[4] ?? const [];
|
||||
expect(p2.length, greaterThanOrEqualTo(2));
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> identicalSignaturePlacementsAppearInEachLocation(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final allPlacements =
|
||||
pdf.placementsByPage.values.expand((list) => list).toList();
|
||||
final assetIds = allPlacements.map((p) => p.asset.id).toSet();
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> onlyTheSelectedSignaturePlacementIsRemoved(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
expect(placements.length, 2); // Started with 3, removed 1, should have 2
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ Future<void> pageBecomesVisibleInTheScrollArea(
|
|||
) async {
|
||||
final page = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
expect(c.read(pdfProvider).currentPage, page);
|
||||
expect(c.read(documentRepositoryProvider).currentPage, page);
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@ import '_world.dart';
|
|||
Future<void> pageIsDisplayed(WidgetTester tester, num param1) async {
|
||||
final expected = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
expect(c.read(pdfProvider).currentPage, expected);
|
||||
expect(c.read(documentRepositoryProvider).currentPage, expected);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import '_world.dart';
|
|||
/// Usage: resize to fit within bounding box
|
||||
Future<void> resizeToFitWithinBoundingBox(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
|
||||
if (pdf.selectedPlacementIndex != null) {
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
|
|
|
@ -9,7 +9,7 @@ Future<void> signaturePlacementOccursOnTheSelectedPage(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
|
||||
// Check that there's at least one placement on the current page
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the app attempts to load the asset
|
||||
|
@ -8,6 +8,6 @@ Future<void> theAppAttemptsToLoadTheAsset(WidgetTester tester) async {
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
// Simulate attempting to load an asset - for now just ensure library is accessible
|
||||
final library = container.read(signatureLibraryProvider);
|
||||
final library = container.read(signatureAssetRepositoryProvider);
|
||||
expect(library, isNotNull);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the asset is loaded and shown as a signature asset
|
||||
|
@ -7,7 +7,7 @@ Future<void> theAssetIsLoadedAndShownAsASignatureAsset(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final library = container.read(signatureLibraryProvider);
|
||||
final library = container.read(signatureAssetRepositoryProvider);
|
||||
expect(
|
||||
library.isNotEmpty,
|
||||
true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the asset is loaded and shown as a signature card
|
||||
|
@ -7,7 +7,7 @@ Future<void> theAssetIsLoadedAndShownAsASignatureCard(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final library = container.read(signatureLibraryProvider);
|
||||
final library = container.read(signatureAssetRepositoryProvider);
|
||||
expect(
|
||||
library.isNotEmpty,
|
||||
true,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the asset is not added to the document
|
||||
Future<void> theAssetIsNotAddedToTheDocument(WidgetTester tester) async {
|
||||
final container = TestWorld.container!;
|
||||
final library = container.read(signatureLibraryProvider);
|
||||
final library = container.read(signatureAssetRepositoryProvider);
|
||||
expect(
|
||||
library.isEmpty,
|
||||
true,
|
||||
|
|
|
@ -7,7 +7,7 @@ import '_world.dart';
|
|||
Future<void> theDocumentIsOpen(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
expect(pdf.loaded, isTrue);
|
||||
expect(pdf.pageCount, greaterThan(0));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ import '_world.dart';
|
|||
/// Usage: the first page is displayed
|
||||
Future<void> theFirstPageIsDisplayed(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
expect(pdf.currentPage, 1);
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import '_world.dart';
|
|||
Future<void> theGoToInputCannotBeUsed(WidgetTester tester) async {
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
// Not loaded, currentPage should remain 1 even after jump attempt
|
||||
expect(c.read(pdfProvider).loaded, isFalse);
|
||||
final before = c.read(pdfProvider).currentPage;
|
||||
c.read(pdfProvider.notifier).jumpTo(3);
|
||||
final after = c.read(pdfProvider).currentPage;
|
||||
expect(c.read(documentRepositoryProvider).loaded, isFalse);
|
||||
final before = c.read(documentRepositoryProvider).currentPage;
|
||||
c.read(documentRepositoryProvider.notifier).jumpTo(3);
|
||||
final after = c.read(documentRepositoryProvider).currentPage;
|
||||
expect(before, equals(after));
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import '_world.dart';
|
|||
Future<void> theLastPageIsDisplayedPage(WidgetTester tester, num param1) async {
|
||||
final last = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = c.read(pdfProvider);
|
||||
final pdf = c.read(documentRepositoryProvider);
|
||||
expect(pdf.pageCount, last);
|
||||
expect(pdf.currentPage, last);
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ Future<void> theLeftPagesOverviewHighlightsPage(
|
|||
) async {
|
||||
final n = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
expect(c.read(pdfProvider).currentPage, n);
|
||||
expect(c.read(documentRepositoryProvider).currentPage, n);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ Future<void> theOtherSignaturePlacementsRemainUnchanged(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
expect(placements.length, 2); // Should have 2 remaining after deleting 1
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ Future<void> thePageLabelShowsPageOf(
|
|||
final current = param1.toInt();
|
||||
final total = param2.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = c.read(pdfProvider);
|
||||
final pdf = c.read(documentRepositoryProvider);
|
||||
expect(pdf.currentPage, current);
|
||||
expect(pdf.pageCount, total);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ Future<void> theSignaturePlacementIsStampedAtTheExactPdfPageCoordinatesAndSize(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
|
||||
final pdfState = container.read(pdfProvider);
|
||||
final pdfState = container.read(documentRepositoryProvider);
|
||||
|
||||
// Verify PDF is loaded
|
||||
expect(pdfState.loaded, isTrue, reason: 'PDF should be loaded');
|
||||
|
|
|
@ -10,7 +10,7 @@ Future<void> theSignaturePlacementOnPageIsShownOnPage(
|
|||
num param2,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final page = param1.toInt();
|
||||
expect(pdf.placementsByPage[page], isNotEmpty);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ Future<void> theSignaturePlacementOnPageRemains(
|
|||
num param1,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final page = param1.toInt();
|
||||
expect(pdf.placementsByPage[page], isNotEmpty);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> theSignaturePlacementRemainsWithinThePageArea(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
for (final placement in placements) {
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> theSignaturePlacementRotatesAroundItsCenterInRealTime(
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
|
||||
if (pdf.selectedPlacementIndex != null) {
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
|
|
|
@ -10,7 +10,7 @@ Future<void> theSignaturePlacementsAppearOnTheCorrespondingPageInTheOutput(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
|
||||
final pdfState = container.read(pdfProvider);
|
||||
final pdfState = container.read(documentRepositoryProvider);
|
||||
|
||||
// Verify that export was successful
|
||||
expect(
|
||||
|
|
|
@ -6,7 +6,7 @@ import '_world.dart';
|
|||
/// Usage: the size and position update in real time
|
||||
Future<void> theSizeAndPositionUpdateInRealTime(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
|
||||
if (pdf.selectedPlacementIndex != null) {
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
|
|
|
@ -8,7 +8,7 @@ import '_world.dart';
|
|||
Future<void> theUserAttemptsToSave(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final sig = container.read(signatureProvider);
|
||||
// Simulate save attempt: since rect is null, mark flag
|
||||
if (!pdf.loaded || sig.rect == null) {
|
||||
|
|
|
@ -6,11 +6,11 @@ import '_world.dart';
|
|||
/// Usage: the user can move to the next or previous page
|
||||
Future<void> theUserCanMoveToTheNextOrPreviousPage(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdfN = container.read(pdfProvider.notifier);
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdfN = container.read(documentRepositoryProvider.notifier);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
expect(pdf.currentPage, 1);
|
||||
pdfN.jumpTo(2);
|
||||
expect(container.read(pdfProvider).currentPage, 2);
|
||||
expect(container.read(documentRepositoryProvider).currentPage, 2);
|
||||
pdfN.jumpTo(1);
|
||||
expect(container.read(pdfProvider).currentPage, 1);
|
||||
expect(container.read(documentRepositoryProvider).currentPage, 1);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user chooses a image file as a signature asset
|
||||
|
@ -12,6 +12,6 @@ Future<void> theUserChoosesAImageFileAsASignatureAsset(
|
|||
TestWorld.container = container;
|
||||
final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
|
||||
container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(bytes, name: 'chosen.png');
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user chooses a signature asset to created a signature card
|
||||
|
@ -12,6 +12,6 @@ Future<void> theUserChoosesASignatureAssetToCreatedASignatureCard(
|
|||
TestWorld.container = container;
|
||||
final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
|
||||
container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(bytes, name: 'card.png');
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ Future<void> theUserClicksTheGoToApplyButton(WidgetTester tester) async {
|
|||
final c = TestWorld.container ?? ProviderContainer();
|
||||
final pending = TestWorld.pendingGoTo;
|
||||
if (pending != null) {
|
||||
c.read(pdfProvider.notifier).jumpTo(pending);
|
||||
c.read(documentRepositoryProvider.notifier).jumpTo(pending);
|
||||
await tester.pump();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ Future<void> theUserClicksTheThumbnailForPage(
|
|||
) async {
|
||||
final page = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
c.read(pdfProvider.notifier).jumpTo(page);
|
||||
c.read(documentRepositoryProvider.notifier).jumpTo(page);
|
||||
await tester.pump();
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ Future<void> theUserDeletesOneSelectedSignaturePlacement(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
if (pdf.selectedPlacementIndex == null) {
|
||||
container.read(pdfProvider.notifier).selectPlacement(0);
|
||||
container.read(documentRepositoryProvider.notifier).selectPlacement(0);
|
||||
}
|
||||
container.read(pdfProvider.notifier).deleteSelectedPlacement();
|
||||
container.read(documentRepositoryProvider.notifier).deleteSelectedPlacement();
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ Future<void> theUserDragsHandlesToResizeAndDragsToReposition(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdfN = container.read(pdfProvider.notifier);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final pdfN = container.read(documentRepositoryProvider.notifier);
|
||||
|
||||
if (pdf.selectedPlacementIndex != null) {
|
||||
final placements = pdf.placementsByPage[pdf.currentPage] ?? [];
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user drags it on the page of the document to place signature placements in multiple locations in the document
|
||||
|
@ -13,7 +13,7 @@ theUserDragsItOnThePageOfTheDocumentToPlaceSignaturePlacementsInMultipleLocation
|
|||
WidgetTester tester,
|
||||
) async {
|
||||
final container = TestWorld.container!;
|
||||
final lib = container.read(signatureLibraryProvider);
|
||||
final lib = container.read(signatureAssetRepositoryProvider);
|
||||
final asset =
|
||||
lib.isNotEmpty
|
||||
? lib.first
|
||||
|
@ -24,28 +24,28 @@ theUserDragsItOnThePageOfTheDocumentToPlaceSignaturePlacementsInMultipleLocation
|
|||
);
|
||||
|
||||
// Ensure PDF is open
|
||||
if (!container.read(pdfProvider).loaded) {
|
||||
if (!container.read(documentRepositoryProvider).loaded) {
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||
}
|
||||
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 1,
|
||||
rect: Rect.fromLTWH(10, 10, 100, 50),
|
||||
asset: asset,
|
||||
);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 2,
|
||||
rect: Rect.fromLTWH(20, 20, 100, 50),
|
||||
asset: asset,
|
||||
);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 3,
|
||||
rect: Rect.fromLTWH(30, 30, 100, 50),
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user drags this signature card on the page of the document to place a signature placement
|
||||
|
@ -16,31 +16,31 @@ theUserDragsThisSignatureCardOnThePageOfTheDocumentToPlaceASignaturePlacement(
|
|||
TestWorld.container = container;
|
||||
|
||||
// Ensure PDF is open
|
||||
if (!container.read(pdfProvider).loaded) {
|
||||
if (!container.read(documentRepositoryProvider).loaded) {
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||
}
|
||||
|
||||
// Get or create an asset
|
||||
var library = container.read(signatureLibraryProvider);
|
||||
var library = container.read(signatureAssetRepositoryProvider);
|
||||
SignatureAsset asset;
|
||||
if (library.isNotEmpty) {
|
||||
asset = library.first;
|
||||
} else {
|
||||
final bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
|
||||
final id = container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(bytes, name: 'placement.png');
|
||||
asset = container
|
||||
.read(signatureLibraryProvider)
|
||||
.read(signatureAssetRepositoryProvider)
|
||||
.firstWhere((a) => a.id == id);
|
||||
}
|
||||
|
||||
// Place it on the current page
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: pdf.currentPage,
|
||||
rect: Rect.fromLTWH(100, 100, 100, 50),
|
||||
|
|
|
@ -10,6 +10,6 @@ Future<void> theUserEntersIntoTheGoToInputAndAppliesIt(
|
|||
) async {
|
||||
final value = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
c.read(pdfProvider.notifier).jumpTo(value);
|
||||
c.read(documentRepositoryProvider.notifier).jumpTo(value);
|
||||
await tester.pump();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ import '_world.dart';
|
|||
Future<void> theUserJumpsToPage(WidgetTester tester, num param1) async {
|
||||
final page = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
c.read(pdfProvider.notifier).jumpTo(page);
|
||||
c.read(documentRepositoryProvider.notifier).jumpTo(page);
|
||||
await tester.pump();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user navigates to page {5} and places another signature placement
|
||||
|
@ -14,9 +14,9 @@ Future<void> theUserNavigatesToPageAndPlacesAnotherSignaturePlacement(
|
|||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final page = param1.toInt();
|
||||
container.read(pdfProvider.notifier).jumpTo(page);
|
||||
container.read(documentRepositoryProvider.notifier).jumpTo(page);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: page,
|
||||
rect: Rect.fromLTWH(40, 40, 100, 50),
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user places a signature placement from asset <second_asset> on page <second_page>
|
||||
|
@ -15,14 +15,14 @@ Future<void> theUserPlacesASignaturePlacementFromAssetOnPage(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final library = container.read(signatureLibraryProvider);
|
||||
final library = container.read(signatureAssetRepositoryProvider);
|
||||
var asset = library.where((a) => a.name == assetName).firstOrNull;
|
||||
if (asset == null) {
|
||||
// add dummy asset
|
||||
final id = container
|
||||
.read(signatureLibraryProvider.notifier)
|
||||
.read(signatureAssetRepositoryProvider.notifier)
|
||||
.add(Uint8List(0), name: assetName);
|
||||
final updatedLibrary = container.read(signatureLibraryProvider);
|
||||
final updatedLibrary = container.read(signatureAssetRepositoryProvider);
|
||||
asset = updatedLibrary.firstWhere(
|
||||
(a) => a.id == id,
|
||||
orElse:
|
||||
|
@ -30,7 +30,7 @@ Future<void> theUserPlacesASignaturePlacementFromAssetOnPage(
|
|||
);
|
||||
}
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: page,
|
||||
rect: Rect.fromLTWH(10, 10, 50, 50),
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user places a signature placement on page {1}
|
||||
|
@ -15,7 +15,7 @@ Future<void> theUserPlacesASignaturePlacementOnPage(
|
|||
TestWorld.container = container;
|
||||
final page = param1.toInt();
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: page,
|
||||
rect: Rect.fromLTWH(20, 20, 100, 50),
|
||||
|
|
|
@ -10,7 +10,7 @@ Future<void> theUserPlacesItInMultipleLocationsInTheDocument(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final notifier = container.read(pdfProvider.notifier);
|
||||
final notifier = container.read(documentRepositoryProvider.notifier);
|
||||
// Always open a fresh doc to avoid state bleed between scenarios
|
||||
notifier.openPicked(path: 'mock.pdf', pageCount: 6);
|
||||
// Place two on page 2 and one on page 4
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: the user places two signature placements on the same page
|
||||
|
@ -12,10 +12,10 @@ Future<void> theUserPlacesTwoSignaturePlacementsOnTheSamePage(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final page = pdf.currentPage;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: page,
|
||||
rect: Rect.fromLTWH(10, 10, 100, 50),
|
||||
|
@ -26,7 +26,7 @@ Future<void> theUserPlacesTwoSignaturePlacementsOnTheSamePage(
|
|||
),
|
||||
);
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: page,
|
||||
rect: Rect.fromLTWH(120, 10, 100, 50),
|
||||
|
|
|
@ -12,7 +12,7 @@ Future<void> theUserSavesexportsTheDocument(WidgetTester tester) async {
|
|||
TestWorld.container = container;
|
||||
|
||||
// Ensure state looks exportable
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final sig = container.read(signatureProvider);
|
||||
expect(pdf.loaded, isTrue, reason: 'PDF must be loaded before export');
|
||||
// Check if there are placements
|
||||
|
|
|
@ -11,9 +11,9 @@ Future<void> theUserSelects(WidgetTester tester, dynamic file) async {
|
|||
TestWorld.container = container;
|
||||
// Mark page for signing to enable signature ops
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 1);
|
||||
container.read(pdfProvider.notifier).setSignedPage(1);
|
||||
container.read(documentRepositoryProvider.notifier).setSignedPage(1);
|
||||
// For invalid/unsupported/empty selections we do NOT set image bytes.
|
||||
// This simulates a failed load and keeps rect null.
|
||||
final token = file.toString();
|
||||
|
|
|
@ -11,6 +11,6 @@ Future<void> theUserTypesIntoTheGoToInputAndPressesEnter(
|
|||
final target = param1.toInt();
|
||||
final c = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = c;
|
||||
c.read(pdfProvider.notifier).jumpTo(target);
|
||||
c.read(documentRepositoryProvider.notifier).jumpTo(target);
|
||||
await tester.pump();
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import '_world.dart';
|
|||
/// Usage: the user uses rotate controls
|
||||
Future<void> theUserUsesRotateControls(WidgetTester tester) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdfN = container.read(pdfProvider.notifier);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final pdfN = container.read(documentRepositoryProvider.notifier);
|
||||
|
||||
if (pdf.selectedPlacementIndex != null) {
|
||||
// Rotate the selected placement by 45 degrees
|
||||
|
|
|
@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_library_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_asset_repository.dart';
|
||||
import 'package:pdf_signature/data/repositories/signature_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import '_world.dart';
|
||||
|
||||
/// Usage: three signature placements are placed on the current page
|
||||
|
@ -14,14 +14,19 @@ Future<void> threeSignaturePlacementsArePlacedOnTheCurrentPage(
|
|||
) async {
|
||||
final container = TestWorld.container ?? ProviderContainer();
|
||||
TestWorld.container = container;
|
||||
container.read(signatureLibraryProvider.notifier).state = [];
|
||||
container.read(pdfProvider.notifier).state = PdfState.initial();
|
||||
container.read(signatureProvider.notifier).state = SignatureState.initial();
|
||||
container.read(signatureAssetRepositoryProvider.notifier).state = [];
|
||||
container.read(documentRepositoryProvider.notifier).state =
|
||||
Document.initial();
|
||||
container.read(signatureCardProvider.notifier).state =
|
||||
SignatureCard.initial();
|
||||
container.read(currentRectProvider.notifier).state = null;
|
||||
container.read(editingEnabledProvider.notifier).state = false;
|
||||
container.read(aspectLockedProvider.notifier).state = false;
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.openPicked(path: 'mock.pdf', pageCount: 5);
|
||||
final pdfN = container.read(pdfProvider.notifier);
|
||||
final pdf = container.read(pdfProvider);
|
||||
final pdfN = container.read(documentRepositoryProvider.notifier);
|
||||
final pdf = container.read(documentRepositoryProvider);
|
||||
final page = pdf.currentPage;
|
||||
pdfN.addPlacement(
|
||||
page: page,
|
||||
|
|
|
@ -26,8 +26,8 @@ void main() {
|
|||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
pdfProvider.overrideWith(
|
||||
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
||||
documentRepositoryProvider.overrideWith(
|
||||
(ref) => DocumentStateNotifier()..openPicked(path: 'test.pdf'),
|
||||
),
|
||||
signatureProvider.overrideWith(
|
||||
(ref) => SignatureController()..placeDefaultRect(),
|
||||
|
|
|
@ -15,8 +15,8 @@ Future<void> pumpWithOpenPdf(WidgetTester tester) async {
|
|||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
pdfProvider.overrideWith(
|
||||
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
||||
documentRepositoryProvider.overrideWith(
|
||||
(ref) => DocumentStateNotifier()..openPicked(path: 'test.pdf'),
|
||||
),
|
||||
useMockViewerProvider.overrideWith((ref) => true),
|
||||
// Continuous mode is always-on; no page view override needed
|
||||
|
@ -49,8 +49,8 @@ Future<void> pumpWithOpenPdfAndSig(WidgetTester tester) async {
|
|||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
pdfProvider.overrideWith(
|
||||
(ref) => PdfController()..openPicked(path: 'test.pdf'),
|
||||
documentRepositoryProvider.overrideWith(
|
||||
(ref) => DocumentStateNotifier()..openPicked(path: 'test.pdf'),
|
||||
),
|
||||
signatureProvider.overrideWith(
|
||||
(ref) =>
|
||||
|
|
|
@ -4,14 +4,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
|
||||
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
||||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
import 'package:pdf_signature/data/services/export_providers.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
|
||||
class _TestPdfController extends PdfController {
|
||||
class _TestPdfController extends DocumentStateNotifier {
|
||||
_TestPdfController() : super() {
|
||||
// Start with a loaded multi-page doc, page 1 of 5
|
||||
state = PdfState.initial().copyWith(
|
||||
state = Document.initial().copyWith(
|
||||
loaded: true,
|
||||
pageCount: 5,
|
||||
currentPage: 1,
|
||||
|
@ -27,7 +27,9 @@ void main() {
|
|||
ProviderScope(
|
||||
overrides: [
|
||||
useMockViewerProvider.overrideWithValue(true),
|
||||
pdfProvider.overrideWith((ref) => _TestPdfController()),
|
||||
documentRepositoryProvider.overrideWith(
|
||||
(ref) => _TestPdfController(),
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
|
|
|
@ -6,11 +6,11 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart';
|
|||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/services/export_providers.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
|
||||
class _TestPdfController extends PdfController {
|
||||
class _TestPdfController extends DocumentStateNotifier {
|
||||
_TestPdfController() : super() {
|
||||
state = PdfState.initial().copyWith(
|
||||
state = Document.initial().copyWith(
|
||||
loaded: true,
|
||||
pageCount: 6,
|
||||
currentPage: 1,
|
||||
|
@ -30,7 +30,7 @@ void main() {
|
|||
overrides: [
|
||||
useMockViewerProvider.overrideWithValue(true),
|
||||
// Continuous mode is always-on; no page view override needed
|
||||
pdfProvider.overrideWith((ref) => ctrl),
|
||||
documentRepositoryProvider.overrideWith((ref) => ctrl),
|
||||
],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
|
|
|
@ -6,11 +6,11 @@ import 'package:pdf_signature/ui/features/pdf/widgets/pdf_page_area.dart';
|
|||
import 'package:pdf_signature/data/repositories/pdf_repository.dart';
|
||||
import 'package:pdf_signature/data/services/export_providers.dart';
|
||||
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||
import 'package:pdf_signature/data/model/model.dart';
|
||||
import 'package:pdf_signature/domain/models/model.dart';
|
||||
|
||||
class _TestPdfController extends PdfController {
|
||||
class _TestPdfController extends DocumentStateNotifier {
|
||||
_TestPdfController() : super() {
|
||||
state = PdfState.initial().copyWith(
|
||||
state = Document.initial().copyWith(
|
||||
loaded: true,
|
||||
pageCount: 6,
|
||||
currentPage: 2,
|
||||
|
@ -29,7 +29,7 @@ void main() {
|
|||
overrides: [
|
||||
useMockViewerProvider.overrideWithValue(true),
|
||||
// Continuous mode is always-on; no page view override needed
|
||||
pdfProvider.overrideWith((ref) => ctrl),
|
||||
documentRepositoryProvider.overrideWith((ref) => ctrl),
|
||||
],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
|
|
|
@ -53,10 +53,10 @@ void main() {
|
|||
await tester.pumpWidget(buildHarness(width: 480));
|
||||
|
||||
// Open sample and add a normalized placement to page 1
|
||||
container.read(pdfProvider.notifier).openSample();
|
||||
container.read(documentRepositoryProvider.notifier).openSample();
|
||||
// One placement at (25% x, 50% y), size 10% x 10%
|
||||
container
|
||||
.read(pdfProvider.notifier)
|
||||
.read(documentRepositoryProvider.notifier)
|
||||
.addPlacement(
|
||||
page: 1,
|
||||
rect: const Rect.fromLTWH(0.25, 0.50, 0.10, 0.10),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue