Skip to content

Commit 693b559

Browse files
author
Team Mobile Schorsch
committed
Release version 3.11.0
1 parent fc825d5 commit 693b559

29 files changed

+283
-134
lines changed

.jazzy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ xcodebuild_arguments:
55
- "-scheme"
66
- GiniCaptureSDK
77
- "-destination"
8-
- platform=iOS Simulator,OS=17.2,name=iPhone 14
8+
- platform=iOS Simulator,OS=17.5,name=iPhone 15
99
author: Gini GmbH
1010
author_url: https://gini.net
1111
module: GiniCaptureSDK

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let package = Package(
1616
dependencies: [
1717
// Dependencies declare other packages that this package depends on.
1818
// .package(url: /* package url */, from: "1.0.0"),
19-
.package(name: "GiniBankAPILibrary", url: "https://github.com/gini/bank-api-library-ios.git", .exact("3.3.1"))
19+
.package(name: "GiniBankAPILibrary", url: "https://github.com/gini/bank-api-library-ios.git", .exact("3.4.0"))
2020
],
2121
targets: [
2222
// Targets are the basic building blocks of a package. A target can define a module or a test suite.

Sources/GiniCaptureSDK/Core/Custom views/GiniBarButton.swift

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -126,56 +126,58 @@ public final class GiniBarButton {
126126
}
127127

128128
private func setupContent(basedOnType type: BarButtonType) {
129-
var buttonTitle: String?
130-
var icon: UIImage?
131-
132-
switch type {
133-
case .cancel:
134-
buttonTitle = NSLocalizedStringPreferredFormat("ginicapture.navigationbar.analysis.back",
135-
comment: "Cancel")
136-
icon = UIImageNamedPreferred(named: "barButton_cancel")
137-
case .help:
138-
buttonTitle = NSLocalizedStringPreferredFormat("ginicapture.navigationbar.camera.help",
139-
comment: "Help")
140-
icon = UIImageNamedPreferred(named: "barButton_help")
141-
case .back(title: let title):
142-
buttonTitle = title
143-
let backString = NSLocalizedStringPreferredFormat("ginicapture.navigationbar.accessibility.back",
144-
comment: "Back")
145-
if title.trimmingCharacters(in: .whitespaces).isNotEmpty {
146-
stackView.accessibilityValue = "\(title) \(backString)"
147-
} else {
148-
stackView.accessibilityValue = backString
149-
}
150-
icon = UIImageNamedPreferred(named: "barButton_back")
151-
case .done:
152-
buttonTitle = NSLocalizedStringPreferredFormat("ginicapture.imagepicker.openbutton",
153-
comment: "Done")
154-
icon = UIImageNamedPreferred(named: "barButton_done")
155-
case .skip:
156-
buttonTitle = NSLocalizedStringPreferredFormat("ginicapture.onboarding.skip",
157-
comment: "Skip button")
158-
}
159-
160-
let buttonTitleIsEmpty = buttonTitle == nil || buttonTitle!.isEmpty
161-
162-
// If there is no image nor any text for the button, the app will crash in debug mode.
163-
if buttonTitleIsEmpty && icon == nil {
164-
assertionFailure("You need to provide at least a valid string or an icon" +
165-
" for the navigation bar button of type: \(type)")
129+
let (buttonTitle, icon) = titleAndIcon(for: type)
130+
131+
// Ensure there’s at least a title or icon to avoid a crash
132+
guard buttonTitle != nil || icon != nil else {
133+
assertionFailure("""
134+
You need to provide at least a valid string or an icon \
135+
for the navigation bar button of type: \(type)
136+
""")
137+
return
166138
}
167139

168140
imageView.image = icon?.tintedImageWithColor(.GiniCapture.accent1)
169141

142+
// Set up title if available and accessibility value for the stackview
170143
if let buttonTitle = buttonTitle {
171-
titleLabel.attributedText = NSAttributedString(string: buttonTitle,
172-
attributes: textAttributes())
173-
if stackView.accessibilityValue == nil {
144+
titleLabel.attributedText = NSAttributedString(string: buttonTitle, attributes: textAttributes())
145+
146+
// Add accessibility value with backString only for the back button when title is not equal to backString
147+
if case .back = type {
148+
let backString = NSLocalizedStringPreferredFormat("ginicapture.navigationbar.accessibility.back",
149+
comment: "Back")
150+
stackView.accessibilityValue = (buttonTitle == backString) ? buttonTitle :
151+
"\(buttonTitle) \(backString)"
152+
} else {
174153
stackView.accessibilityValue = buttonTitle
175154
}
176155
}
177156
}
178157

158+
private func titleAndIcon(for type: BarButtonType) -> (String?, UIImage?) {
159+
switch type {
160+
case .cancel:
161+
return (NSLocalizedStringPreferredFormat("ginicapture.navigationbar.analysis.back",
162+
comment: "Cancel"),
163+
UIImageNamedPreferred(named: "barButton_cancel"))
164+
case .help:
165+
return (NSLocalizedStringPreferredFormat("ginicapture.navigationbar.camera.help",
166+
comment: "Help"),
167+
UIImageNamedPreferred(named: "barButton_help"))
168+
case .back(let title):
169+
return (title, UIImageNamedPreferred(named: "barButton_back"))
170+
case .done:
171+
return (NSLocalizedStringPreferredFormat("ginicapture.imagepicker.openbutton",
172+
comment: "Done"),
173+
UIImageNamedPreferred(named: "barButton_done"))
174+
case .skip:
175+
return (NSLocalizedStringPreferredFormat("ginicapture.onboarding.skip",
176+
comment: "Skip button"),
177+
nil)
178+
}
179+
}
180+
179181
private func textAttributes() -> [NSAttributedString.Key: Any] {
180182
var attributes: [NSAttributedString.Key: Any]
181183
let buttonFont = configuration.textStyleFonts[.body]

Sources/GiniCaptureSDK/Core/Extensions/Data.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extension Data {
1616
0x47: "image/gif",
1717
0x49: "image/tiff",
1818
0x4D: "image/tiff",
19+
0x52: "image/webp",
1920
0x25: "application/pdf",
2021
0xD0: "application/vnd",
2122
0x46: "text/plain"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// GiniBankDocument+Convenience.swift
3+
//
4+
// Copyright © 2024 Gini GmbH. All rights reserved.
5+
//
6+
7+
import GiniBankAPILibrary
8+
import UIKit
9+
10+
extension Document.UploadMetadata {
11+
convenience init(
12+
interfaceOrientation: UIInterfaceOrientation,
13+
documentSource: DocumentSource,
14+
importMethod: DocumentImportMethod?
15+
) {
16+
self.init(
17+
giniCaptureVersion: GiniCaptureSDKVersion,
18+
deviceOrientation: interfaceOrientation.isLandscape ? "landscape" : "portrait",
19+
source: documentSource.value,
20+
importMethod: importMethod?.rawValue ?? "",
21+
entryPoint: GiniConfiguration.shared.entryPoint.stringValue,
22+
osVersion: UIDevice.current.systemVersion
23+
)
24+
}
25+
26+
convenience init(
27+
deviceOrientation: UIDeviceOrientation,
28+
documentSource: DocumentSource,
29+
importMethod: DocumentImportMethod?
30+
) {
31+
self.init(
32+
giniCaptureVersion: GiniCaptureSDKVersion,
33+
deviceOrientation: deviceOrientation.isLandscape ? "landscape" : "portrait",
34+
source: documentSource.value,
35+
importMethod: importMethod?.rawValue ?? "",
36+
entryPoint: GiniConfiguration.shared.entryPoint.stringValue,
37+
osVersion: UIDevice.current.systemVersion
38+
)
39+
}
40+
}

Sources/GiniCaptureSDK/Core/GiniConfiguration.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,13 @@ import GiniBankAPILibrary
553553
case button
554554
// Must be used when the user launches the SDK from a text field.
555555
case field
556+
557+
var stringValue: String {
558+
switch self {
559+
case .button: "button"
560+
case .field: "field"
561+
}
562+
}
556563
}
557564

558565
/**

Sources/GiniCaptureSDK/Core/Helpers/GiniCaptureDocumentValidator.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ fileprivate extension GiniCaptureDocumentValidator {
104104
if document.extractedParameters[QRCodesExtractor.epsCodeUrlKey] == nil {
105105
throw DocumentValidationError.qrCodeFormatNotValid
106106
}
107+
case .some(.giniQRCode):
108+
if document.extractedParameters[QRCodesExtractor.giniCodeUrlKey] == nil {
109+
throw DocumentValidationError.qrCodeFormatNotValid
110+
}
107111
case .none:
108112
throw DocumentValidationError.qrCodeFormatNotValid
109113
}

Sources/GiniCaptureSDK/Core/Helpers/ImageMetaInformationManager.swift

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import UIKit
1010
import ImageIO
1111
import AVFoundation
1212
import MobileCoreServices
13+
import GiniBankAPILibrary
1314

1415
typealias MetaInformation = NSDictionary
1516

@@ -92,13 +93,7 @@ final class ImageMetaInformationManager {
9293
// user comment fields
9394
let userCommentRotation = "RotDeltaDeg"
9495
let userCommentContentId = "ContentId"
95-
let userCommentPlatform = "Platform"
96-
let userCommentOSVer = "OSVer"
97-
let userCommentGiniVersionVer = "GiniCaptureVer"
9896
let userCommentDeviceOrientation = "DeviceOrientation"
99-
let userCommentSource = "Source"
100-
let userCommentImportMethod = "ImportMethod"
101-
let userCommentEntryPoint = "EntryPoint"
10297

10398
var imageData: Data?
10499
var metaInformation: MetaInformation?
@@ -232,43 +227,24 @@ final class ImageMetaInformationManager {
232227
return nil
233228
}
234229

235-
fileprivate func entryFieldString(_ entryPoint: GiniConfiguration.GiniEntryPoint) -> String {
236-
switch entryPoint {
237-
case .button:
238-
return "button"
239-
case .field:
240-
return "field"
241-
}
242-
}
243-
244230
fileprivate func userComment(rotationDegrees: Int? = nil) -> String {
245-
let platform = "iOS"
246-
let osVersion = UIDevice.current.systemVersion
247-
let GiniCaptureVersion = GiniCapture.versionString
248-
let uuid = imageUUID()
249-
let entryPoint = entryFieldString(GiniConfiguration.shared.entryPoint)
250-
var comment = "\(userCommentPlatform)=\(platform)," +
251-
"\(userCommentOSVer)=\(osVersion)," +
252-
"\(userCommentGiniVersionVer)=\(GiniCaptureVersion)," +
253-
"\(userCommentContentId)=\(uuid)," +
254-
"\(userCommentSource)=\(imageSource.value)," +
255-
"\(userCommentEntryPoint)=\(entryPoint)"
256-
257-
if let imageImportMethod = imageImportMethod, imageSource.value != DocumentSource.camera.value {
258-
comment += ",\(userCommentImportMethod)=\(imageImportMethod.rawValue)"
259-
}
260-
231+
var rotationNorm = ""
261232
if let rotationDegrees = rotationDegrees {
262-
// normalize the rotation to 0-360
263-
let rotation = imageRotationDeltaDegrees() + rotationDegrees
264-
let rotationNorm = normalizedDegrees(imageRotation: rotation)
265-
comment += ",\(userCommentRotation)=\(rotationNorm)"
266-
}
267-
268-
if let deviceOrientationOnCapture = deviceOrientationOnCapture {
269-
comment += ",\(userCommentDeviceOrientation)=\(deviceOrientationOnCapture)"
233+
rotationNorm = "\(normalizedDegrees(imageRotation: imageRotationDeltaDegrees() + rotationDegrees))"
270234
}
271-
return comment
235+
let importMethod = imageSource.value != DocumentSource.camera.value
236+
? imageImportMethod?.rawValue ?? ""
237+
: ""
238+
return Document.UploadMetadata.constructComment(
239+
osVersion: UIDevice.current.systemVersion,
240+
giniVersion: GiniCapture.versionString,
241+
contentId: imageUUID(),
242+
source: imageSource.value,
243+
entryPoint: GiniConfiguration.shared.entryPoint.stringValue,
244+
importMethod: importMethod,
245+
deviceOrientation: deviceOrientationOnCapture ?? "",
246+
rotation: rotationNorm
247+
)
272248
}
273249

274250
fileprivate func imageUUID() -> String {

Sources/GiniCaptureSDK/Core/Helpers/QRCodesExtractor.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,27 @@ public enum QRCodesFormat {
1111
case epc06912
1212
case eps4mobile
1313
case bezahl
14+
case giniQRCode
15+
16+
var prefixURL: String {
17+
switch self {
18+
case .epc06912:
19+
return "BCD"
20+
case .eps4mobile:
21+
return "epspayment://"
22+
case .bezahl:
23+
return "bank://"
24+
case .giniQRCode:
25+
return "https://pay.gini.net/"
26+
}
27+
}
1428
}
1529

1630
public final class QRCodesExtractor {
1731

1832
public static let epsCodeUrlKey = "epsPaymentQRCodeUrl"
19-
33+
public static let giniCodeUrlKey = "giniPaymentQRCodeUrl"
34+
2035
class func extractParameters(from string: String, withFormat qrCodeFormat: QRCodesFormat?) -> [String: String] {
2136
switch qrCodeFormat {
2237
case .some(.bezahl):
@@ -25,6 +40,8 @@ public final class QRCodesExtractor {
2540
return extractParameters(fromEPC06912CodeString: string)
2641
case .some(.eps4mobile):
2742
return [epsCodeUrlKey: string]
43+
case .some(.giniQRCode):
44+
return [giniCodeUrlKey: string]
2845
case .none:
2946
return [:]
3047
}

Sources/GiniCaptureSDK/Core/Models/GiniCaptureDocument.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright © 2017 Gini GmbH. All rights reserved.
77
//
88

9+
import GiniBankAPILibrary
910
import UIKit
1011

1112
/**
@@ -14,6 +15,7 @@ import UIKit
1415

1516
@objc public protocol GiniCaptureDocument: AnyObject {
1617
var type: GiniCaptureDocumentType { get }
18+
var uploadMetadata: Document.UploadMetadata? { get }
1719
var data: Data { get }
1820
var id: String { get }
1921
var previewImage: UIImage? { get }
@@ -74,12 +76,13 @@ public class GiniCaptureDocumentBuilder: NSObject {
7476
*/
7577
public func build(with data: Data, fileName: String?) -> GiniCaptureDocument? {
7678
if data.isPDF {
77-
return GiniPDFDocument(data: data, fileName: fileName)
79+
return GiniPDFDocument(data: data, fileName: fileName, uploadMetadata: generateUploadMetadata())
7880
} else if data.isImage {
7981
return GiniImageDocument(data: data,
8082
imageSource: documentSource,
8183
imageImportMethod: importMethod,
82-
deviceOrientation: deviceOrientation)
84+
deviceOrientation: deviceOrientation,
85+
uploadMetadata: generateUploadMetadata())
8386
}
8487
return nil
8588
}
@@ -102,6 +105,14 @@ public class GiniCaptureDocumentBuilder: NSObject {
102105
completion(self.build(with: data, fileName: openURL.lastPathComponent))
103106
}
104107
}
108+
109+
public func generateUploadMetadata() -> Document.UploadMetadata {
110+
return Document.UploadMetadata(
111+
interfaceOrientation: deviceOrientation ?? .portrait,
112+
documentSource: documentSource,
113+
importMethod: importMethod
114+
)
115+
}
105116
}
106117

107118
private extension GiniCaptureDocumentBuilder {

Sources/GiniCaptureSDK/Core/Models/GiniImageDocument.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright © 2017 Gini GmbH. All rights reserved.
77
//
88

9+
import GiniBankAPILibrary
910
import UIKit
1011
import MobileCoreServices
1112

@@ -22,6 +23,7 @@ final public class GiniImageDocument: NSObject, GiniCaptureDocument {
2223
public var previewImage: UIImage?
2324
public var isReviewable: Bool
2425
public var isImported: Bool
26+
public var uploadMetadata: Document.UploadMetadata?
2527
public var rotationDelta: Int { // Should be normalized to be in [0, 360)
2628
return self.metaInformationManager.imageRotationDeltaDegrees()
2729
}
@@ -43,11 +45,12 @@ final public class GiniImageDocument: NSObject, GiniCaptureDocument {
4345
processedImageData: Data? = nil,
4446
imageSource: DocumentSource,
4547
imageImportMethod: DocumentImportMethod? = nil,
46-
deviceOrientation: UIInterfaceOrientation? = nil) {
48+
deviceOrientation: UIInterfaceOrientation? = nil,
49+
uploadMetadata: Document.UploadMetadata? = nil) {
4750
self.previewImage = UIImage(data: processedImageData ?? data)
4851
self.isReviewable = true
4952
self.id = UUID().uuidString
50-
53+
self.uploadMetadata = uploadMetadata
5154
switch imageSource {
5255
case .appName(name: _):
5356
isFromOtherApp = true

0 commit comments

Comments
 (0)