diff --git a/.circleci/config.yml b/.circleci/config.yml index 59e440d0..b24fb975 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -124,3 +124,4 @@ workflows: context: - security-tools - circleci + diff --git a/Package.swift b/Package.swift index 7f365176..e01fe64d 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "VGSShowSDK", platforms: [ - .iOS(.v10) + .iOS(.v13) ], products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. diff --git a/Sources/VGSShowSDK/UIElements/VGSImageView/VGSImageViewRepresentable/VGSImageViewRepresentable.swift b/Sources/VGSShowSDK/UIElements/VGSImageView/VGSImageViewRepresentable/VGSImageViewRepresentable.swift new file mode 100644 index 00000000..6531ea9b --- /dev/null +++ b/Sources/VGSShowSDK/UIElements/VGSImageView/VGSImageViewRepresentable/VGSImageViewRepresentable.swift @@ -0,0 +1,92 @@ +// +// VGSImageViewRepresentable.swift +// VGSShowSDK +// +import SwiftUI + +@available(iOS 14.0, *) +/// An object that displays revealed image data. +public struct VGSImageViewRepresentable: VGSViewRepresentableProtocol, VGSViewRepresentableCallbacksProtocol { + weak var vgsShow: VGSShow? + /// Name that will be associated with `VGSImageViewRepresentable` and used as a decoding `contentPath` on request response with revealed data from your organization vault. + var contentPath: String + /// Image content mode, default is `.scaleToFill`. + var imageContentMode: UIView.ContentMode = .scaleToFill + + // MARK: - VGSImageViewRepresentable interaction callbacks + /// Tells when Image View content did changed. + var onContentDidChange: (() -> Void)? + /// Tells when reveal data operation was failed for the Image View. + /// - Parameter error: `VGSShowError` object. + var onRevealError: ((VGSShowError) -> Void)? + + // MARK: - Initialization + /// Initialization + /// + /// - Parameters: + /// - contentPath: `String` path in reveal request response with revealed data that should be displayed in VGSImageViewRepresentable . + public init(vgsShow: VGSShow, contentPath: String) { + self.vgsShow = vgsShow + self.contentPath = contentPath + } + + public func makeUIView(context: Context) -> VGSImageView { + let vgsImageView = VGSImageView() + vgsImageView.contentPath = contentPath + vgsImageView.imageContentMode = imageContentMode + vgsShow?.subscribe(vgsImageView) + return vgsImageView + } + + public func updateUIView(_ uiView: VGSImageView, context: Context) { + uiView.imageContentMode = imageContentMode + } + /// Name that will be associated with `VGSImageViewRepresentable` and used as a decoding `contentPath` on request response with revealed data from your organization vault. + public func contentPath(_ path: String) -> VGSImageViewRepresentable { + var newRepresentable = self + newRepresentable.contentPath = path + return newRepresentable + } + /// Set mage content mode, default is `.scaleToFill`. + public func imageContentMode(_ mode: UIView.ContentMode) -> VGSImageViewRepresentable { + var newRepresentable = self + newRepresentable.imageContentMode = mode + return newRepresentable + } + + // MARK: - Handle Image View events + public func onContentDidChange(_ action: (() -> Void)?) -> VGSImageViewRepresentable { + var newRepresentable = self + newRepresentable.onContentDidChange = action + return newRepresentable + } + + /// Tells when reveal image operation was failed for the image view. + /// - action: `VGSShowError` object. + public func onRevealError(_ action: ((VGSShowError) -> Void)?) -> VGSImageViewRepresentable { + var newRepresentable = self + newRepresentable.onRevealError = action + return newRepresentable + } + + // MARK: - Coordinator + public func makeCoordinator() -> Coordinator { + return Coordinator(self) + } + + public class Coordinator: NSObject, VGSImageViewDelegate { + var parent: VGSImageViewRepresentable + + init(_ parent: VGSImageViewRepresentable) { + self.parent = parent + } + + public func imageDidChange(in imageView: VGSImageView) { + parent.onContentDidChange?() + } + + public func imageView(_ imageView: VGSImageView, didFailWithError error: VGSShowError) { + parent.onRevealError?(error) + } + } +} diff --git a/Sources/VGSShowSDK/UIElements/VGSLabel/VGSLabelRepresentable/VGSLabelRepresentable.swift b/Sources/VGSShowSDK/UIElements/VGSLabel/VGSLabelRepresentable/VGSLabelRepresentable.swift new file mode 100644 index 00000000..3d945f8f --- /dev/null +++ b/Sources/VGSShowSDK/UIElements/VGSLabel/VGSLabelRepresentable/VGSLabelRepresentable.swift @@ -0,0 +1,379 @@ +// +// VGSLabelRepresentable.swift +// VGSShowSDK +// + +import SwiftUI + +/// VGSLabelRepresentable Callback handler protocol. +protocol VGSLabelRepresentableCallbacksProtocol: VGSViewRepresentableCallbacksProtocol { + /// Tells when text copy to pasteboard in specific format. + var onCopyText: ((VGSLabel.CopyTextFormat) -> Void)? { get set } +} + +@available(iOS 14.0, *) +/// A View that displays revealed text data. +public struct VGSLabelRepresentable: VGSViewRepresentableProtocol, VGSLabelRepresentableCallbacksProtocol { + weak var vgsShow: VGSShow? + /// Name that will be associated with `VGSLabelRepresentable` and used as a decoding `contentPath` on request response with revealed data from your organization vault. + var contentPath: String + /// Transformation regex to format raw revealed text. + var transformationRegex: VGSTransformationRegex? + /// Placeholder text. + var placeholder: String? + /// Placeholder text styles. + var placeholderStyle: VGSPlaceholderLabelStyle = VGSPlaceholderLabelStyle() + /// `Bool` flag. Apply secure mask if `true`. If secure range is not defined mask all text. Default is `false`. + var isSecureText = false + /// Text Symbol that will replace visible label text character when securing String. Should be one charcter only. Default is `*` symbol. + var secureTextSymbol = "*" + ///`Int` object. Defines range start, should be less or equal to `end` and string length. Default is `nil`. + var secureTextStart: Int? + ///`Int` object. Defines range end, should be greater or equal to `end` and string length. Default is `nil`. + var secureTextEnd: Int? + /// An array of `VGSTextRange` objects to be applied subsequently. + var secureTextRanges = [VGSTextRange]() + + // MARK: - UI Attribute + /// `UIEdgeInsets` for text. **IMPORTANT!** Paddings should be non-negative. + var labelPaddings = UIEdgeInsets.zero + /// `UIEdgeInsets` for placeholder. Default is `nil`. If placeholder paddings not set, `paddings` property will be used to control placeholder insets. **IMPORTANT!** Paddings should be non-negative. + var placeholderLabelPaddings: UIEdgeInsets? + /// Field border line color. + var borderColor: UIColor? + /// Field border line width. + var bodrerWidth: CGFloat? + // MARK: - Accessibility Attributes + /// A succinct label in a localized string that + /// identifies the accessibility element. + var vgsAccessibilityLabel: String? + /// A localized string that contains a brief description of the result of + /// performing an action on the accessibility element. + var vgsAccessibilityHint: String? + /// `UIEdgeInsets` for text. **IMPORTANT!** Paddings should be non-negative. + + // MARK: - Font Attributes + /// Indicates whether `VGSLabelRepresentable ` should automatically update its font + /// when the device’s `UIContentSizeCategory` is changed. It only works + /// automatically with dynamic fonts + var vgsAdjustsFontForContentSizeCategory: Bool? + /// `VGSLabelRepresentable` text font. + var font: UIFont? + /// Number of lines. Default is 1. + var numberOfLines: Int = 1 + /// `VGSLabelRepresentable` text color. + var textColor: UIColor? + /// `VGSLabelRepresentable` text alignment. + var textAlignment: NSTextAlignment = .natural + /// `VGSLabelRepresentable` line break mode. + var lineBreakMode: NSLineBreakMode = .byTruncatingTail + /// `VGSLabelRepresentable` minimum text line height. + var textMinLineHeight: CGFloat = 0 + + // MARK: - VGSLabelRepresentable interaction callbacks + /// Tells when reveal data operation was failed for the label. + /// - Parameter error: `VGSShowError` object. + var onRevealError: ((VGSShowError) -> Void)? + /// Tells when label input did changed. + var onContentDidChange: (() -> Void)? + /// Tells when raw text is copied in the specified label. + /// - action: `VGSLabel.CopyTextFormat` object, copied text format. + var onCopyText: ((VGSLabel.CopyTextFormat) -> Void)? + + // MARK: - Initialization + /// Initialization + /// + /// - Parameters: + /// - contentPath: `String` path in reveal request response with revealed data that should be displayed in VGSLabelRepresentable . + public init(vgsShow: VGSShow, contentPath: String) { + self.contentPath = contentPath + self.vgsShow = vgsShow + } + + public func makeUIView(context: Context) -> VGSLabel { + let vgsLabel = VGSLabel() + vgsLabel.delegate = context.coordinator + vgsLabel.font = font + vgsLabel.contentPath = contentPath + vgsLabel.placeholder = placeholder + vgsLabel.placeholderStyle = placeholderStyle + vgsLabel.isSecureText = isSecureText + vgsLabel.secureTextSymbol = secureTextSymbol + vgsLabel.paddings = labelPaddings + vgsLabel.vgsAccessibilityLabel = vgsAccessibilityLabel + vgsLabel.vgsAccessibilityHint = vgsAccessibilityHint + vgsLabel.numberOfLines = numberOfLines + vgsLabel.textAlignment = textAlignment + vgsLabel.lineBreakMode = lineBreakMode + vgsLabel.textMinLineHeight = textMinLineHeight + + if let color = borderColor {vgsLabel.borderColor = color} + if let lineWidth = bodrerWidth {vgsLabel.borderWidth = lineWidth} + + if placeholderLabelPaddings != nil { + vgsLabel.placeholderPaddings = placeholderLabelPaddings + } + if secureTextStart != nil || secureTextEnd != nil { + vgsLabel.setSecureText(start: secureTextStart, end: secureTextEnd) + } + if !secureTextRanges.isEmpty { + vgsLabel.setSecureText(ranges: secureTextRanges) + } + if let adjustsFont = vgsAdjustsFontForContentSizeCategory { + vgsLabel.vgsAdjustsFontForContentSizeCategory = adjustsFont + } + if let txtColor = textColor { + vgsLabel.textColor = txtColor + } + + if let regex = transformationRegex { + vgsLabel.textFormattersContainer.addTransformationRegex(regex) + } + vgsShow?.subscribe(vgsLabel) + return vgsLabel + } + + public func updateUIView(_ uiView: VGSLabel, context: Context) { + uiView.font = font + uiView.placeholder = placeholder + uiView.placeholderStyle = placeholderStyle + uiView.isSecureText = isSecureText + uiView.secureTextSymbol = secureTextSymbol + uiView.paddings = labelPaddings + uiView.vgsAccessibilityLabel = vgsAccessibilityLabel + uiView.vgsAccessibilityHint = vgsAccessibilityHint + uiView.numberOfLines = numberOfLines + uiView.textAlignment = textAlignment + uiView.lineBreakMode = lineBreakMode + uiView.textMinLineHeight = textMinLineHeight + + if let color = borderColor {uiView.borderColor = color} + if let lineWidth = bodrerWidth {uiView.borderWidth = lineWidth} + + if placeholderLabelPaddings != nil { + uiView.placeholderPaddings = placeholderLabelPaddings + } + if secureTextStart != nil || secureTextEnd != nil { + uiView.setSecureText(start: secureTextStart, end: secureTextEnd) + } + if !secureTextRanges.isEmpty { + uiView.setSecureText(ranges: secureTextRanges) + } + if let adjustsFont = vgsAdjustsFontForContentSizeCategory { + uiView.vgsAdjustsFontForContentSizeCategory = adjustsFont + } + if let txtColor = textColor { + uiView.textColor = txtColor + } + + if let regex = transformationRegex { + uiView.textFormattersContainer.addTransformationRegex(regex) + } + } + + /// Add transformation regex to format raw revealed text. + /// - Parameters: + /// - regex: `NSRegularExpression` object, transformation regex. + /// - template: `String` object, template for replacement. + public func addTransformationRegex(_ regex: NSRegularExpression, template: String) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.transformationRegex = VGSTransformationRegex(regex: regex, template: template) + return newRepresentable + } + + /// Name that will be associated with `VGSLabelRepresentable` and used as a decoding `contentPath` on request response with revealed data from your organization vault. + public func contentPath(_ path: String) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.contentPath = path + return newRepresentable + } + + /// Placeholder text. + public func placeholder(_ text: String) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.placeholder = text + return newRepresentable + } + + /// Placeholder text styles. + public func placeholderStyle(_ style: VGSPlaceholderLabelStyle) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.placeholderStyle = style + return newRepresentable + } + + /// `Bool` flag. Apply secure mask if `true`. If secure range is not defined mask all text. Default is `false`. + public func isSecureText(_ isSecure: Bool) -> VGSLabelRepresentable{ + var newRepresentable = self + newRepresentable.isSecureText = isSecure + return newRepresentable + } + + /// Text Symbol that will replace visible label text character when securing String. Should be one charcter only. + public func secureTextSymbol(_ symbol: String) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.secureTextSymbol = secureTextSymbol + return newRepresentable + } + + /// Set text range to be replaced with `VGSLabel.secureTextSymbol`. + /// - Parameters: + /// - start: `Int` object. Defines range start, should be less or equal to `end` and string length. Default is `nil`. + /// - end: `Int` object. Defines range end, should be greater or equal to `end` and string length. Default is `nil`. + public func setSecureText(start: Int? = nil, end: Int? = nil) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.secureTextStart = start + newRepresentable.secureTextEnd = end + + return newRepresentable + } + + /// Set array of text ranges to be replaced with `VGSLabel.secureTextSymbol`. + /// - Parameter ranges: `[VGSTextRange]` object, an array of `VGSTextRange` objects to be applied subsequently. + public func setSecureText(ranges: [VGSTextRange]) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.secureTextRanges = ranges + return newRepresentable + } + + // MARK: - UI Attribute + /// `UIEdgeInsets` for text. **IMPORTANT!** Paddings should be non-negative. + public func labelPaddings(_ paddings: UIEdgeInsets) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.labelPaddings = paddings + return newRepresentable + } + + /// `UIEdgeInsets` for placeholder. Default is `nil`. If placeholder paddings not set, `paddings` property will be used to control placeholder insets. **IMPORTANT!** Paddings should be non-negative. + public func placeholderLabelPaddings(_ paddings: UIEdgeInsets) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.placeholderLabelPaddings = paddings + return newRepresentable + } + + // MARK: - Accessibility Attributes + /// A succinct label in a localized string that + /// identifies the accessibility element. + public func vgsAccessibilityLabel(_ label: String) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.vgsAccessibilityLabel = label + return newRepresentable + } + + /// A localized string that contains a brief description of the result of + /// performing an action on the accessibility element. + public func vgsAccessibilityHint(_ hint: String?) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.vgsAccessibilityHint = hint + return newRepresentable + } + + /// Set `borderColor` and `lineWidth`. + public func border(color: UIColor, lineWidth: CGFloat) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.borderColor = color + newRepresentable.bodrerWidth = lineWidth + return newRepresentable + } + + // MARK: - Font Attributes + /// Indicates whether `VGSLabel ` should automatically update its font + /// when the device’s `UIContentSizeCategory` is changed. It only works + /// automatically with dynamic fonts + public func vgsAdjustsFontForContentSizeCategory(_ adjusts: Bool) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.vgsAdjustsFontForContentSizeCategory = adjusts + return newRepresentable + } + + /// Label text font. By default use default dynamic font style `.body` to update its size + /// automatically when the device’s `UIContentSizeCategory` changed. + public func font(_ font: UIFont) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.font = font + return newRepresentable + } + + /// Number of lines. Default is 1. + public func numberOfLines(_ lines: Int) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.numberOfLines = lines + return newRepresentable + } + + /// Label text color. + public func textColor(_ color: UIColor?) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.textColor = color + return newRepresentable + } + + /// Label text alignment. + public func textAlignment(_ alignment: NSTextAlignment) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.textAlignment = alignment + return newRepresentable + } + + /// Label line break mode. + public func lineBreakMode(_ mode: NSLineBreakMode) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.lineBreakMode = mode + return newRepresentable + } + + // MARK: - Custom text styles + /// Label minimum text line height. + public func textMinLineHeight(_ height: CGFloat) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.textMinLineHeight = height + return newRepresentable + } + + // MARK: - Handle Label events + /// Tells when label text did changed. + public func onContentDidChange(_ action: (() -> Void)?) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.onContentDidChange = action + return newRepresentable + } + /// Tells when raw text is copied in the specified label. + /// - action: `VGSLabel.CopyTextFormat` object, copied text format. + public func onCopyText(_ action: ((VGSLabel.CopyTextFormat) -> Void)?) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.onCopyText = action + return newRepresentable + } + /// Tells when reveal data operation was failed for the label. + /// - action: `VGSShowError` object. + public func onRevealError(_ action: ((VGSShowError) -> Void)?) -> VGSLabelRepresentable { + var newRepresentable = self + newRepresentable.onRevealError = action + return newRepresentable + } + + // MARK: - Coordinator + public func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + public class Coordinator: NSObject, VGSLabelDelegate { + var parent: VGSLabelRepresentable + + init(_ parent: VGSLabelRepresentable) { + self.parent = parent + } + + public func labelTextDidChange(_ label: VGSLabel) { + parent.onContentDidChange?() + } + + public func labelCopyTextDidFinish(_ label: VGSLabel, format: VGSLabel.CopyTextFormat) { + parent.onCopyText?(format) + } + + public func labelRevealDataDidFail(_ label: VGSLabel, error: VGSShowError) { + parent.onRevealError?(error) + } + } +} diff --git a/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFView.swift b/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFView.swift index 2b05bc39..3b9c38a8 100644 --- a/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFView.swift +++ b/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFView.swift @@ -17,14 +17,14 @@ public final class VGSPDFView: UIView, VGSShowPdfViewProtocol { /// The object that acts as the delegate of the `VGSPDFView`. public weak var delegate: VGSPDFViewDelegate? - /// Pdf display mode, default is `.singlePageContinuous`. + /// PDF display mode, default is `.singlePageContinuous`. public var pdfDisplayMode: PDFDisplayMode = PDFDisplayMode.singlePageContinuous { didSet { maskedPdfView.displayMode = pdfDisplayMode } } - /// PDf layout direction, either vertical or horizontal for the given display mode, default is `.vertical`. + /// PDF layout direction, either vertical or horizontal for the given display mode, default is `.vertical`. public var pdfDisplayDirection: PDFDisplayDirection = PDFDisplayDirection.vertical { didSet { maskedPdfView.displayDirection = pdfDisplayDirection @@ -45,7 +45,7 @@ public final class VGSPDFView: UIView, VGSShowPdfViewProtocol { } } - /// Background color of pdf viewer. Default is `gray` with 50% opacity. + /// Background color of PDF viewer. public var pdfBackgroundColor: UIColor? { didSet { maskedPdfView.backgroundColor = pdfBackgroundColor ?? UIColor.gray.withAlphaComponent(0) diff --git a/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFViewRepresentable/VGSPDFViewRepresentable.swift b/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFViewRepresentable/VGSPDFViewRepresentable.swift new file mode 100644 index 00000000..96a9f652 --- /dev/null +++ b/Sources/VGSShowSDK/UIElements/VGSPDFView/VGSPDFViewRepresentable/VGSPDFViewRepresentable.swift @@ -0,0 +1,145 @@ +// +// VGSPDFViewRepresentable.swift +// VGSShowSDK +// + +import SwiftUI +import PDFKit + +@available(iOS 14.0, *) +/// A View that displays revealed PDF data. +public struct VGSPDFViewRepresentable: VGSViewRepresentableProtocol, VGSViewRepresentableCallbacksProtocol { + weak var vgsShow: VGSShow? + /// Name that will be associated with `VGSPDFViewRepresentable` and used as a decoding `contentPath` on request response with revealed data from your organization vault. + var contentPath: String + /// PDF display mode, default is `.singlePageContinuous`. + var pdfDisplayMode: PDFDisplayMode = PDFDisplayMode.singlePageContinuous + /// PDF layout direction, either vertical or horizontal for the given display mode, default is `.vertical`. + var pdfDisplayDirection: PDFDisplayDirection = PDFDisplayDirection.vertical + /// A boolean value indicating whether pdf is autoscaling, default is `true`. + var pdfAutoScales: Bool = true + /// A Boolean value determines whether the view will display the first page as a book cover (meaningful only when the document is in two-up or two-up continuous display mode). + var displayAsBook: Bool = false + /// Background color of PDF viewer. + var pdfBackgroundColor: UIColor = UIColor.gray.withAlphaComponent(0) + /// Determines if shadows should be drawn around page borders in a PDF View, default is `true`. + var pageShadowsEnabled: Bool = true + + // MARK: - VGSPDFViewRepresentable interaction callbacks + /// Tells when PDF View content did changed. + var onContentDidChange: (() -> Void)? + /// Tells when reveal data operation was failed for the PSD View. + /// - Parameter error: `VGSShowError` object. + var onRevealError: ((VGSShowError) -> Void)? + + // MARK: - Initialization + /// Initialization + /// + /// - Parameters: + /// - contentPath: `String` path in reveal request response with revealed data that should be displayed in VGSPDFViewRepresentable . + public init(vgsShow: VGSShow, contentPath: String) { + self.vgsShow = vgsShow + self.contentPath = contentPath + } + + public func makeUIView(context: Context) -> VGSPDFView { + let vgsPDFView = VGSPDFView() + vgsPDFView.contentPath = contentPath + vgsPDFView.pdfDisplayMode = pdfDisplayMode + vgsPDFView.pdfDisplayDirection = pdfDisplayDirection + vgsPDFView.pdfAutoScales = pdfAutoScales + vgsPDFView.displayAsBook = displayAsBook + vgsPDFView.pdfBackgroundColor = pdfBackgroundColor + vgsPDFView.pageShadowsEnabled = pageShadowsEnabled + vgsShow?.subscribe(vgsPDFView) + return vgsPDFView + } + + public func updateUIView(_ uiView: VGSPDFView, context: Context) { + uiView.pdfDisplayMode = pdfDisplayMode + uiView.pdfDisplayDirection = pdfDisplayDirection + uiView.pdfAutoScales = pdfAutoScales + uiView.displayAsBook = displayAsBook + uiView.pdfBackgroundColor = pdfBackgroundColor + uiView.pageShadowsEnabled = pageShadowsEnabled + } + /// Name that will be associated with `VGSPDFViewRepresentable` and used as a decoding `contentPath` on request response with revealed data from your organization vault. + public func contentPath(_ path: String) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.contentPath = path + return newRepresentable + } + /// Set PDF display mode, default is `.singlePageContinuous`. + public func pdfDisplayMode(_ mode: PDFDisplayMode) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.pdfDisplayMode = mode + return newRepresentable + } + /// Set PDF layout direction, either vertical or horizontal for the given display mode, default is `.vertical`. + public func pdfDisplayDirection(_ direction: PDFDisplayDirection) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.pdfDisplayDirection = direction + return newRepresentable + } + /// Set whether pdf is autoscaling, default is `true`. + public func pdfAutoScales(_ scale: Bool) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.pdfAutoScales = scale + return newRepresentable + } + /// Set whether the view will display the first page as a book cover (meaningful only when the document is in two-up or two-up continuous display mode). + public func displayAsBook(_ bookDisplay: Bool) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.displayAsBook = bookDisplay + return newRepresentable + } + /// Set background color of PDF viewer. + public func pdfBackgroundColor(_ color: UIColor) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.pdfBackgroundColor = color + return newRepresentable + } + /// Set if shadows should be drawn around page borders in a PDF View, default is `true`. + public func pageShadowsEnabled(_ enabled: Bool) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.pageShadowsEnabled = enabled + return newRepresentable + } + + // MARK: - Handle PDF View events + /// Tells when PDF View content did changed. + public func onContentDidChange(_ action: (() -> Void)?) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.onContentDidChange = action + return newRepresentable + } + + /// Tells when reveal operation was failed for the PDF View. + /// - action: `VGSShowError` object. + public func onRevealError(_ action: ((VGSShowError) -> Void)?) -> VGSPDFViewRepresentable { + var newRepresentable = self + newRepresentable.onRevealError = action + return newRepresentable + } + + // MARK: - Coordinator + public func makeCoordinator() -> Coordinator { + return Coordinator(self) + } + + public class Coordinator: NSObject, VGSPDFViewDelegate { + var parent: VGSPDFViewRepresentable + + init(_ parent: VGSPDFViewRepresentable) { + self.parent = parent + } + + public func documentDidChange(in pdfView: VGSPDFView) { + parent.onContentDidChange?() + } + + public func pdfView(_ pdfView: VGSPDFView, didFailWithError error: VGSShowError) { + parent.onRevealError?(error) + } + } +} diff --git a/Sources/VGSShowSDK/UIElements/VGSPlaceholderLabelStyle.swift b/Sources/VGSShowSDK/UIElements/VGSPlaceholderLabelStyle.swift index 4b23d1e6..7150b4f6 100644 --- a/Sources/VGSShowSDK/UIElements/VGSPlaceholderLabelStyle.swift +++ b/Sources/VGSShowSDK/UIElements/VGSPlaceholderLabelStyle.swift @@ -15,12 +15,12 @@ public struct VGSPlaceholderLabelStyle { public var color: UIColor = UIColor.gray.withAlphaComponent(0.7) /// Font. - public var font: UIFont? + public var font: UIFont? - /// Indicates whether placeholder should automatically update its font - /// when the device’s `UIContentSizeCategory` is changed. It only works - /// automatically with dynamic fonts - public var adjustsFontForContentSizeCategory: Bool = false + /// Indicates whether placeholder should automatically update its font + /// when the device’s `UIContentSizeCategory` is changed. It only works + /// automatically with dynamic fonts + public var adjustsFontForContentSizeCategory: Bool = false /// Number of lines, default is `1`. public var numberOfLines: Int = 1 @@ -36,4 +36,7 @@ public struct VGSPlaceholderLabelStyle { /// Line break mode. public var lineBreakMode: NSLineBreakMode? + + /// Initialization. + public init(){} } diff --git a/Sources/VGSShowSDK/UIElements/VGSViewRepresentableProtocols/VGSViewRepresentableCallbacksProtocol.swift b/Sources/VGSShowSDK/UIElements/VGSViewRepresentableProtocols/VGSViewRepresentableCallbacksProtocol.swift new file mode 100644 index 00000000..374f1d09 --- /dev/null +++ b/Sources/VGSShowSDK/UIElements/VGSViewRepresentableProtocols/VGSViewRepresentableCallbacksProtocol.swift @@ -0,0 +1,14 @@ +// +// VGSViewRepresentableCallbacksProtocol.swift +// VGSShowSDK +// + +import Foundation + +/// VGSViewRepresentable Callback handler protocol. +protocol VGSViewRepresentableCallbacksProtocol { + /// Tells when VGSViewRepresentable content did changed. + var onContentDidChange: (() -> Void)? { get set } + /// Tells when reveal data operation was failed for the VGSViewRepresentable. + var onRevealError: ((VGSShowError) -> Void)? { get set } +} diff --git a/Sources/VGSShowSDK/UIElements/VGSViewRepresentableProtocols/VGSViewRepresentableProtocol.swift b/Sources/VGSShowSDK/UIElements/VGSViewRepresentableProtocols/VGSViewRepresentableProtocol.swift new file mode 100644 index 00000000..1693c3b6 --- /dev/null +++ b/Sources/VGSShowSDK/UIElements/VGSViewRepresentableProtocols/VGSViewRepresentableProtocol.swift @@ -0,0 +1,16 @@ +// +// VGSViewRepresentableProtocol.swift +// VGSShowSDK +// + +import Foundation +import SwiftUI + +@available(iOS 14.0, *) +/// VGS View Representable protocol. +protocol VGSViewRepresentableProtocol: UIViewRepresentable { + /// `String` path in reveal request response with revealed data that should be displayed in VGS View Representable . + var contentPath: String { get } + + var vgsShow: VGSShow? { get } +} diff --git a/Sources/VGSShowSDK/Utils/Helpers/VGSUtils.swift b/Sources/VGSShowSDK/Utils/Helpers/VGSUtils.swift index 2c629747..be55562a 100644 --- a/Sources/VGSShowSDK/Utils/Helpers/VGSUtils.swift +++ b/Sources/VGSShowSDK/Utils/Helpers/VGSUtils.swift @@ -22,5 +22,5 @@ internal class Utils { /// VGS Show SDK Version. /// Necessary since SPM doesn't track info plist correctly: https://forums.swift.org/t/add-info-plist-on-spm-bundle/40274/5 - static let vgsShowVersion = "1.1.7" + static let vgsShowVersion = "1.2.0" } diff --git a/Tests/VGSShowSDKTests/UIElements/VGSAttributedLabelTests.swift b/Tests/VGSShowSDKTests/UIElements/VGSAttributedLabelTests.swift index 26a9aef0..0d7e5495 100644 --- a/Tests/VGSShowSDKTests/UIElements/VGSAttributedLabelTests.swift +++ b/Tests/VGSShowSDKTests/UIElements/VGSAttributedLabelTests.swift @@ -28,7 +28,14 @@ class VGSAttributedLabelTests: XCTestCase { } func testApplyPlaceholderStyle() { - let style = VGSPlaceholderLabelStyle(color: .red, font: .systemFont(ofSize: 12), numberOfLines: 1, textAlignment: .center, characterSpacing: 2.0, textMinLineHeight: 20, lineBreakMode: .byTruncatingTail) + var style = VGSPlaceholderLabelStyle() + style.color = UIColor.red + style.font = UIFont.systemFont(ofSize: 12) + style.numberOfLines = 1 + style.textAlignment = NSTextAlignment.center + style.characterSpacing = 2.0 + style.textMinLineHeight = 20.0 + style.lineBreakMode = NSLineBreakMode.byTruncatingTail attributedLabel.applyPlaceholderStyle(style) XCTAssertEqual(attributedLabel.textColor, style.color) diff --git a/VGSShowDemoApp/Podfile b/VGSShowDemoApp/Podfile index c00d8ea5..7eead69a 100644 --- a/VGSShowDemoApp/Podfile +++ b/VGSShowDemoApp/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -# platform :ios, '10.0' +# platform :ios, '13.0' source 'https://github.com/CocoaPods/Specs.git' @@ -9,7 +9,7 @@ target 'VGSShowDemoApp' do # Pods for VGSShowDemoApp - pod 'VGSCollectSDK' + pod 'VGSCollectSDK', '1.16.0' pod 'VGSShowSDK', :path => "../" diff --git a/VGSShowDemoApp/VGSShowDemoApp.xcodeproj/project.pbxproj b/VGSShowDemoApp/VGSShowDemoApp.xcodeproj/project.pbxproj index a9bd316b..3b6fba8a 100644 --- a/VGSShowDemoApp/VGSShowDemoApp.xcodeproj/project.pbxproj +++ b/VGSShowDemoApp/VGSShowDemoApp.xcodeproj/project.pbxproj @@ -3,10 +3,15 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ + 034C25CD2B9F4A64004065D9 /* ShowCardDataSwiftUIHostingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 034C25CC2B9F4A64004065D9 /* ShowCardDataSwiftUIHostingVC.swift */; }; + 034C25CF2B9F4ABC004065D9 /* ShowCardDataSwiftUIDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 034C25CE2B9F4ABC004065D9 /* ShowCardDataSwiftUIDemo.swift */; }; + 034C25D12B9F5112004065D9 /* ShowCardDataSwiftUI.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 034C25D02B9F5112004065D9 /* ShowCardDataSwiftUI.storyboard */; }; + 034C26042BA333A1004065D9 /* CardDataCollectionSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 034C26022BA333A1004065D9 /* CardDataCollectionSwiftUI.swift */; }; + 034C26052BA333A1004065D9 /* CollectCardDataSwiftUIHostingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 034C26032BA333A1004065D9 /* CollectCardDataSwiftUIHostingVC.swift */; }; 44014794256641A500A3627B /* UIFont+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44014793256641A500A3627B /* UIFont+Extensions.swift */; }; 4409318F25B6B95300CAF065 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4409318E25B6B95300CAF065 /* UIColor+Extensions.swift */; }; 440CE9F826398B7900FE6B17 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 440CE9F726398B7900FE6B17 /* README.md */; }; @@ -72,6 +77,11 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 034C25CC2B9F4A64004065D9 /* ShowCardDataSwiftUIHostingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowCardDataSwiftUIHostingVC.swift; sourceTree = ""; }; + 034C25CE2B9F4ABC004065D9 /* ShowCardDataSwiftUIDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowCardDataSwiftUIDemo.swift; sourceTree = ""; }; + 034C25D02B9F5112004065D9 /* ShowCardDataSwiftUI.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ShowCardDataSwiftUI.storyboard; sourceTree = ""; }; + 034C26022BA333A1004065D9 /* CardDataCollectionSwiftUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardDataCollectionSwiftUI.swift; sourceTree = ""; }; + 034C26032BA333A1004065D9 /* CollectCardDataSwiftUIHostingVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectCardDataSwiftUIHostingVC.swift; sourceTree = ""; }; 44014793256641A500A3627B /* UIFont+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Extensions.swift"; sourceTree = ""; }; 4409318E25B6B95300CAF065 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; 440CE9F726398B7900FE6B17 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -140,6 +150,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 034C25CB2B9F473B004065D9 /* SwiftUI */ = { + isa = PBXGroup; + children = ( + 034C25CC2B9F4A64004065D9 /* ShowCardDataSwiftUIHostingVC.swift */, + 034C25CE2B9F4ABC004065D9 /* ShowCardDataSwiftUIDemo.swift */, + 034C26022BA333A1004065D9 /* CardDataCollectionSwiftUI.swift */, + 034C26032BA333A1004065D9 /* CollectCardDataSwiftUIHostingVC.swift */, + ); + path = SwiftUI; + sourceTree = ""; + }; 44415F8F255D36F90012D107 = { isa = PBXGroup; children = ( @@ -232,6 +253,7 @@ 4444EEED255E6452002C9215 /* LaunchScreen.storyboard */, 44F534CB263695D300ECEA77 /* ShowFile.storyboard */, A0A4EEA72A57A31300172678 /* ShowImage.storyboard */, + 034C25D02B9F5112004065D9 /* ShowCardDataSwiftUI.storyboard */, ); path = Storyboards; sourceTree = ""; @@ -289,6 +311,7 @@ A0A4EEA92A57A4D500172678 /* ShowImage */, 44F534D32636962D00ECEA77 /* ShowCard */, 44F535072636D07E00ECEA77 /* ShowPDF */, + 034C25CB2B9F473B004065D9 /* SwiftUI */, ); path = UseCases; sourceTree = ""; @@ -467,6 +490,7 @@ 4444EEF3255E645D002C9215 /* Assets.xcassets in Resources */, 44F534CC263695D300ECEA77 /* ShowFile.storyboard in Resources */, 44F534DF2636965E00ECEA77 /* Main.storyboard in Resources */, + 034C25D12B9F5112004065D9 /* ShowCardDataSwiftUI.storyboard in Resources */, 442F80B225ADB4BE00CC04A2 /* UITestsMockedData.plist in Resources */, A0A4EEA82A57A31300172678 /* ShowImage.storyboard in Resources */, ); @@ -554,17 +578,21 @@ buildActionMask = 2147483647; files = ( 446CB7EE25626D5700E770F1 /* UIViewController+Extensions.swift in Sources */, + 034C25CD2B9F4A64004065D9 /* ShowCardDataSwiftUIHostingVC.swift in Sources */, A0060F8A2A58A2F20060CE85 /* InitialViewController.swift in Sources */, 44F5350A2636D07E00ECEA77 /* ShowDemoPDFViewController.swift in Sources */, 4444EEEB255E6446002C9215 /* AppDelegate.swift in Sources */, 44F534D92636962D00ECEA77 /* ShowDemoViewController.swift in Sources */, 44415FDB255D37540012D107 /* Helpers.swift in Sources */, 440F04D4256E748D00540D58 /* UIDevice+Extensions.swift in Sources */, + 034C26052BA333A1004065D9 /* CollectCardDataSwiftUIHostingVC.swift in Sources */, 44415FDF255D37610012D107 /* DemoAppConfig.swift in Sources */, 4409318F25B6B95300CAF065 /* UIColor+Extensions.swift in Sources */, A0A4EEB82A57A4D500172678 /* CollectImageDemoViewController.swift in Sources */, 44014794256641A500A3627B /* UIFont+Extensions.swift in Sources */, + 034C26042BA333A1004065D9 /* CardDataCollectionSwiftUI.swift in Sources */, A0A4EEBB2A57A4D500172678 /* ShowImageDemoViewController.swift in Sources */, + 034C25CF2B9F4ABC004065D9 /* ShowCardDataSwiftUIDemo.swift in Sources */, 44F534D82636962D00ECEA77 /* CollectViewController.swift in Sources */, 44F5350B2636D07E00ECEA77 /* CollectPDFDemoViewController.swift in Sources */, ); @@ -660,7 +688,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -714,7 +742,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -736,7 +764,7 @@ "$(PROJECT_DIR)", ); INFOPLIST_FILE = VGSShowDemoApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -761,7 +789,7 @@ "$(PROJECT_DIR)", ); INFOPLIST_FILE = VGSShowDemoApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/VGSShowDemoApp/VGSShowDemoApp/Application/AppDelegate.swift b/VGSShowDemoApp/VGSShowDemoApp/Application/AppDelegate.swift index 3fe3b9f8..3086f6b8 100644 --- a/VGSShowDemoApp/VGSShowDemoApp/Application/AppDelegate.swift +++ b/VGSShowDemoApp/VGSShowDemoApp/Application/AppDelegate.swift @@ -24,7 +24,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { #if DEBUG // Setup VGS Show loggers: // Show warnings and errors. - VGSLogger.shared.configuration.level = .info + VGSLogger.shared.configuration.level = .warning // Show network session for reveal requests. VGSLogger.shared.configuration.isNetworkDebugEnabled = true @@ -34,10 +34,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Setup VGS Collect loggers: // Show warnings and errors. - VGSCollectLogger.shared.configuration.level = .info + VGSCollectLogger.shared.configuration.level = .warning // Show network session for collect requests. - VGSCollectLogger.shared.configuration.isNetworkDebugEnabled = false + VGSCollectLogger.shared.configuration.isNetworkDebugEnabled = true // *You can stop all VGS Collect loggers in app: // VGSCollectLogger.shared.disableAllLoggers() @@ -50,3 +50,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } } + +extension UIApplication { + func endEditing() { + sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } +} diff --git a/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/CardDataCollectionSwiftUI.swift b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/CardDataCollectionSwiftUI.swift new file mode 100644 index 00000000..ee1e54e7 --- /dev/null +++ b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/CardDataCollectionSwiftUI.swift @@ -0,0 +1,144 @@ +// +// CardDataCollectionSwiftUI.swift +// demoapp +// + +import Foundation +import SwiftUI +import VGSCollectSDK + +struct CardDataCollectionSwiftUI: View { + let vgsCollect = VGSCollect(id: DemoAppConfig.shared.vaultId, environment: .sandbox) + + // MARK: - State + @State private var holderTextFieldState: VGSTextFieldState? + @State private var cardTextFieldState: VGSCardState? + @State private var expDateTextFieldState: VGSTextFieldState? + @State private var responseState: String = "Waiting for response..." + + // MARK: - Textfield UI attributes + let paddings = UIEdgeInsets(top: 2, left: 8, bottom: 2, right: 8) + let validColor = UIColor.lightGray + let invalidColor = UIColor.red + + // MARK: - Build View + var body: some View { + + // MARK: - Textfield Configuration + var holderNameConfiguration: VGSConfiguration { + let config = VGSConfiguration(collector: vgsCollect, fieldName: "card_holderName") + config.type = .cardHolderName + config.isRequiredValidOnly = true + return config + } + + var cardNumConfiguration: VGSConfiguration { + let config = VGSConfiguration(collector: vgsCollect, fieldName: "card_number") + config.type = .cardNumber + config.isRequiredValidOnly = true + return config + } + + var expDateConfiguration: VGSExpDateConfiguration { + let config = VGSExpDateConfiguration(collector: vgsCollect, fieldName: "card_expirationDate") + config.type = .expDate + // Default .expDate format is "##/##" + config.formatPattern = "##/####" + // Update validation rules + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleCardExpirationDate(dateFormat: .longYear, error: VGSValidationErrorType.expDate.rawValue) + ]) + config.isRequiredValidOnly = true + return config + } + + return VStack(spacing: 8) { + VGSTextFieldRepresentable(configuration: holderNameConfiguration) + .placeholder("Cardholder name") + .textFieldPadding(paddings) + .border(color: (holderTextFieldState?.isValid ?? true) ? validColor : invalidColor, lineWidth: 1) + .frame(height: 54) + VGSCardTextFieldRepresentable(configuration: cardNumConfiguration) + .placeholder("4111 1111 1111 1111") + .onStateChange { newState in + cardTextFieldState = newState + } + .cardIconSize(CGSize(width: 40, height: 20)) + .cardIconLocation(.right) + .textFieldPadding(paddings) + .border(color: (cardTextFieldState?.isValid ?? true) ? validColor : invalidColor, lineWidth: 1) + .frame(height: 54) + VGSExpDateTextFieldRepresentable(configuration: expDateConfiguration) + .placeholder("10/2025") + .monthPickerFormat(.longSymbols) + .textFieldPadding(paddings) + .border(color: (expDateTextFieldState?.isValid ?? true) ? validColor : invalidColor, lineWidth: 1) + .frame(height: 54) + Button(action: { + UIApplication.shared.endEditing() + sendData() + }) { + Text("Send data") + .padding() + .cornerRadius(8) + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.blue, lineWidth: 2) + ) + }.padding(.top, 50) + Text(responseState).padding(.top, 50) + }.padding(.leading, 20) + .padding(.trailing, 20) + } + + private func sendData() { + /// send extra data + var extraData = [String: Any]() + extraData["customKey"] = "Custom Value" + + // Send Request func + vgsCollect.sendData(path: "/post", extraData: extraData) { (response) in + + switch response { + case .success(_, let data, _): + if let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { + print("SUCCESS: \(jsonData)") + if let aliases = jsonData["json"] as? [String: Any], + let cardNumber = aliases["card_number"], + let expDate = aliases["card_expirationDate"], + let cardHolderName = aliases["card_holderName"] { + + print(""" + card_namber: \(cardNumber)\n + expiration_date: \(expDate) + """) + let payload = ["payment_card_holder_name": cardHolderName, + "payment_card_number": cardNumber, + "payment_card_expiration_date": expDate] + + DemoAppConfig.shared.collectPayload = payload + responseState = "\(payload)" + print(payload) + } + } + return + case .failure(let code, _, _, let error): + responseState = "Response Error: \(code)" + print("Error \(code)") + switch code { + case 400..<499: + // Wrong request. This also can happend when your Routs not setup yet or your is wrong + print("Error: Wrong Request, code: \(code)") + case VGSErrorType.inputDataIsNotValid.rawValue: + if let error = error as? VGSError { + print("Error: Input data is not valid. Details:\n \(error)") + } + default: + print("Error: Something went wrong. Code: \(code)") + } + print("Submit request error: \(code), \(String(describing: error))") + return + } + } + } +} diff --git a/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/CollectCardDataSwiftUIHostingVC.swift b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/CollectCardDataSwiftUIHostingVC.swift new file mode 100644 index 00000000..2250d429 --- /dev/null +++ b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/CollectCardDataSwiftUIHostingVC.swift @@ -0,0 +1,28 @@ +// +// CollectCardDataSwiftUIHostingVC.swift +// demoapp +// + + +import Foundation +import SwiftUI + +class CollectCardDataSwiftUIHostingVC: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + let swiftUIView = CardDataCollectionSwiftUI() + let hostingController = UIHostingController(rootView: swiftUIView) + addChild(hostingController) + hostingController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingController.view) + + NSLayoutConstraint.activate([ + hostingController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + hostingController.didMove(toParent: self) + } +} diff --git a/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/ShowCardDataSwiftUIDemo.swift b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/ShowCardDataSwiftUIDemo.swift new file mode 100644 index 00000000..47343f88 --- /dev/null +++ b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/ShowCardDataSwiftUIDemo.swift @@ -0,0 +1,109 @@ +// +// ShowCardDataSwiftUIDemo.swift +// VGSShowDemoApp +// + +import Foundation +import SwiftUI +import VGSShowSDK + +@available(iOS 14.0, *) +struct ShowCardDataSwiftUIDemo: View { + let vgsShow = VGSShow(id: DemoAppConfig.shared.vaultId, environment: .sandbox) + let labelPaddings = UIEdgeInsets(top: 2, left: 8, bottom: 2, right: 8) + + @State private var holderLabelBorderColor: UIColor = .lightGray + @State private var cardLabelBorderColor: UIColor = .lightGray + @State private var expDateLabelBorderColor: UIColor = .lightGray + @State private var responseState: String = "Waitin for revealed data..." + + var body: some View { + /// Change raw card number format + let cardNumberPattern = "(\\d{4})(\\d{4})(\\d{4})(\\d{4})" + let template = "$1 $2 $3 $4" + // swiftlint:disable:next force_try + let regex = try! NSRegularExpression(pattern: cardNumberPattern, options: []) + + var placeholderStyle = VGSPlaceholderLabelStyle() + placeholderStyle.color = .lightGray + + return VStack(spacing: 8) { + VGSLabelRepresentable(vgsShow: vgsShow, contentPath: "json.payment_card_holder_name") + .placeholder("XXXXXXXXXXXXXXXXXXXX") + .placeholderStyle(placeholderStyle) + .onContentDidChange({ + holderLabelBorderColor = .darkGray + print("-card holder name label updated") + }) + .onRevealError({ error in + holderLabelBorderColor = .red + print("-card holder name label error: \(error)") + }) + .labelPaddings(labelPaddings) + .border(color: holderLabelBorderColor, lineWidth: 1) + .frame(height: 54) + VGSLabelRepresentable(vgsShow: vgsShow, contentPath: "json.payment_card_number") + .placeholder("XXXX XXXX XXXX XXXX") + .placeholderStyle(placeholderStyle) + .setSecureText(ranges: [VGSTextRange(start: 5, end: 8), + VGSTextRange(start: 10, end: 13)]) + .addTransformationRegex(regex, template: template) + .labelPaddings(labelPaddings) + .border(color: cardLabelBorderColor, lineWidth: 1) + .onContentDidChange({ + cardLabelBorderColor = .darkGray + print("-card number label updated") + }) + .onRevealError({ error in + cardLabelBorderColor = .red + print("-card number label error: \(error)") + }) + .border(color: cardLabelBorderColor, lineWidth: 1) + .frame(height: 54) + VGSLabelRepresentable(vgsShow: vgsShow, contentPath: "json.payment_card_expiration_date") + .labelPaddings(labelPaddings) + .placeholder("XX/XX") + .placeholderStyle(placeholderStyle) + .onContentDidChange({ + expDateLabelBorderColor = .darkGray + print("-card expDate label updated") + }) + .onRevealError({ error in + expDateLabelBorderColor = .red + print("-card expDate label error: \(error)") + }) + .border(color: expDateLabelBorderColor, lineWidth: 1) + .frame(height: 54) + Button(action: { + // Reveal show data + self.loadData() + }) { + Text("Reveal Data") + .padding() + .cornerRadius(8) + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.blue, lineWidth: 2) + ) + }.padding(.top, 50) + Text(responseState).padding(.top, 50) + }.padding(.leading, 20) + .padding(.trailing, 20) + } + + private func loadData() { + /// Reveal previously collected data. + vgsShow.request(path: DemoAppConfig.shared.path, + method: .post, payload: DemoAppConfig.shared.collectPayload) { (requestResult) in + + switch requestResult { + case .success(let code): + responseState = "Success, code: \(code)." + print("vgsshow success, code: \(code)") + case .failure(let code, let error): + responseState = "Reveal error, code: \(code)." + print("vgsshow failed, code: \(code), error: \(String(describing: error))") + } + } + } +} diff --git a/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/ShowCardDataSwiftUIHostingVC.swift b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/ShowCardDataSwiftUIHostingVC.swift new file mode 100644 index 00000000..0ec98d3c --- /dev/null +++ b/VGSShowDemoApp/VGSShowDemoApp/Controllers/UseCases/SwiftUI/ShowCardDataSwiftUIHostingVC.swift @@ -0,0 +1,30 @@ +// +// ShowCardDataSwiftUIHostingVC.swift +// VGSShowDemoApp +// + + +import Foundation +import SwiftUI + +@available(iOS 14.0, *) +class ShowCardDataSwiftUIHostingVC: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + let swiftUIView = ShowCardDataSwiftUIDemo() + let hostingController = UIHostingController(rootView: swiftUIView) + addChild(hostingController) + hostingController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingController.view) + + NSLayoutConstraint.activate([ + hostingController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + + hostingController.didMove(toParent: self) + } +} diff --git a/VGSShowDemoApp/VGSShowDemoApp/Storyboards/Main.storyboard b/VGSShowDemoApp/VGSShowDemoApp/Storyboards/Main.storyboard index 6a59f656..073cec32 100644 --- a/VGSShowDemoApp/VGSShowDemoApp/Storyboards/Main.storyboard +++ b/VGSShowDemoApp/VGSShowDemoApp/Storyboards/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -347,6 +347,26 @@ + + + + + + + + + + + + + + @@ -390,7 +410,17 @@ - + + + + + + + + + + + @@ -417,10 +447,10 @@ - + - + diff --git a/VGSShowDemoApp/VGSShowDemoApp/Storyboards/ShowCardDataSwiftUI.storyboard b/VGSShowDemoApp/VGSShowDemoApp/Storyboards/ShowCardDataSwiftUI.storyboard new file mode 100644 index 00000000..2b74bad1 --- /dev/null +++ b/VGSShowDemoApp/VGSShowDemoApp/Storyboards/ShowCardDataSwiftUI.storyboard @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VGSShowSDK.podspec b/VGSShowSDK.podspec index d4022d87..4578b78a 100644 --- a/VGSShowSDK.podspec +++ b/VGSShowSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "VGSShowSDK" - spec.version = "1.1.7" + spec.version = "1.2.0" spec.summary = "VGS Show - is a product suite that allows customers to reveal and show information securely without possession of it." spec.swift_version = '5.0' spec.description = <<-DESC @@ -9,8 +9,8 @@ Pod::Spec.new do |spec| spec.homepage = "https://github.com/verygoodsecurity/vgs-show-ios" spec.license = { type: 'MIT', file: 'LICENSE' } spec.author = { "Very Good Security" => "support@verygoodsecurity.com" } - spec.platform = :ios, "10.0" - spec.ios.deployment_target = "10.0" + spec.platform = :ios, "13.0" + spec.ios.deployment_target = "13.0" spec.source = { :git => "https://github.com/verygoodsecurity/vgs-show-ios.git", :tag => "#{spec.version}" } spec.requires_arc = true diff --git a/VGSShowSDK.xcodeproj/project.pbxproj b/VGSShowSDK.xcodeproj/project.pbxproj index 17eacda6..42a766c9 100644 --- a/VGSShowSDK.xcodeproj/project.pbxproj +++ b/VGSShowSDK.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 0345B1802B8E1969002A70C3 /* VGSLabelRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0345B17F2B8E1969002A70C3 /* VGSLabelRepresentable.swift */; }; + 034C25FD2BA2FC13004065D9 /* VGSViewRepresentableProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 034C25FC2BA2FC13004065D9 /* VGSViewRepresentableProtocol.swift */; }; + 034C26012BA3015E004065D9 /* VGSViewRepresentableCallbacksProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 034C26002BA3015E004065D9 /* VGSViewRepresentableCallbacksProtocol.swift */; }; + 03717E332B9A12B2006DC837 /* VGSImageViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03717E322B9A12B2006DC837 /* VGSImageViewRepresentable.swift */; }; + 03717E362B9A27B4006DC837 /* VGSPDFViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03717E352B9A27B4006DC837 /* VGSPDFViewRepresentable.swift */; }; 038184DC2B0BA1B800928C36 /* String+ExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038184DB2B0BA1B800928C36 /* String+ExtensionTests.swift */; }; 03D10DB92B04F3CA00C86E40 /* VGSShowRequestOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D10DB82B04F3CA00C86E40 /* VGSShowRequestOptionsTests.swift */; }; 03D10DBC2B04F75400C86E40 /* VGSDataDecoderFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D10DBB2B04F75400C86E40 /* VGSDataDecoderFactoryTests.swift */; }; @@ -125,6 +130,11 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0345B17F2B8E1969002A70C3 /* VGSLabelRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSLabelRepresentable.swift; sourceTree = ""; }; + 034C25FC2BA2FC13004065D9 /* VGSViewRepresentableProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSViewRepresentableProtocol.swift; sourceTree = ""; }; + 034C26002BA3015E004065D9 /* VGSViewRepresentableCallbacksProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSViewRepresentableCallbacksProtocol.swift; sourceTree = ""; }; + 03717E322B9A12B2006DC837 /* VGSImageViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSImageViewRepresentable.swift; sourceTree = ""; }; + 03717E352B9A27B4006DC837 /* VGSPDFViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSPDFViewRepresentable.swift; sourceTree = ""; }; 038184DB2B0BA1B800928C36 /* String+ExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ExtensionTests.swift"; sourceTree = ""; }; 03D10DB82B04F3CA00C86E40 /* VGSShowRequestOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSShowRequestOptionsTests.swift; sourceTree = ""; }; 03D10DBB2B04F75400C86E40 /* VGSDataDecoderFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDataDecoderFactoryTests.swift; sourceTree = ""; }; @@ -254,6 +264,39 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0345B17E2B8E194D002A70C3 /* VGSLabelRepresentable */ = { + isa = PBXGroup; + children = ( + 0345B17F2B8E1969002A70C3 /* VGSLabelRepresentable.swift */, + ); + path = VGSLabelRepresentable; + sourceTree = ""; + }; + 034C25FB2BA2FBC8004065D9 /* VGSViewRepresentableProtocols */ = { + isa = PBXGroup; + children = ( + 034C25FC2BA2FC13004065D9 /* VGSViewRepresentableProtocol.swift */, + 034C26002BA3015E004065D9 /* VGSViewRepresentableCallbacksProtocol.swift */, + ); + path = VGSViewRepresentableProtocols; + sourceTree = ""; + }; + 03717E312B9A128F006DC837 /* VGSImageViewRepresentable */ = { + isa = PBXGroup; + children = ( + 03717E322B9A12B2006DC837 /* VGSImageViewRepresentable.swift */, + ); + path = VGSImageViewRepresentable; + sourceTree = ""; + }; + 03717E342B9A27A2006DC837 /* VGSPDFViewRepresentable */ = { + isa = PBXGroup; + children = ( + 03717E352B9A27B4006DC837 /* VGSPDFViewRepresentable.swift */, + ); + path = VGSPDFViewRepresentable; + sourceTree = ""; + }; 038184DA2B0BA19200928C36 /* ExtensionTests */ = { isa = PBXGroup; children = ( @@ -313,6 +356,7 @@ 44168FD326329FAE0088E515 /* VGSPDFView */ = { isa = PBXGroup; children = ( + 03717E342B9A27A2006DC837 /* VGSPDFViewRepresentable */, 44168FD926329FAE0088E515 /* VGSSecurePDFView */, 44168FD626329FAE0088E515 /* VGSPDFViewDelegate.swift */, 44168FD726329FAE0088E515 /* VGSPDFView.swift */, @@ -612,6 +656,7 @@ A0A4EEBD2A57A66D00172678 /* UIView+Internal.swift */, A0A4EEBE2A57A66D00172678 /* VGSImageView */, 44F534E4263697D100ECEA77 /* VGSViewProtocols */, + 034C25FB2BA2FBC8004065D9 /* VGSViewRepresentableProtocols */, 44168FD326329FAE0088E515 /* VGSPDFView */, 44A79F63255D0678009AF720 /* VGSLabel */, 44A79F68255D0678009AF720 /* VGSMaskedLabel.swift */, @@ -624,6 +669,7 @@ 44A79F63255D0678009AF720 /* VGSLabel */ = { isa = PBXGroup; children = ( + 0345B17E2B8E194D002A70C3 /* VGSLabelRepresentable */, 44A79F64255D0678009AF720 /* VGSLabel+Internal.swift */, 44A79F65255D0678009AF720 /* VGSLabelDelegate.swift */, 44A79F66255D0678009AF720 /* VGSLabel.swift */, @@ -758,6 +804,7 @@ A0A4EEBE2A57A66D00172678 /* VGSImageView */ = { isa = PBXGroup; children = ( + 03717E312B9A128F006DC837 /* VGSImageViewRepresentable */, A0A4EEBF2A57A66D00172678 /* VGSImageView+Internal.swift */, A0A4EEC02A57A66D00172678 /* VGSImageViewModel.swift */, A0A4EEC12A57A66D00172678 /* VGSImageView.swift */, @@ -934,11 +981,13 @@ 44E05118256E49C400DDBE41 /* String+Exntesions.swift in Sources */, 4461083225639CDF006479FB /* VGSAnalyticsClient.swift in Sources */, 44A79F6B255D0678009AF720 /* APIClient.swift in Sources */, + 03717E332B9A12B2006DC837 /* VGSImageViewRepresentable.swift in Sources */, 44BAD78025C7EA520060A170 /* VGSTextRange.swift in Sources */, 44A79F76255D0678009AF720 /* VGSTransformationRegex.swift in Sources */, 44168FDE26329FAE0088E515 /* VGSPDFView.swift in Sources */, 448F55CA258336BA0024E814 /* VGSRequestBodyPayload.swift in Sources */, 441690002632A4480088E515 /* VGSDataDecoderFactory.swift in Sources */, + 034C25FD2BA2FC13004065D9 /* VGSViewRepresentableProtocol.swift in Sources */, 446DA63E2644191000DDBD5E /* VGSShowRequestOptions.swift in Sources */, A0A4EEC92A57A66D00172678 /* VGSImageViewDelegate.swift in Sources */, 44168FE126329FAE0088E515 /* VGSPdfViewModel.swift in Sources */, @@ -963,6 +1012,7 @@ 44168FFE2632A4480088E515 /* VGSShowRawDataDecoder.swift in Sources */, 44168FDF26329FAE0088E515 /* VGSPDFView+Internal.swift in Sources */, 441963E12592357400CAFBB3 /* VGSPlaceholderLabelStyle.swift in Sources */, + 0345B1802B8E1969002A70C3 /* VGSLabelRepresentable.swift in Sources */, 44A79F81255D0678009AF720 /* VGSLabelDelegate.swift in Sources */, 44A79F84255D0678009AF720 /* VGSMaskedLabel.swift in Sources */, 44168FFA2632A4480088E515 /* VGSShowPDFContent.swift in Sources */, @@ -987,12 +1037,14 @@ 44168FFF2632A4480088E515 /* VGSShowTextDecoder.swift in Sources */, 445FD81625E37F4000B36614 /* VGSShowSatelliteUtils.swift in Sources */, 44BAD6DC25C289460060A170 /* VGSLogEvent.swift in Sources */, + 034C26012BA3015E004065D9 /* VGSViewRepresentableCallbacksProtocol.swift in Sources */, 44BAD76425C445A70060A170 /* VGSShow+Logging.swift in Sources */, 448525C525829F8400721F73 /* VGSShowRequestLogger.swift in Sources */, 44BAD6E625C28DEC0060A170 /* VGSLogger.swift in Sources */, 44416C0C2642AC150099B48F /* FileManager+Extensions.swift in Sources */, 44A79F6D255D0678009AF720 /* VGSShow+Network.swift in Sources */, 44A79F80255D0678009AF720 /* VGSLabel+Internal.swift in Sources */, + 03717E362B9A27B4006DC837 /* VGSPDFViewRepresentable.swift in Sources */, 4409318925B6B8FC00CAF065 /* UIApplication+Extensions.swift in Sources */, 44A79F6C255D0678009AF720 /* VGSShowRequestResult.swift in Sources */, 44A474962588865F00534965 /* URL+Extensions.swift in Sources */, @@ -1103,7 +1155,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.2.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1161,7 +1214,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.2.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -1187,13 +1241,13 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; INFOPLIST_FILE = "$(SRCROOT)/Sources/VGSShowSDK/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.7; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = com.vgs.framework.VGSShowsSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1218,13 +1272,13 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; INFOPLIST_FILE = "$(SRCROOT)/Sources/VGSShowSDK/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.7; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = com.vgs.framework.VGSShowsSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1246,7 +1300,7 @@ INFOPLIST_FILE = Tests/VGSShowSDKTests/Info.plist; "INFOPLIST_FILE[sdk=*]" = ""; INFOPLIST_PREPROCESS = NO; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1270,7 +1324,7 @@ INFOPLIST_EXPAND_BUILD_SETTINGS = YES; INFOPLIST_FILE = Tests/VGSShowSDKTests/Info.plist; INFOPLIST_PREPROCESS = NO; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks",