anyline-ocr-react-native-module 42.2.0 → 43.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/android/build.gradle +7 -3
  2. package/android/src/main/AndroidManifest.xml +9 -8
  3. package/android/src/main/assets/cow_tag_scanner.ale +46 -0
  4. package/android/src/main/java/com/anyline/reactnative/AnylinePackage.java +1 -2
  5. package/android/src/main/java/com/anyline/reactnative/AnylineSDKPlugin.java +25 -71
  6. package/android/src/main/java/com/anyline/reactnative/RotateButtonConfig.java +12 -2
  7. package/android/src/main/java/com/anyline/reactnative/ScanActivity.java +206 -0
  8. package/android/src/main/res/drawable/rotate_screen_background.xml +18 -0
  9. package/android/src/main/res/drawable/rotate_screen_white.png +0 -0
  10. package/android/src/main/res/layout/activity_scan.xml +27 -0
  11. package/android/src/main/res/values/anyline_sdk_plugin_strings.xml +2 -28
  12. package/ios/ALJsonUIConfiguration.h +29 -36
  13. package/ios/ALJsonUIConfiguration.m +136 -76
  14. package/ios/ALNFCScanViewController.h +3 -16
  15. package/ios/ALNFCScanViewController.m +361 -232
  16. package/ios/ALPluginHelper.h +19 -62
  17. package/ios/ALPluginHelper.m +208 -529
  18. package/ios/ALPluginScanViewController.h +5 -32
  19. package/ios/ALPluginScanViewController.m +339 -287
  20. package/ios/AnylineReact.podspec +4 -3
  21. package/ios/AnylineSDKPlugin.m +39 -82
  22. package/package.json +8 -8
  23. package/android/.gradle/6.7/executionHistory/executionHistory.lock +0 -0
  24. package/android/.gradle/6.7/fileChanges/last-build.bin +0 -0
  25. package/android/.gradle/6.7/fileHashes/fileHashes.bin +0 -0
  26. package/android/.gradle/6.7/fileHashes/fileHashes.lock +0 -0
  27. package/android/.gradle/6.7/gc.properties +0 -0
  28. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  29. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  30. package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  31. package/android/.gradle/checksums/checksums.lock +0 -0
  32. package/android/.gradle/checksums/md5-checksums.bin +0 -0
  33. package/android/.gradle/checksums/sha1-checksums.bin +0 -0
  34. package/android/.gradle/configuration-cache/gc.properties +0 -0
  35. package/android/.gradle/vcs-1/gc.properties +0 -0
  36. package/android/.idea/compiler.xml +0 -6
  37. package/android/.idea/gradle.xml +0 -18
  38. package/android/.idea/jarRepositories.xml +0 -35
  39. package/android/.idea/misc.xml +0 -10
  40. package/android/.idea/vcs.xml +0 -6
  41. package/android/.settings/org.eclipse.buildship.core.prefs +0 -13
  42. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  43. package/android/local.properties +0 -8
  44. package/android/src/main/java/com/anyline/reactnative/Anyline4Activity.java +0 -621
  45. package/android/src/main/java/com/anyline/reactnative/AnylineBaseActivity.java +0 -267
  46. package/android/src/main/java/com/anyline/reactnative/AnylinePluginHelper.java +0 -324
  47. package/android/src/main/java/com/anyline/reactnative/AnylineUIConfig.java +0 -88
  48. package/android/src/main/java/com/anyline/reactnative/Document4Activity.java +0 -595
  49. package/android/src/main/res/layout/activity_scan_document.xml +0 -63
  50. package/android/src/main/res/layout/activity_scan_scanview.xml +0 -52
  51. package/android/src/main/res/values/com_crashlytics_export_strings.xml +0 -10
@@ -1,52 +1,60 @@
1
- //
2
- // ALPluginScanViewController.m
3
- // Anyline React-Native Example
4
- //
5
- // Created by Daniel Albertini on 30.10.18.
6
- //
1
+ #import <Anyline/Anyline.h>
7
2
 
8
3
  #import "ALPluginScanViewController.h"
9
- #import <Anyline/Anyline.h>
10
4
  #import "ALPluginHelper.h"
11
5
  #import "ALRoundedView.h"
12
6
 
7
+ @interface ALPluginScanViewController () <ALScanPluginDelegate, ALViewPluginCompositeDelegate, ALScanViewDelegate>
13
8
 
14
- @interface ALPluginScanViewController ()<ALIDPluginDelegate,ALOCRScanPluginDelegate,ALBarcodeScanPluginDelegate,ALMeterScanPluginDelegate,ALLicensePlateScanPluginDelegate,ALDocumentScanPluginDelegate,AnylineNativeBarcodeDelegate, ALInfoDelegate, ALScanViewPluginDelegate, ALDocumentInfoDelegate, ALCompositeScanPluginDelegate>
9
+ // ACO should it have the `assign` attribute?
10
+ @property (nonatomic, strong) ALPluginCallback callback;
15
11
 
16
- @property (nonatomic, strong) NSDictionary *anylineConfig;
17
- @property (nonatomic, weak) id<ALPluginScanViewControllerDelegate> delegate;
18
- @property (nonatomic, strong) NSString *licensekey;
19
- @property (nonatomic, strong) ALJsonUIConfiguration *uiConfig;
12
+ @property (nonatomic, strong) NSDictionary *config;
20
13
 
21
- @property (nonatomic,strong) UIButton *doneButton;
22
- @property (nonatomic,strong) UILabel *scannedLabel;
14
+ @property (nonatomic, copy) NSString *licenseKey;
23
15
 
24
- @property (nonatomic, strong) UISegmentedControl *segment;
16
+ @property (nonatomic, strong) ALJSONUIConfiguration *uiConfig;
17
+
18
+ @property (nonatomic, strong) ALScanView *scanView;
19
+
20
+ @property (nonatomic, strong) UIButton *doneButton;
21
+
22
+ @property (nonatomic, strong) UILabel *scannedLabel;
25
23
 
26
24
  @property (nonatomic, strong) ALRoundedView *roundedView;
27
- @property (nonatomic, assign) BOOL showingLabel;
28
25
 
29
- @property (nonatomic, strong) ALScanView *scanView;
26
+ @property (nonatomic, strong) UISegmentedControl *segment;
30
27
 
31
28
  @property (nonatomic, strong) NSMutableArray<NSDictionary *> *detectedBarcodes;
32
29
 
30
+ @property (nonatomic, strong) NSLayoutConstraint *labelHorizontalOffsetConstraint;
31
+
32
+ @property (nonatomic, strong) NSLayoutConstraint *labelVerticalOffsetConstraint;
33
+
34
+ /// Applicable to non-composites (otherwise null)
35
+ @property (nonatomic, readonly, nullable) ALPluginConfig *pluginConfig;
36
+
33
37
  @end
34
38
 
39
+
35
40
  @implementation ALPluginScanViewController
36
41
 
37
- - (instancetype)initWithLicensekey:(NSString *)licensekey
38
- configuration:(NSDictionary *)anylineConfig
39
- uiConfiguration:(ALJsonUIConfiguration *)jsonUIConfig
40
- delegate:(id<ALPluginScanViewControllerDelegate>)delegate {
41
- self = [super init];
42
- if(self) {
43
- _licensekey = licensekey;
44
- _delegate = delegate;
45
- _anylineConfig = anylineConfig;
46
- _uiConfig = jsonUIConfig;
42
+ - (void)dealloc {
43
+ // NSLog(@"ACO dealloc ALPluginScanViewController");
44
+ }
45
+
46
+ - (instancetype)initWithLicensekey:(NSString *)licenseKey
47
+ configuration:(NSDictionary *)config
48
+ uiConfiguration:(ALJSONUIConfiguration *)JSONUIConfig
49
+ finished:(ALPluginCallback)callback {
50
+
51
+ if (self = [super init]) {
52
+ _licenseKey = licenseKey;
53
+ _callback = callback;
54
+ _config = config;
55
+ _uiConfig = JSONUIConfig;
47
56
 
48
57
  self.quality = 100;
49
- self.nativeBarcodeEnabled = NO;
50
58
  self.cropAndTransformErrorMessage = @"";
51
59
  }
52
60
  return self;
@@ -56,327 +64,371 @@
56
64
  [super viewDidLoad];
57
65
 
58
66
  NSError *error = nil;
59
-
60
-
61
- [AnylineSDK setupWithLicenseKey:self.licensekey error:&error];
62
- if (error) {
63
- [self.delegate pluginScanViewController:self
64
- didStopScanning:self
65
- error:error];
67
+
68
+ self.view.backgroundColor = [UIColor blackColor];
69
+
70
+ // ACO is there an equivalent place to that of an AppDelegate on which this could be added?
71
+ [AnylineSDK setupWithLicenseKey:self.licenseKey error:&error];
72
+
73
+ if ([self showErrorAlertIfNeeded:error]) {
66
74
  return;
67
75
  }
68
-
69
- self.scanView = [ALScanView scanViewForFrame:self.view.bounds
70
- configDict:self.anylineConfig
71
- delegate:self
72
- error:&error];
73
-
74
- if ([self.scanView.scanViewPlugin isKindOfClass:[ALDocumentScanViewPlugin class]]) {
75
- [(ALDocumentScanViewPlugin *)self.scanView.scanViewPlugin addScanViewPluginDelegate:self];
76
- [((ALDocumentScanViewPlugin *)self.scanView.scanViewPlugin).documentScanPlugin addInfoDelegate:self];
77
-
78
- ((ALDocumentScanViewPlugin *)self.scanView.scanViewPlugin).documentScanPlugin.justDetectCornersIfPossible = NO;
79
- [((ALDocumentScanViewPlugin *)self.scanView.scanViewPlugin) setValue:self forKey:@"tmpOutlineDelegate"];
80
-
81
-
82
- self.roundedView = [ALPluginHelper createRoundedViewForViewController:self];
83
-
84
- self.scanView.cameraConfig = [ALCameraConfig defaultCameraConfig];
85
- }
86
76
 
87
- if ([self.scanView.scanViewPlugin isKindOfClass:[ALBarcodeScanViewPlugin class]] && self.anylineConfig[@"viewPlugin"][@"plugin"][@"barcodePlugin"][@"enablePDF417Parsing"]) {
88
- ((ALBarcodeScanViewPlugin*)self.scanView.scanViewPlugin).barcodeScanPlugin.parsePDF417 = YES;
89
- }
90
-
91
- if(!self.scanView) {
92
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Could not start scanning" message:error.localizedDescription delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
93
- [alert show];
94
-
77
+ self.scanView = [ALScanViewFactory withJSONDictionary:self.config
78
+ delegate:self
79
+ error:&error];
80
+
81
+ if ([self showErrorAlertIfNeeded:error]) {
95
82
  return;
96
83
  }
97
-
98
- [self.scanView startCamera];
99
-
84
+
100
85
  [self.view addSubview:self.scanView];
101
-
102
- if (self.uiConfig.segmentModes && [self.scanView.scanViewPlugin isKindOfClass:[ALMeterScanViewPlugin class]]) {
103
- self.segment = [ALPluginHelper createSegmentForViewController:self
104
- config:self.uiConfig
105
- scanMode:((ALMeterScanViewPlugin *)self.scanView.scanViewPlugin).meterScanPlugin.scanMode];
106
- [(ALMeterScanViewPlugin *)self.scanView.scanViewPlugin addScanViewPluginDelegate:self];
107
- }
108
-
109
-
110
-
111
- if (self.nativeBarcodeEnabled) {
112
- error = nil;
113
- BOOL success = [self.scanView.captureDeviceManager addBarcodeDelegate:self error:&error];
114
-
115
- if(!success) {
116
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Could not start scanning" message:error.localizedDescription delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
117
- [alert show];
118
-
119
- return;
120
- }
121
- }
122
-
86
+
87
+ self.scanView.translatesAutoresizingMaskIntoConstraints = false;
88
+ [self.scanView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
89
+ [self.scanView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
90
+ [self.scanView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
91
+ [self.scanView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
92
+
93
+ self.scanView.supportedNativeBarcodeFormats = self.uiConfig.nativeBarcodeFormats;
94
+ self.scanView.delegate = self;
123
95
  self.detectedBarcodes = [NSMutableArray array];
124
-
96
+
125
97
  self.doneButton = [ALPluginHelper createButtonForViewController:self config:self.uiConfig];
126
-
98
+
127
99
  self.scannedLabel = [ALPluginHelper createLabelForView:self.view];
100
+
101
+ [self configureLabel:self.scannedLabel config:self.uiConfig];
102
+
103
+ [self configureSegmentControl];
104
+ }
105
+
106
+ - (void)viewWillAppear:(BOOL)animated {
107
+ [super viewWillAppear:animated];
108
+ [self.scanView startCamera];
128
109
  }
129
110
 
130
111
  - (void)viewDidAppear:(BOOL)animated {
131
112
  [super viewDidAppear:animated];
132
-
113
+
114
+ // avoid allowing the app to be put to sleep after a long period without touch events
133
115
  [UIApplication sharedApplication].idleTimerDisabled = YES;
134
-
116
+
135
117
  NSError *error;
136
- BOOL success = [self.scanView.scanViewPlugin startAndReturnError:&error];
137
- if(!success) {
138
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Could not start scanning" message:error.localizedDescription delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
139
- [alert show];
140
- }
141
-
142
-
143
- if(self.uiConfig.segmentModes){
144
- self.segment.frame = CGRectMake(self.scanView.scanViewPlugin.cutoutRect.origin.x + self.uiConfig.segmentXPositionOffset/2,
145
- self.scanView.scanViewPlugin.cutoutRect.origin.y + self.uiConfig.segmentYPositionOffset/2,
146
- self.view.frame.size.width - 2*(self.scanView.scanViewPlugin.cutoutRect.origin.x + self.uiConfig.segmentXPositionOffset/2),
147
- self.segment.frame.size.height);
148
- self.segment.hidden = NO;
149
- }
150
-
118
+ [self.scanView.scanViewPlugin startWithError:&error];
119
+ [self showErrorAlertIfNeeded:error];
151
120
  }
152
121
 
153
122
  - (void)viewDidDisappear:(BOOL)animated {
154
123
  [UIApplication sharedApplication].idleTimerDisabled = NO;
124
+ [super viewDidDisappear:animated];
155
125
  }
156
126
 
157
127
  - (BOOL)shouldAutorotate {
158
128
  return NO;
159
129
  }
160
130
 
161
- - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
162
- [self dismissViewControllerAnimated:YES completion:^{
163
- [self.delegate pluginScanViewController:self didStopScanning:self];
164
- }];
165
- }
131
+ /// The segment control contains a list of scan modes each of which, when selected, reloads the scan view with
132
+ /// the appropriate scan mode for the active plugin (keeping everything else the same)
133
+ - (void)configureSegmentControl {
166
134
 
167
- - (void)doneButtonPressed:(id)sender {
168
- [self.scanView.scanViewPlugin stopAndReturnError:nil];
169
- [self dismissViewControllerAnimated:YES completion:^{
170
- [self.delegate pluginScanViewController:self didStopScanning:sender];
171
- }];
172
- }
135
+ NSString *scanMode = [self currentScanMode];
136
+ if (!scanMode) {
137
+ // Do nothing else: our plugin does not support scan modes.
138
+ return;
139
+ }
173
140
 
174
- - (void)segmentChange:(id)sender {
175
- NSString *modeString = self.uiConfig.segmentModes[((UISegmentedControl *)sender).selectedSegmentIndex];
176
- ALScanMode scanMode = [ALPluginHelper scanModeFromString:modeString];
177
- if ([self.scanView.scanViewPlugin isKindOfClass:[ALMeterScanViewPlugin class]]) {
178
- [((ALMeterScanViewPlugin *)self.scanView.scanViewPlugin).meterScanPlugin setScanMode:scanMode error:nil];
141
+ NSLog(@"The scan mode: %@", scanMode);
142
+
143
+ // At this point, you can safely create segment controls.
144
+ if (!self.uiConfig.segmentModes) {
145
+ return;
179
146
  }
180
- }
181
147
 
182
- #pragma mark - ALScanViewPluginDelegate Delegate Methods
148
+ if (![self segmentModesAreValid]) {
149
+ return;
150
+ }
183
151
 
184
- //Update the position and size of the segment control, after cutout has been updated.
185
- - (void)anylineScanViewPlugin:(ALAbstractScanViewPlugin *)anylineScanViewPlugin updatedCutout:(CGRect)cutoutRect {
186
- //Handle Cutout related positions here. E.g. Warning Views/Icons
187
- //SegmentControl is not modified here, because it will move with cutout changes (=> origin.y changes from analog to digital meter scanMode)
188
- }
152
+ // Give it the current scanmode that's initially defined already in the config JSON
153
+ self.segment = [ALPluginHelper createSegmentForViewController:self
154
+ config:self.uiConfig
155
+ initialScanMode:scanMode];
189
156
 
157
+ self.segment.hidden = NO;
158
+ self.segment.translatesAutoresizingMaskIntoConstraints = NO;
159
+ [self.segment.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
160
+ [self.segment.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor
161
+ constant:self.uiConfig.segmentYPositionOffset].active = YES;
190
162
 
191
- #pragma mark - Anyline Result Delegate Methods
192
- - (void)anylineIDScanPlugin:(ALIDScanPlugin * _Nonnull)anylineIDScanPlugin
193
- didFindResult:(ALIDResult * _Nonnull)scanResult {
194
- NSDictionary *dictResult = [ALPluginHelper dictionaryForIDResult:scanResult
195
- detectedBarcodes:self.detectedBarcodes
196
- outline:self.scanView.scanViewPlugin.outline
197
- quality:self.quality];
198
-
199
- [self handleResult:dictResult result:scanResult];
163
+ // NOTE: uncomment this to show the segment full width
164
+ [self.segment.leftAnchor constraintEqualToAnchor:self.view.leftAnchor constant:10].active = YES;
200
165
  }
201
166
 
202
- - (void)anylineOCRScanPlugin:(ALOCRScanPlugin * _Nonnull)anylineOCRScanPlugin
203
- didFindResult:(ALOCRResult * _Nonnull)scanResult {
204
- NSDictionary *dictResult = [ALPluginHelper dictionaryForOCRResult:scanResult
205
- detectedBarcodes:self.detectedBarcodes
206
- outline:self.scanView.scanViewPlugin.outline
207
- quality:self.quality];
208
-
209
- [self handleResult:dictResult result:scanResult];
167
+ - (void)configureLabel:(UILabel *)label config:(ALJSONUIConfiguration *)config {
168
+
169
+ if (config.labelText.length < 1) {
170
+ return;
171
+ }
172
+
173
+ label.alpha = 1;
174
+ label.text = config.labelText;
175
+ label.font = [UIFont fontWithName:@"HelveticaNeue" size:config.labelSize];
176
+ label.textColor = config.labelColor;
177
+ label.translatesAutoresizingMaskIntoConstraints = NO;
178
+
179
+ [label.leftAnchor constraintEqualToAnchor:self.view.leftAnchor constant:10].active = YES;
180
+
181
+ self.labelHorizontalOffsetConstraint = [label.centerXAnchor
182
+ constraintEqualToAnchor:self.view.centerXAnchor constant:0];
183
+ self.labelVerticalOffsetConstraint = [label.bottomAnchor
184
+ constraintEqualToAnchor:self.view.topAnchor
185
+ constant:0];
186
+
187
+ self.labelHorizontalOffsetConstraint.active = YES;
188
+ self.labelVerticalOffsetConstraint.active = YES;
210
189
  }
211
190
 
212
- - (void)anylineBarcodeScanPlugin:(ALBarcodeScanPlugin * _Nonnull)anylineBarcodeScanPlugin
213
- didFindResult:(ALBarcodeResult * _Nonnull)scanResult {
214
- NSDictionary *dictResult = [ALPluginHelper dictionaryForBarcodeResult:scanResult
215
- outline:self.scanView.scanViewPlugin.outline
216
- quality:self.quality];
217
-
218
- [self handleResult:dictResult result:scanResult];
191
+ - (void)handleResult:(id _Nullable)resultObj {
192
+
193
+ NSMutableDictionary *resultDictionary = [NSMutableDictionary dictionaryWithDictionary:resultObj];
194
+
195
+ if (self.detectedBarcodes.count) {
196
+ resultDictionary[@"nativeBarcodesDetected"] = self.detectedBarcodes;
197
+ }
198
+
199
+ // dismiss the view controller, if cancelOnResult for the config is true
200
+ NSObject<ALScanViewPluginBase> *scanViewPluginBase = self.scanView.scanViewPlugin;
201
+ if ([scanViewPluginBase isKindOfClass:ALScanViewPlugin.class]) {
202
+ ALScanViewPlugin *scanViewPlugin = (ALScanViewPlugin *)scanViewPluginBase;
203
+ BOOL cancelOnResult = scanViewPlugin.scanPlugin.scanPluginConfig.cancelOnResult;
204
+ if (cancelOnResult) {
205
+ __weak __block typeof(self) weakSelf = self;
206
+ [self dismissViewControllerAnimated:YES completion:^{
207
+ weakSelf.callback(resultDictionary, nil);
208
+ }];
209
+ }
210
+ } else if ([scanViewPluginBase isKindOfClass:ALViewPluginComposite.class]) {
211
+ // for composites, the cancelOnResult values for each child don't matter
212
+ [self dismissViewControllerAnimated:YES completion:nil];
213
+ self.callback(resultDictionary, nil);
214
+ }
219
215
  }
220
216
 
221
- - (void)anylineMeterScanPlugin:(ALMeterScanPlugin * _Nonnull)anylineMeterScanPlugin
222
- didFindResult:(ALMeterResult * _Nonnull)scanResult {
223
- NSDictionary *dictResult = [ALPluginHelper dictionaryForMeterResult:scanResult
224
- detectedBarcodes:self.detectedBarcodes
225
- outline:self.scanView.scanViewPlugin.outline
226
- quality:self.quality];
227
-
228
- [self handleResult:dictResult result:scanResult];
217
+ // MARK: - ALScanPluginDelegate
218
+
219
+ - (void)scanPlugin:(ALScanPlugin *)scanPlugin resultReceived:(ALScanResult *)scanResult {
220
+
221
+ CGFloat compressionQuality = self.quality / 100.0f;
222
+
223
+ NSMutableDictionary *resultDictMutable = [NSMutableDictionary dictionaryWithDictionary:scanResult.resultDictionary];
224
+
225
+ NSString *imagePath = [ALPluginHelper saveImageToFileSystem:scanResult.croppedImage
226
+ compressionQuality:compressionQuality];
227
+ resultDictMutable[@"imagePath"] = imagePath;
228
+
229
+ imagePath = [ALPluginHelper saveImageToFileSystem:scanResult.fullSizeImage
230
+ compressionQuality:compressionQuality];
231
+
232
+ resultDictMutable[@"fullImagePath"] = imagePath;
233
+
234
+ [self handleResult:resultDictMutable];
229
235
  }
230
236
 
231
- - (void)anylineLicensePlateScanPlugin:(ALLicensePlateScanPlugin * _Nonnull)anylineLicensePlateScanPlugin
232
- didFindResult:(ALLicensePlateResult * _Nonnull)scanResult {
233
- NSDictionary *dictResult = [ALPluginHelper dictionaryForLicensePlateResult:scanResult
234
- detectedBarcodes:self.detectedBarcodes
235
- outline:self.scanView.scanViewPlugin.outline
236
- quality:self.quality];
237
-
238
- [self handleResult:dictResult result:scanResult];
237
+
238
+ // MARK: - ALViewPluginCompositeDelegate
239
+
240
+ - (void)viewPluginComposite:(ALViewPluginComposite *)viewPluginComposite
241
+ allResultsReceived:(NSArray<ALScanResult *> *)scanResults {
242
+ // combine all into an array and create a string version of it.
243
+ NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:scanResults.count];
244
+ CGFloat compressionQuality = self.quality / 100.0f;
245
+
246
+ for (ALScanResult *scanResult in scanResults) {
247
+ NSMutableDictionary *resultDictMutable = [NSMutableDictionary dictionaryWithDictionary:scanResult.resultDictionary];
248
+ NSString *imagePath = [ALPluginHelper saveImageToFileSystem:scanResult.croppedImage
249
+ compressionQuality:compressionQuality];
250
+ resultDictMutable[@"imagePath"] = imagePath;
251
+ imagePath = [ALPluginHelper saveImageToFileSystem:scanResult.fullSizeImage
252
+ compressionQuality:compressionQuality];
253
+ resultDictMutable[@"fullImagePath"] = imagePath;
254
+ results[scanResult.pluginID] = resultDictMutable;
255
+ }
256
+ [self handleResult:results];
239
257
  }
240
258
 
241
- - (void)anylineDocumentScanPlugin:(ALDocumentScanPlugin * _Nonnull)anylineDocumentScanPlugin
242
- hasResult:(UIImage * _Nonnull)transformedImage
243
- fullImage:(UIImage * _Nonnull)fullFrame
244
- documentCorners:(ALSquare * _Nonnull)corners {
245
- NSDictionary *dictResult = [ALPluginHelper dictionaryForTransformedImage:transformedImage
246
- fullFrame:fullFrame
247
- quality:self.quality
248
- detectedBarcodes:self.detectedBarcodes
249
- outline:corners];
250
-
251
- [self handleResult:dictResult result:nil];
259
+ // MARK: - ALScanViewDelegate
260
+
261
+ - (void)scanView:(ALScanView *)scanView updatedCutoutWithPluginID:(NSString *)pluginID frame:(CGRect)frame {
262
+
263
+ if (CGRectIsEmpty(frame)) {
264
+ return;
265
+ }
266
+
267
+ CGFloat xOffset = self.uiConfig.labelXPositionOffset;
268
+ CGFloat yOffset = self.uiConfig.labelYPositionOffset;
269
+
270
+ // takes into account that frame reported for a cutout is in relation to
271
+ // its scan view's coordinate system
272
+ yOffset += [self.scanView convertRect:frame toView:self.scanView.superview].origin.y;
273
+
274
+ self.labelHorizontalOffsetConstraint.constant = xOffset;
275
+
276
+ self.labelVerticalOffsetConstraint.constant = yOffset;
252
277
  }
253
278
 
254
- - (void)anylineCompositeScanPlugin:(ALAbstractScanViewPluginComposite *)anylineCompositeScanPlugin
255
- didFindResult:(ALCompositeResult *)scanResult {
256
- NSDictionary *dictResult = [ALPluginHelper dictionaryForCompositeResult:scanResult
257
- detectedBarcodes:self.detectedBarcodes
258
- quality:self.quality];
259
-
260
- [self handleResult:dictResult result:nil];
261
-
279
+ - (void)scanView:(ALScanView *)scanView didReceiveNativeBarcodeResult:(ALScanResult *)scanResult {
280
+ // for this implementation we just take the last detected (we can show a list of it)
281
+ [self.detectedBarcodes removeAllObjects];
282
+ [self.detectedBarcodes addObject:scanResult.resultDictionary];
262
283
  }
263
284
 
264
- - (void)anylineTireScanPlugin:(ALTireScanPlugin * _Nonnull)anylineTireScanPlugin
265
- didFindResult:(ALTireResult * _Nonnull)scanResult {
266
- NSDictionary *dictResult = [ALPluginHelper dictionaryForTireResult:scanResult
267
- quality:self.quality];
268
-
269
- [self handleResult:dictResult result:scanResult];
285
+ // MARK: - Getters and Setters
286
+
287
+ - (ALPluginConfig * _Nullable)pluginConfig {
288
+ // applic. only to non-composites
289
+ NSObject<ALScanViewPluginBase> *scanVwPluginBase = self.scanView.scanViewPlugin;
290
+ if ([scanVwPluginBase isKindOfClass:ALScanViewPlugin.class]) {
291
+ return ((ALScanViewPlugin *)scanVwPluginBase).scanPlugin.scanPluginConfig.pluginConfig;
292
+ }
293
+ return nil;
270
294
  }
271
295
 
272
- - (void)anylineCaptureDeviceManager:(ALCaptureDeviceManager * _Nonnull)captureDeviceManager
273
- didFindBarcodeResult:(NSString * _Nonnull)scanResult
274
- type:(NSString * _Nonnull)barcodeType {
275
- [self.detectedBarcodes addObject:[ALPluginHelper dictionaryForBarcodeResults:self.detectedBarcodes
276
- barcodeType:barcodeType
277
- scanResult:scanResult]];
296
+ // MARK: - Selector Actions
297
+
298
+ - (void)doneButtonPressed:(id)sender {
299
+ [self.scanView.scanViewPlugin stop];
300
+
301
+ __weak __block typeof(self) weakSelf = self;
302
+ [self dismissViewControllerAnimated:YES completion:^{
303
+ weakSelf.callback(nil, @"Canceled");
304
+ }];
278
305
  }
279
306
 
280
- /*
281
- This method receives errors that occured during the scan.
282
- */
283
- -(void)anylineDocumentScanPlugin:(ALDocumentScanPlugin *)anylineDocumentScanPlugin reportsPictureProcessingFailure:(ALDocumentError)error {
284
- [self showUserLabel:error];
307
+ - (void)segmentChange:(id)sender {
308
+ NSString *newMode = self.uiConfig.segmentModes[((UISegmentedControl *)sender).selectedSegmentIndex];
309
+ [self updateScanModeWithValue:newMode];
285
310
  }
286
311
 
287
- /*
288
- This method receives errors that occured during the scan.
289
- */
312
+ // MARK: - Handle scan mode switching
290
313
 
291
- -(void)anylineDocumentScanPlugin:(ALDocumentScanPlugin *)anylineDocumentScanPlugin reportsPreviewProcessingFailure:(ALDocumentError)error {
292
- [self showUserLabel:error];
293
- }
294
- - (void)anylineScanPlugin:(ALAbstractScanPlugin * _Nonnull)anylineScanPlugin
295
- runSkipped:(ALRunSkippedReason * _Nonnull)runSkippedReason {
296
-
297
- switch (runSkippedReason.reason) {
298
- case ALRunFailurePointsOutOfCutout: {
299
- NSLog(@"Failure: points out of bounce");
300
-
301
- self.roundedView.textLabel.text = self.cropAndTransformErrorMessage;
302
-
303
- // Animate the appearance of the label
304
- CGFloat fadeDuration = 1.5;
305
-
306
- // Check for Strict Mode and set it
307
- if( self.showingLabel == 0){
308
- self.showingLabel = 1;
309
- [UIView animateWithDuration:fadeDuration animations:^{
310
- self.roundedView.alpha = 1;
311
- } completion:^(BOOL finished) {
312
- [UIView animateWithDuration:fadeDuration animations:^{
313
- self.roundedView.alpha = 0;
314
- } completion:^(BOOL finished) {
315
- self.showingLabel = 0;
316
- }];
317
- }];
318
- }
319
- break;
320
- }
321
- default:
322
- break;
314
+ - (void)updateScanModeWithValue:(NSString *)modeString {
315
+ ALPluginConfig *pluginConfig = self.pluginConfig;
316
+
317
+ id key = [ALPluginHelper confPropKeyWithScanModeForPluginConfig:pluginConfig];
318
+
319
+ // obj is something like an ALMeterConfig instance, that you can call scanMode: (or setScanMode:) on
320
+ id obj = [self.pluginConfig valueForKey:key];
321
+ NSAssert(obj, @"obj shouldn't be nil!");
322
+
323
+ id scanModeObj = [obj valueForKey:@"scanMode"];
324
+ NSString *newScanMode;
325
+
326
+ // does the equivalent of +[ALConfigMeterScanMode withValue:modeString],
327
+ // (or whatever scan mode object gets evaluated) avoiding warnings:
328
+ // https://stackoverflow.com/a/20058585
329
+ SEL selector = NSSelectorFromString(@"withValue:");
330
+ IMP imp = [[scanModeObj class] methodForSelector:selector];
331
+ NSString *(*func)(id, SEL, NSString *) = (void *)imp;
332
+ newScanMode = func([scanModeObj class], selector, modeString);
333
+
334
+ NSAssert(newScanMode, @"newScanMode is not nil!");
335
+
336
+ // like obj, pluginSubConfig should be the the plugin-specific config object
337
+ // (e.g. ALLicensePlateConfig) which responds to setScanMode:.
338
+ selector = NSSelectorFromString(@"setScanMode:");
339
+ imp = [obj methodForSelector:selector];
340
+ id (*func2)(id, SEL, id) = (void *)imp;
341
+ id pluginSubConfig = func2(obj, selector, newScanMode);
342
+
343
+ [pluginConfig setValue:pluginSubConfig forKey:key];
344
+
345
+ NSError *error;
346
+ BOOL success = [self updatePluginConfig:pluginConfig error:&error];
347
+
348
+ if (!success) {
349
+ // check error
350
+ NSLog(@"there was an error changing the scan mode: %@", error.localizedDescription);
323
351
  }
324
352
  }
325
353
 
326
- - (void)handleResult:(NSDictionary *)dictResult result:(ALScanResult *)scanResult {
327
- if ([scanResult.result isKindOfClass:[NSString class]]) {
328
- self.scannedLabel.text = (NSString *)scanResult.result;
354
+ // assume that pluginConfig carries the updated scanMode or whatever value that you wish to refresh.
355
+ - (BOOL)updatePluginConfig:(ALPluginConfig *)pluginConfig error:(NSError * _Nullable * _Nullable)error {
356
+
357
+ ALScanPluginConfig *scanPluginConfig = [[ALScanPluginConfig alloc] initWithPluginConfig:pluginConfig];
358
+ ALScanViewPluginConfig *origSVPConfig = ((ALScanViewPlugin *)self.scanView.scanViewPlugin).scanViewPluginConfig;
359
+ ALScanViewPluginConfig *scanViewPluginConfig = [ALScanViewPluginConfig withScanPluginConfig:scanPluginConfig
360
+ cutoutConfig:origSVPConfig.cutoutConfig
361
+ scanFeedbackConfig:origSVPConfig.scanFeedbackConfig];
362
+ ALScanViewPlugin *newScanViewPlugin = [[ALScanViewPlugin alloc] initWithConfig:scanViewPluginConfig error:error];
363
+ if (!newScanViewPlugin) {
364
+ return NO;
329
365
  }
330
-
331
- [self.delegate pluginScanViewController:self
332
- didScan:dictResult
333
- continueScanning:!self.scanView.scanViewPlugin.scanViewPluginConfig.cancelOnResult];
334
-
335
- if (self.scanView.scanViewPlugin.scanViewPluginConfig.cancelOnResult) {
336
- [self dismissViewControllerAnimated:YES completion:NULL];
366
+
367
+ newScanViewPlugin.scanPlugin.delegate = self;
368
+
369
+ BOOL success = [self.scanView setScanViewPlugin:newScanViewPlugin error:error];
370
+ if (!success) {
371
+ return NO;
337
372
  }
338
- self.detectedBarcodes = [NSMutableArray array];
373
+
374
+ success = [[self.scanView scanViewPlugin] startWithError:error];
375
+ if (!success) {
376
+ // check error
377
+ return NO;
378
+ }
379
+ return YES;
339
380
  }
340
381
 
341
- - (void)showUserLabel:(ALDocumentError)error {
342
- NSString *helpString = nil;
343
- switch (error) {
344
- case ALDocumentErrorNotSharp:
345
- helpString = @"Document not Sharp";
346
- break;
347
- case ALDocumentErrorSkewTooHigh:
348
- helpString = @"Wrong Perspective";
349
- break;
350
- case ALDocumentErrorImageTooDark:
351
- helpString = @"Too Dark";
352
- break;
353
- case ALDocumentErrorShakeDetected:
354
- helpString = @"Too much shaking";
355
- break;
356
- default:
357
- break;
382
+
383
+ /// If the running plugin supports a scan mode, this returns the string representation of it.
384
+ - (NSString * _Nullable)currentScanMode {
385
+ // Does our running plugin contain a property named something like `XXXConfig`?
386
+ // If yes, is there a `scanMode` inside?
387
+ NSString * _Nullable pluginConfigPropertyWithScanMode = [ALPluginHelper confPropKeyWithScanModeForPluginConfig:self.pluginConfig];
388
+ if (!pluginConfigPropertyWithScanMode) {
389
+ return nil;
358
390
  }
359
-
360
- // The error is not in the list above or a label is on screen at the moment
361
- if(!helpString || self.showingLabel) {
362
- return;
391
+ // obj is something like an ALMeterConfig instance
392
+ id obj = [self.pluginConfig valueForKey:pluginConfigPropertyWithScanMode];
393
+ NSAssert(obj, @"obj shouldn't be nil!");
394
+ id scanModeObj = [obj valueForKey:@"scanMode"];
395
+ return [scanModeObj valueForKey:@"value"];
396
+ }
397
+
398
+ // Check whether the scan modes indicated in options > segmentConfig are valid.
399
+ // Otherwise, the segment control is not shown.
400
+ - (BOOL)segmentModesAreValid {
401
+ if (self.uiConfig.segmentModes.count < 1) {
402
+ return NO;
363
403
  }
364
-
365
- self.showingLabel = YES;
366
- self.roundedView.textLabel.text = helpString;
367
-
368
-
369
- // Animate the appearance of the label
370
- CGFloat fadeDuration = 0.8;
371
- [UIView animateWithDuration:fadeDuration animations:^{
372
- self.roundedView.alpha = 1;
373
- } completion:^(BOOL finished) {
374
- [UIView animateWithDuration:fadeDuration animations:^{
375
- self.roundedView.alpha = 0;
376
- } completion:^(BOOL finished) {
377
- self.showingLabel = NO;
378
- }];
379
- }];
404
+
405
+ // easy question first: is there an identical number of segModes and segTitles?
406
+ if (self.uiConfig.segmentModes.count != self.uiConfig.segmentTitles.count) {
407
+ NSLog(@"Error: should have the same number of segment modes and segment titles!");
408
+ return NO;
409
+ }
410
+
411
+ NSString *propKey = [ALPluginHelper confPropKeyWithScanModeForPluginConfig:self.pluginConfig];
412
+ id obj = [self.pluginConfig valueForKey:propKey];
413
+ NSAssert(obj, @"obj shouldn't be nil!");
414
+
415
+ // go through each self.segmentMode. Each call below should be non-nil.
416
+ // NOTE: for now (24.01.2023) TIN and Container scanModes should be named in the JSON config
417
+ // in all UPPERCASE (because the schema demands it to be so).
418
+ for (NSString *scanModeStr in self.uiConfig.segmentModes) {
419
+ if (![[[obj scanMode] class] withValue:scanModeStr]) {
420
+ NSLog(@"Error: %@ is not a valid scan mode for the current plugin", scanModeStr);
421
+ return NO;
422
+ }
423
+ }
424
+
425
+ return YES;
426
+ }
427
+
428
+ // MARK: - Miscellaneous
429
+
430
+ - (BOOL)showErrorAlertIfNeeded:(NSError *)error {
431
+ return [ALPluginHelper showErrorAlertIfNeeded:error pluginCallback:self.callback];
380
432
  }
381
433
 
382
434
  @end