session-ios/Session/Signal/OWSQRCodeScanningViewContro...

163 lines
4.2 KiB
Objective-C

//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSQRCodeScanningViewController.h"
#import "OWSBezierPathView.h"
#import "UIColor+OWS.h"
#import "UIView+OWS.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSQRCodeScanningViewController ()
@property (atomic) ZXCapture *capture;
@property (nonatomic) BOOL captureEnabled;
@property (nonatomic) UIView *maskingView;
@property (nonatomic) dispatch_queue_t captureQueue;
@end
#pragma mark -
@implementation OWSQRCodeScanningViewController
- (void)dealloc
{
[self.capture.layer removeFromSuperlayer];
}
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
_captureEnabled = NO;
_captureQueue = dispatch_get_main_queue();
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) {
return self;
}
_captureEnabled = NO;
_captureQueue = dispatch_get_main_queue();
return self;
}
- (void)loadView
{
[super loadView];
OWSBezierPathView *maskingView = [OWSBezierPathView new];
self.maskingView = maskingView;
[maskingView setConfigureShapeLayerBlock:^(CAShapeLayer *layer, CGRect bounds) {
// Add a circular mask
UIBezierPath *path = [UIBezierPath bezierPathWithRect:bounds];
CGFloat margin = ScaleFromIPhone5To7Plus(24.f, 48.f);
CGFloat radius = MIN(bounds.size.width, bounds.size.height) * 0.5f - margin;
// Center the circle's bounding rectangle
CGRect circleRect = CGRectMake(
bounds.size.width * 0.5f - radius, bounds.size.height * 0.5f - radius, radius * 2.f, radius * 2.f);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:circleRect cornerRadius:16.f];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
layer.path = path.CGPath;
layer.fillRule = kCAFillRuleEvenOdd;
layer.fillColor = UIColor.lokiDarkestGray.CGColor;
layer.opacity = 0.32f;
}];
[self.view addSubview:maskingView];
[maskingView ows_autoPinToSuperviewEdges];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.captureEnabled) {
[self startCapture];
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self stopCapture];
}
- (void)viewWillLayoutSubviews
{
self.capture.layer.frame = self.view.bounds;
}
- (void)startCapture
{
self.captureEnabled = YES;
if (!self.capture) {
dispatch_async(self.captureQueue, ^{
self.capture = [[ZXCapture alloc] init];
self.capture.camera = self.capture.back;
self.capture.focusMode = AVCaptureFocusModeContinuousAutoFocus;
self.capture.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
self.capture.layer.frame = self.view.bounds;
[self.view.layer addSublayer:self.capture.layer];
[self.view bringSubviewToFront:self.maskingView];
[self.capture start];
});
});
} else {
[self.capture start];
}
}
- (void)stopCapture
{
self.captureEnabled = NO;
dispatch_async(self.captureQueue, ^{
[self.capture stop];
});
}
- (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result
{
if (!self.captureEnabled) {
return;
}
[self stopCapture];
// Vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
if (self.scanDelegate) {
if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithData:)]) {
OWSLogInfo(@"Scanned Data Code.");
ZXByteArray *byteArray = result.resultMetadata[@(kResultMetadataTypeByteSegments)][0];
NSData *decodedData = [NSData dataWithBytes:byteArray.array length:byteArray.length];
[self.scanDelegate controller:self didDetectQRCodeWithData:decodedData];
}
if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithString:)]) {
OWSLogInfo(@"Scanned String Code.");
[self.scanDelegate controller:self didDetectQRCodeWithString:result.text];
}
}
}
@end
NS_ASSUME_NONNULL_END