├── Podfile ├── BarcodeScanner ├── Supporting Files │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-1024.png │ │ │ ├── Icon-20.png │ │ │ ├── Icon-29.png │ │ │ ├── Icon-40.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-20@2x.png │ │ │ ├── Icon-20@3x.png │ │ │ ├── Icon-29@2x.png │ │ │ ├── Icon-29@3x.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ └── Contents.json │ ├── Font │ │ ├── ProximaNovaExCn-Bold.ttf │ │ ├── ProximaNovaExCn-Light.ttf │ │ ├── ProximaNovaExCn-Thin.ttf │ │ └── ProximaNovaExCn-Regular.ttf │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── AppDelegate.swift │ ├── SceneDelegate.swift │ └── Info.plist ├── Common │ ├── Components │ │ ├── STCamera │ │ │ ├── FlashlightStatus.swift │ │ │ ├── STScanArea.swift │ │ │ └── STCamera.swift │ │ ├── STAlert │ │ │ └── STAlert.swift │ │ └── STModal │ │ │ └── STModal.swift │ ├── Extensions │ │ ├── UIView.swift │ │ └── UIViewController.swift │ └── Services │ │ └── Network │ │ └── NetworkService.swift └── Modules │ ├── Main │ ├── Builder │ │ └── MainBuilder.swift │ ├── Router │ │ └── MainRouter.swift │ ├── Presenter │ │ └── MainPresenter.swift │ └── View │ │ ├── MainViewController.swift │ │ └── MainViewController.xib │ ├── Error │ ├── Builder │ │ └── ErrorBuilder.swift │ ├── Presenter │ │ └── ErrorPresenter.swift │ ├── Model │ │ └── NetworkError.swift │ └── View │ │ ├── ErrorViewController.swift │ │ └── ErrorViewController.xib │ └── Product │ ├── Builder │ └── ProductBuilder.swift │ ├── Model │ └── Product.swift │ ├── Presenter │ └── ProductPresenter.swift │ └── View │ ├── ProductViewController.swift │ └── ProductViewController.xib ├── .gitignore ├── BarcodeScanner.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── IDETemplateMacros.plist ├── Podfile.lock ├── LICENSE.txt ├── README.md └── BarcodeScanner.xcodeproj └── project.pbxproj /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '13.0' 2 | 3 | target 'BarcodeScanner' do 4 | 5 | pod 'SwiftEntryKit' 6 | 7 | end 8 | -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pbxuser 3 | *.mode1v3 4 | *.mode2v3 5 | *.perspectivev3 6 | *.xcuserstate 7 | project.xcworkspace/ 8 | xcuserdata/ 9 | Pods/ -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Bold.ttf -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Light.ttf -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Thin.ttf -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Font/ProximaNovaExCn-Regular.ttf -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-1024.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-20.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-29.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/BarcodeScanner/HEAD/BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /BarcodeScanner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BarcodeScanner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - QuickLayout (3.0.0) 3 | - SwiftEntryKit (1.2.3): 4 | - QuickLayout (= 3.0.0) 5 | 6 | DEPENDENCIES: 7 | - SwiftEntryKit 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - QuickLayout 12 | - SwiftEntryKit 13 | 14 | SPEC CHECKSUMS: 15 | QuickLayout: 07b45a72b10083fee3f095990cfed1c1e7b27f0a 16 | SwiftEntryKit: 340713c2e4a6662c5149629990bf1088bf5f0389 17 | 18 | PODFILE CHECKSUM: 533cf2b58c9fd8d51c0fc541c894245268a17d8a 19 | 20 | COCOAPODS: 1.10.1 21 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Tamerlan Satualdypov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /BarcodeScanner/Common/Components/STCamera/FlashlightStatus.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import Foundation 25 | 26 | enum FlashlightStatus { 27 | case on 28 | case off 29 | 30 | case notFound 31 | case notInitialized 32 | } 33 | -------------------------------------------------------------------------------- /BarcodeScanner.xcworkspace/xcshareddata/IDETemplateMacros.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FILEHEADER 6 | 7 | // MIT License 8 | // 9 | // Copyright (c) 2021 Tamerlan Satualdypov 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in all 19 | // copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | 30 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Extensions/UIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | extension UIView { 27 | 28 | public func setupShadow(withColor color : UIColor, opacity : Float, offset : CGSize) -> () { 29 | self.layer.shadowColor = color.cgColor 30 | self.layer.shadowOpacity = opacity 31 | self.layer.shadowOffset = offset 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Extensions/UIViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | extension UIViewController { 27 | 28 | public func showAlert(title: String, message: String) -> () { 29 | let alert = STAlert(title: title, message: message, preferredStyle: .alert) 30 | .addCancel(title: "Понятно") 31 | .prepared() 32 | 33 | self.present(alert, animated: true) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Main/Builder/MainBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import Foundation 25 | 26 | final class MainBuilder { 27 | 28 | public static func build() -> MainViewController { 29 | let view = MainViewController() 30 | let router = MainRouter(view: view) 31 | let presenter = MainPresenter(view: view, router: router) 32 | 33 | view.presenter = presenter 34 | 35 | return view 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Error/Builder/ErrorBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import Foundation 25 | 26 | final class ErrorBuilder { 27 | 28 | public static func build(with error: NetworkError, delegate: STModalDelegate?) -> STModal { 29 | let view = ErrorViewController() 30 | let presenter = ErrorPresenter(view: view, error: error) 31 | 32 | view.presenter = presenter 33 | 34 | return .init(view: view, delegate: delegate) 35 | .set(width: .offset(value: 16.0)) 36 | .set(height: .intrinsic) 37 | .set(verticalOffset: 32.0) 38 | .set(position: .bottom) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Product/Builder/ProductBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import Foundation 25 | 26 | final class ProductBuilder { 27 | 28 | public static func build(with product: Product, delegate: STModalDelegate?) -> STModal { 29 | let view = ProductViewController() 30 | let presenter = ProductPresenter(view: view, product: product) 31 | 32 | view.presenter = presenter 33 | 34 | return .init(view: view, delegate: delegate) 35 | .set(width: .offset(value: 16.0)) 36 | .set(height: .intrinsic) 37 | .set(verticalOffset: 32.0) 38 | .set(position: .bottom) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | @UIApplicationMain 27 | class AppDelegate: UIResponder, UIApplicationDelegate { 28 | 29 | public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 30 | return true 31 | } 32 | 33 | public func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 34 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 35 | } 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 27 | 28 | public var window: UIWindow? 29 | 30 | public func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 31 | guard let windowScene = (scene as? UIWindowScene) else { return } 32 | 33 | self.window = UIWindow(frame: windowScene.coordinateSpace.bounds) 34 | self.window?.windowScene = windowScene 35 | 36 | self.window?.rootViewController = MainBuilder.build() 37 | self.window?.makeKeyAndVisible() 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Error/Presenter/ErrorPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | import Foundation 24 | 25 | protocol ErrorPresenterProtocol { 26 | func viewDidLoad() -> () 27 | init(view : ErrorViewControllerProtocol, error : NetworkError) 28 | } 29 | 30 | final class ErrorPresenter : ErrorPresenterProtocol { 31 | 32 | private weak var view: ErrorViewControllerProtocol? 33 | private var error: NetworkError 34 | 35 | public func viewDidLoad() -> () { 36 | self.view?.set(image: self.error.image) 37 | self.view?.set(title: self.error.title) 38 | self.view?.set(message: self.error.message) 39 | } 40 | 41 | init(view: ErrorViewControllerProtocol, error: NetworkError) { 42 | self.view = view 43 | self.error = error 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Product/Model/Product.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | struct Product { 27 | let classification : String 28 | let name : String 29 | let barcode : String 30 | 31 | let image : UIImage? 32 | 33 | /// Структура для сериализации JSON-a возвращающий название продукта 34 | struct Name : Decodable { 35 | let status : Int 36 | let names : [String] 37 | } 38 | 39 | /// Структура для сериализации JSON-a возвращающий классификатор продукта 40 | struct Class : Decodable { 41 | let status : Int 42 | let classification : [String] 43 | 44 | enum CodingKeys : String, CodingKey { 45 | case status 46 | case classification = "class" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Product/Presenter/ProductPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import Foundation 25 | 26 | protocol ProductPresenterProtocol { 27 | func viewDidLoad() -> () 28 | init(view: ProductViewControllerProtocol, product: Product) 29 | } 30 | 31 | final class ProductPresenter : ProductPresenterProtocol { 32 | 33 | private weak var view: ProductViewControllerProtocol? 34 | private var product: Product 35 | 36 | public func viewDidLoad() -> () { 37 | self.view?.set(image: self.product.image) 38 | self.view?.set(classification: self.product.classification) 39 | self.view?.set(name: self.product.name) 40 | self.view?.set(barcode: self.product.barcode) 41 | } 42 | 43 | init(view: ProductViewControllerProtocol, product: Product) { 44 | self.view = view 45 | self.product = product 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/onl1ner/onl1ner/blob/master/Resources/BarcodeScanner/Header.png) 2 | 3 | ## What is it? 4 | **BarcodeScanner – simple & easy application that helps you to scan both EAN8 and EAN13 barcodes.** 5 | 6 | ## How the app works 7 | To scan a barcode simply point the camera at the code and you are done! No need to press a button or take a photo. Application will automaticaly recognise the code your camera pointing at. 8 | 9 | BarcodeScanner will give you information related to scanned product. Name of the product, it's class(if classified) and product's photo. To recognise the name and class application uses API of [OlegON's database](https://barcodes.olegon.ru "OlegON's database"). The photos are simply downloaded from Google via their [Google Custom Search API](https://developers.google.com/custom-search "Google Custom Search API"). 10 | 11 | ## License 12 | This application is distributed under the terms and conditions of the MIT license. 13 | ``` 14 | Copyright (c) 2021 Tamerlan Satualdypov 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining 17 | a copy of this software and associated documentation files (the 18 | "Software"), to deal in the Software without restriction, including 19 | without limitation the rights to use, copy, modify, merge, publish, 20 | distribute, sublicense, and/or sell copies of the Software, and to 21 | permit persons to whom the Software is furnished to do so, subject to 22 | the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included 25 | in all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 30 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 31 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 32 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 33 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Main/Router/MainRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import SwiftEntryKit 26 | 27 | protocol MainRouterProtocol { 28 | func show(product: Product) -> () 29 | func show(error: NetworkError) -> () 30 | 31 | init(view: MainViewController) 32 | } 33 | 34 | final class MainRouter: MainRouterProtocol { 35 | 36 | private weak var view : MainViewController? 37 | 38 | public func show(product: Product) -> () { 39 | let modal = ProductBuilder.build(with: product, delegate: self.view) 40 | SwiftEntryKit.display(entry: modal.view, using: modal.attributes) 41 | } 42 | 43 | public func show(error: NetworkError) -> () { 44 | let modal = ErrorBuilder.build(with: error, delegate: self.view) 45 | SwiftEntryKit.display(entry: modal.view, using: modal.attributes) 46 | } 47 | 48 | init(view: MainViewController) { 49 | self.view = view 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | Разрешите доступ к камере, чтобы вы могли сканировать штрихкоды! 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | UISceneConfigurations 30 | 31 | UIWindowSceneSessionRoleApplication 32 | 33 | 34 | UISceneConfigurationName 35 | Default Configuration 36 | UISceneDelegateClassName 37 | $(PRODUCT_MODULE_NAME).SceneDelegate 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Error/Model/NetworkError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | enum NetworkError: Error { 27 | case notFound 28 | case transportError(Error) 29 | case badRequest 30 | case unexpected 31 | 32 | public var title: String { 33 | return "Произошла ошибка" 34 | } 35 | 36 | public var message: String { 37 | switch self { 38 | case .notFound: return "Похоже, что в базе данных не нашлось продуктов с подходящим штрихкодом." 39 | case .transportError(let error as NSError): return "Произошла ошибка при отправке данных на сервер. Код: \(error.code)" 40 | case .badRequest, .unexpected: return "Произошла непредвиденная ошибка." 41 | } 42 | } 43 | 44 | public var image: UIImage? { 45 | switch self { 46 | case .notFound: return .init(systemName: "tray.and.arrow.up") 47 | case .transportError(_): return .init(systemName: "wifi.exclamationmark") 48 | case .badRequest, .unexpected: return .init(systemName: "barcode.viewfinder") 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Main/Presenter/MainPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | protocol MainPresenterProtocol { 27 | func product(for barcode: String) -> () 28 | 29 | init(view: MainViewControllerProtocol, router: MainRouterProtocol) 30 | } 31 | 32 | final class MainPresenter: MainPresenterProtocol { 33 | 34 | private weak var view: MainViewControllerProtocol? 35 | private var router: MainRouterProtocol 36 | 37 | public func product(for barcode: String) -> () { 38 | self.view?.stopInput() 39 | self.view?.startLoading() 40 | 41 | NetworkService.shared.product(for: barcode) { result in 42 | self.view?.stopLoading() 43 | 44 | switch result { 45 | case .success(let product): self.router.show(product: product) 46 | case .failure(let error): self.router.show(error: error) 47 | } 48 | } 49 | } 50 | 51 | init(view: MainViewControllerProtocol, router: MainRouterProtocol) { 52 | self.view = view 53 | self.router = router 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Error/View/ErrorViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import SwiftEntryKit 26 | 27 | protocol ErrorViewControllerProtocol: AnyObject { 28 | func set(image : UIImage?) 29 | func set(title : String) -> () 30 | func set(message : String) -> () 31 | } 32 | 33 | final class ErrorViewController: UIViewController, ErrorViewControllerProtocol { 34 | 35 | @IBOutlet private weak var imageView: UIImageView! 36 | 37 | @IBOutlet private weak var titleLabel: UILabel! 38 | @IBOutlet private weak var messageLabel: UILabel! 39 | 40 | public var presenter : ErrorPresenterProtocol! 41 | 42 | @IBAction private func dismissPressed(_ sender: UIButton) -> () { 43 | SwiftEntryKit.dismiss() 44 | } 45 | 46 | public func set(image: UIImage?) -> () { 47 | self.imageView.image = image 48 | } 49 | 50 | public func set(title: String) -> () { 51 | self.titleLabel.text = title 52 | } 53 | 54 | public func set(message: String) -> () { 55 | self.messageLabel.text = message 56 | } 57 | 58 | override public func viewDidLoad() -> () { 59 | super.viewDidLoad() 60 | 61 | self.view.layer.cornerRadius = 16 62 | self.presenter.viewDidLoad() 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Components/STAlert/STAlert.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | final class STAlert { 27 | 28 | private var actionSheetController : UIAlertController 29 | 30 | public func prepared() -> UIAlertController { 31 | return self.actionSheetController 32 | } 33 | 34 | public func addAction(title: String, style: UIAlertAction.Style, actionHandler: ((UIAlertAction) -> ())?) -> Self { 35 | let action = UIAlertAction(title: title, style: style, handler: actionHandler) 36 | self.actionSheetController.addAction(action) 37 | return self 38 | } 39 | 40 | public func addCancel(title: String = "Cancel") -> Self { 41 | let cancelAction = UIAlertAction(title: title, style: .cancel, handler: nil) 42 | self.actionSheetController.addAction(cancelAction) 43 | return self 44 | } 45 | 46 | public convenience init(error: NSError) { 47 | self.init(title: "Error", message: "\(error.domain). Code: \(error.code)", preferredStyle: .alert) 48 | 49 | let action = UIAlertAction(title: "Ok", style: .cancel, handler: { _ in 50 | self.actionSheetController.dismiss(animated: true, completion: nil) 51 | }) 52 | 53 | self.actionSheetController.addAction(action) 54 | } 55 | 56 | public init(title: String? = nil, message: String? = nil, preferredStyle: UIAlertController.Style) { 57 | self.actionSheetController = .init(title: title, message: message, preferredStyle: preferredStyle) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /BarcodeScanner/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom": "iphone", 6 | "filename" : "Icon-20@2x.png", 7 | "scale": "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom": "iphone", 12 | "filename" : "Icon-20@3x.png", 13 | "scale": "3x" 14 | }, 15 | { 16 | "size" : "20x20", 17 | "idiom": "ipad", 18 | "filename" : "Icon-20.png", 19 | "scale": "1x" 20 | }, 21 | { 22 | "size" : "20x20", 23 | "idiom": "ipad", 24 | "filename" : "Icon-20@2x.png", 25 | "scale": "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-29@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "29x29", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-29@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-40@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "40x40", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-40@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-60@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "Icon-60@3x.png", 61 | "scale" : "3x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-29.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-29@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-40.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-40@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "Icon-1024.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Components/STModal/STModal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import SwiftEntryKit 26 | 27 | protocol STModalDelegate { 28 | func modalDidDisappear() -> () 29 | } 30 | 31 | final class STModal { 32 | 33 | public private(set) var view: UIViewController 34 | public private(set) var attributes: EKAttributes 35 | 36 | private var delegate: STModalDelegate? 37 | 38 | private func setDefaultAttributes() -> () { 39 | self.attributes.screenBackground = .color(color: .black.with(alpha: 0.25)) 40 | self.attributes.displayDuration = .infinity 41 | 42 | self.attributes.entryInteraction = .absorbTouches 43 | self.attributes.screenInteraction = .dismiss 44 | 45 | self.attributes.lifecycleEvents.didDisappear = self.delegate?.modalDidDisappear 46 | } 47 | 48 | public func set(position: EKAttributes.Position) -> Self { 49 | self.attributes.position = position 50 | return self 51 | } 52 | 53 | public func set(verticalOffset: CGFloat) -> Self { 54 | self.attributes.positionConstraints.verticalOffset = verticalOffset 55 | return self 56 | } 57 | 58 | public func set(width: EKAttributes.PositionConstraints.Edge) -> Self { 59 | self.attributes.positionConstraints.size.width = width 60 | return self 61 | } 62 | 63 | public func set(height: EKAttributes.PositionConstraints.Edge) -> Self { 64 | self.attributes.positionConstraints.size.height = height 65 | return self 66 | } 67 | 68 | public init(view: UIViewController, delegate: STModalDelegate? = nil) { 69 | self.view = view 70 | self.attributes = .init() 71 | 72 | self.delegate = delegate 73 | 74 | self.setDefaultAttributes() 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Product/View/ProductViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import SwiftEntryKit 26 | 27 | protocol ProductViewControllerProtocol: AnyObject { 28 | func set(image: UIImage?) -> () 29 | func set(classification: String) -> () 30 | func set(name: String) -> () 31 | func set(barcode: String) -> () 32 | } 33 | 34 | final class ProductViewController: UIViewController, ProductViewControllerProtocol { 35 | 36 | @IBOutlet private weak var imageBackView: UIView! 37 | @IBOutlet private weak var imageView: UIImageView! 38 | 39 | @IBOutlet private weak var classLabel: UILabel! 40 | @IBOutlet private weak var nameLabel: UILabel! 41 | 42 | @IBOutlet private weak var barcodeBackView: UIView! 43 | @IBOutlet private weak var barcodeLabel: UILabel! 44 | 45 | public var presenter: ProductPresenterProtocol! 46 | 47 | @IBAction private func dismissPressed(_ sender: UIButton) -> () { 48 | SwiftEntryKit.dismiss() 49 | } 50 | 51 | public func set(image: UIImage?) -> () { 52 | self.imageView.image = image 53 | } 54 | 55 | public func set(classification: String) -> () { 56 | self.classLabel.text = classification 57 | } 58 | 59 | public func set(name: String) -> () { 60 | self.nameLabel.text = name 61 | } 62 | 63 | public func set(barcode: String) -> () { 64 | self.barcodeLabel.text = barcode 65 | } 66 | 67 | override public func viewDidLoad() -> () { 68 | super.viewDidLoad() 69 | 70 | self.view.layer.cornerRadius = 16 71 | 72 | self.imageBackView.layer.cornerRadius = 20 73 | 74 | self.barcodeBackView.layer.cornerRadius = 16 75 | self.imageView.layer.cornerRadius = 16 76 | 77 | self.imageBackView.setupShadow(withColor: .black, opacity: 0.2, offset: .zero) 78 | self.barcodeBackView.setupShadow(withColor: .black, opacity: 0.2, offset: .zero) 79 | 80 | self.presenter.viewDidLoad() 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Components/STCamera/STScanArea.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import CoreGraphics 26 | 27 | final class STScanArea : UIView { 28 | 29 | public var sizeMultiplier : CGFloat = 0.2 { 30 | didSet{ 31 | self.draw(self.bounds) 32 | } 33 | } 34 | 35 | public var lineWidth : CGFloat = 5 { 36 | didSet{ 37 | self.draw(self.bounds) 38 | } 39 | } 40 | 41 | public var lineColor : UIColor = UIColor.white { 42 | didSet{ 43 | self.draw(self.bounds) 44 | } 45 | } 46 | 47 | private func drawCorners() -> () { 48 | /// Углы прямоугольника рисуются по часовой стрелке начиная с левого верхнего угла 49 | 50 | let currentContext = UIGraphicsGetCurrentContext() 51 | 52 | currentContext?.setLineWidth(lineWidth) 53 | currentContext?.setStrokeColor(lineColor.cgColor) 54 | 55 | /// Первая часть левого верхнего угла 56 | currentContext?.beginPath() 57 | currentContext?.move(to: CGPoint(x: 0, y: 0)) 58 | currentContext?.addLine(to: CGPoint(x: self.bounds.size.width * sizeMultiplier, y: 0)) 59 | currentContext?.strokePath() 60 | 61 | /// Правый верхний угол 62 | currentContext?.beginPath() 63 | currentContext?.move(to: CGPoint(x: self.bounds.size.width - self.bounds.size.width * sizeMultiplier, y: 0)) 64 | currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: 0)) 65 | currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height * sizeMultiplier)) 66 | currentContext?.strokePath() 67 | 68 | /// Правый нижний угол 69 | currentContext?.beginPath() 70 | currentContext?.move(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height - self.bounds.size.height * sizeMultiplier)) 71 | currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height)) 72 | currentContext?.addLine(to: CGPoint(x: self.bounds.size.width - self.bounds.size.width * sizeMultiplier, y: self.bounds.size.height)) 73 | currentContext?.strokePath() 74 | 75 | /// Левый нижний угол 76 | currentContext?.beginPath() 77 | currentContext?.move(to: CGPoint(x: self.bounds.size.width * sizeMultiplier, y: self.bounds.size.height)) 78 | currentContext?.addLine(to: CGPoint(x: 0, y: self.bounds.size.height)) 79 | currentContext?.addLine(to: CGPoint(x: 0, y: self.bounds.size.height - self.bounds.size.height * sizeMultiplier)) 80 | currentContext?.strokePath() 81 | 82 | /// Вторая часть левого верхнего угла 83 | currentContext?.beginPath() 84 | currentContext?.move(to: CGPoint(x: 0, y: self.bounds.size.height * sizeMultiplier)) 85 | currentContext?.addLine(to: CGPoint(x: 0, y: 0)) 86 | currentContext?.strokePath() 87 | } 88 | 89 | override public func draw(_ rect: CGRect) -> Void { 90 | super.draw(rect) 91 | self.drawCorners() 92 | } 93 | 94 | override init(frame: CGRect) { 95 | super.init(frame: frame) 96 | self.backgroundColor = UIColor.clear 97 | } 98 | 99 | required init?(coder: NSCoder) { 100 | super.init(coder: coder) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Main/View/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import SwiftEntryKit 26 | 27 | protocol MainViewControllerProtocol: AnyObject, STModalDelegate { 28 | func stopInput() -> () 29 | 30 | func startLoading() -> () 31 | func stopLoading() -> () 32 | } 33 | 34 | final class MainViewController: UIViewController, MainViewControllerProtocol { 35 | 36 | @IBOutlet private weak var toggleFlashlightButton : UIButton! 37 | 38 | @IBOutlet private weak var blurEffectView : UIVisualEffectView! 39 | @IBOutlet private weak var activityIndicator : UIActivityIndicatorView! 40 | 41 | private lazy var camera : STCameraProtocol = STCamera(frame: self.view.layer.bounds, delegate: self) 42 | 43 | public var presenter : MainPresenterProtocol! 44 | 45 | @IBAction private func toggleFlashlight(_ sender: UIButton) -> () { 46 | let status = self.camera.toggleFlashlight() 47 | 48 | switch status { 49 | case .on: sender.setImage(UIImage(systemName: "bolt.slash.circle.fill"), for: .normal) 50 | case .off: sender.setImage(UIImage(systemName: "bolt.circle.fill"), for: .normal) 51 | case .notFound: self.showAlert(title: "Произошла ошибка", message: "Похоже, что на вашем устройстве нет фонарика.") 52 | case .notInitialized: self.showAlert(title: "Произошла ошибка", message: "Не удалось переключить фонарик. Попробуйте еще раз.") 53 | } 54 | } 55 | 56 | private func createCamera() -> () { 57 | guard let cameraLayer = self.camera.layer else { return } 58 | self.view.layer.addSublayer(cameraLayer) 59 | 60 | self.camera.start() 61 | } 62 | 63 | private func startInput() -> () { 64 | self.camera.start() 65 | 66 | UIView.animate(withDuration: 0.2) { 67 | self.blurEffectView.alpha = 0.0 68 | } completion: { _ in 69 | self.blurEffectView.isHidden = true 70 | } 71 | } 72 | 73 | public func startLoading() -> () { 74 | self.activityIndicator.startAnimating() 75 | } 76 | 77 | public func stopLoading() -> () { 78 | self.activityIndicator.stopAnimating() 79 | } 80 | 81 | public func stopInput() -> () { 82 | self.blurEffectView.isHidden = false 83 | 84 | UIView.animate(withDuration: 0.2) { 85 | self.blurEffectView.alpha = 1.0 86 | } 87 | 88 | self.camera.stop() 89 | } 90 | 91 | override public func viewDidLoad() -> () { 92 | super.viewDidLoad() 93 | 94 | self.createCamera() 95 | 96 | self.view.bringSubviewToFront(self.toggleFlashlightButton) 97 | self.view.bringSubviewToFront(self.blurEffectView) 98 | } 99 | 100 | override public func viewDidLayoutSubviews() -> () { 101 | super.viewDidLayoutSubviews() 102 | self.camera.frame = view.layer.bounds 103 | } 104 | } 105 | 106 | extension MainViewController: STCameraDelegate { 107 | 108 | public func scanned(barcode: String) -> () { 109 | self.presenter.product(for: barcode) 110 | } 111 | 112 | } 113 | 114 | extension MainViewController: STModalDelegate { 115 | 116 | public func modalDidDisappear() -> () { 117 | self.startInput() 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Main/View/MainViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 33 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Components/STCamera/STCamera.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | import AVFoundation 26 | 27 | protocol STCameraDelegate { 28 | func scanned(barcode : String) -> () 29 | } 30 | 31 | protocol STCameraProtocol : AnyObject { 32 | var layer : AVCaptureVideoPreviewLayer? { get } 33 | var frame : CGRect { get set } 34 | 35 | func start() -> () 36 | func stop() -> () 37 | 38 | func toggleFlashlight() -> FlashlightStatus 39 | 40 | init(frame : CGRect, delegate : STCameraDelegate?) 41 | } 42 | 43 | final class STCamera : NSObject, STCameraProtocol { 44 | 45 | private let codeTypes: [AVMetadataObject.ObjectType] = [.ean8, .ean13] 46 | 47 | private var captureSession: AVCaptureSession = .init() 48 | private var delegate: STCameraDelegate? 49 | 50 | private var scanArea: STScanArea = .init(frame: .init(x: 0, y: 0, width: 250.0, height: 100.0)) 51 | 52 | public var layer: AVCaptureVideoPreviewLayer? 53 | 54 | public var frame: CGRect { 55 | didSet { 56 | self.layer?.frame = self.frame 57 | self.scanArea.center = self.center 58 | } 59 | } 60 | 61 | public var center: CGPoint { 62 | return .init(x: self.frame.width / 2, y: self.frame.height / 2) 63 | } 64 | 65 | private func configure() -> () { 66 | guard let captureDevice = AVCaptureDevice.default(for: .video) else { return } 67 | 68 | do { 69 | // Добавляем инпут как инстанс класса AVCaptureDeviceInput полученного девайса 70 | let input = try AVCaptureDeviceInput(device: captureDevice) 71 | self.captureSession.addInput(input) 72 | 73 | // Инициализируем оутпут, используя класс AVCaptureMetadataOutput и добавляем в нашу сессию 74 | let captureOutput = AVCaptureMetadataOutput() 75 | self.captureSession.addOutput(captureOutput) 76 | 77 | // Инициализуем наш делегат для получения всех сигналов 78 | captureOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) 79 | captureOutput.metadataObjectTypes = self.codeTypes 80 | captureOutput.rectOfInterest = self.scanArea.bounds 81 | 82 | } catch { return } 83 | 84 | // Инициализируем слой с превью видео 85 | self.layer = .init(session: self.captureSession) 86 | 87 | self.layer?.videoGravity = .resizeAspectFill 88 | self.layer?.frame = self.frame 89 | 90 | self.layer?.addSublayer(self.scanArea.layer) 91 | } 92 | 93 | public func stop() -> () { 94 | self.captureSession.stopRunning() 95 | } 96 | 97 | public func start() -> () { 98 | self.captureSession.startRunning() 99 | } 100 | 101 | public func toggleFlashlight() -> FlashlightStatus { 102 | guard let captureDevice = AVCaptureDevice.default(for: .video) else { return .notInitialized } 103 | 104 | if captureDevice.hasTorch { 105 | do { 106 | try captureDevice.lockForConfiguration() 107 | captureDevice.torchMode = captureDevice.torchMode == .off ? .on : .off 108 | captureDevice.unlockForConfiguration() 109 | 110 | return captureDevice.torchMode == .on ? .on : .off 111 | } catch let error { 112 | print("Cannot toggle flashlight: \(error.localizedDescription)") 113 | return .notInitialized 114 | } 115 | } else { return .notFound } 116 | } 117 | 118 | init(frame: CGRect, delegate: STCameraDelegate?) { 119 | self.frame = frame 120 | self.delegate = delegate 121 | 122 | super.init() 123 | 124 | self.configure() 125 | } 126 | } 127 | 128 | extension STCamera : AVCaptureMetadataOutputObjectsDelegate { 129 | public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) -> () { 130 | 131 | guard !metadataObjects.isEmpty, 132 | let metadataObj = metadataObjects.first as? AVMetadataMachineReadableCodeObject 133 | else { return } 134 | 135 | if self.codeTypes.contains(metadataObj.type) { 136 | if let barcode = metadataObj.stringValue { 137 | self.delegate?.scanned(barcode: barcode) 138 | } 139 | } 140 | 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /BarcodeScanner/Common/Services/Network/NetworkService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import UIKit 25 | 26 | protocol NetworkServiceProtocol { 27 | func product(for barcode : String, completion: @escaping (Result) -> ()) -> () 28 | } 29 | 30 | final class NetworkService : NetworkServiceProtocol { 31 | 32 | public static let shared : NetworkServiceProtocol = NetworkService() 33 | 34 | private let barcodeBase : String = "https://barcodes.olegon.ru/api/card/" 35 | 36 | private let imageBase : String = "https://www.googleapis.com/customsearch/v1" 37 | private let imageKey : String = "YOUR-API-KEY" 38 | private let imageEngineKey : String = "YOUR-SEARCH-ENGINE-KEY" 39 | 40 | private func deserialize(data : Data, as objectType : T.Type) -> T? { 41 | return try? JSONDecoder().decode(objectType, from: data) 42 | } 43 | 44 | private func createDataTask(with url: URL?, completion: @escaping (Data?, URLResponse?, Error?) -> ()) -> () { 45 | guard let url = url else { return } 46 | URLSession.shared.dataTask(with: url, completionHandler: completion).resume() 47 | } 48 | 49 | private func processDataTask(data: Data?, response: URLResponse?, error: Error?) -> Result { 50 | if let error = error { 51 | return .failure(.transportError(error)) 52 | } 53 | 54 | switch (response as! HTTPURLResponse).statusCode { 55 | case 400: return .failure(.badRequest) 56 | case 404: return .failure(.notFound) 57 | case 429: return .failure(.unexpected) 58 | default: break 59 | } 60 | 61 | if let data = data { 62 | if let deserialized = self.deserialize(data: data, as: T.self) { 63 | return .success(deserialized) 64 | } 65 | } 66 | 67 | return .failure(.unexpected) 68 | } 69 | 70 | private func image(from url: URL?, completion: @escaping (UIImage?) -> ()) -> () { 71 | self.createDataTask(with: url) { data, _, error in 72 | guard error == nil, let data = data else { return completion(nil) } 73 | completion(.init(data: data)) 74 | } 75 | } 76 | 77 | private func productImage(for barcode : String, completion: @escaping (UIImage?) -> ()) -> () { 78 | let queryParameters = [URLQueryItem(name: "key", value: self.imageKey), 79 | URLQueryItem(name: "cx", value: self.imageEngineKey), 80 | URLQueryItem(name: "searchType", value: "image"), 81 | URLQueryItem(name: "q", value: barcode), 82 | URLQueryItem(name: "fields", value: "items(link)")] 83 | 84 | var components = URLComponents(string: self.imageBase) 85 | components?.queryItems = queryParameters 86 | 87 | self.createDataTask(with: components?.url) { data, response, error in 88 | if let data = data { 89 | guard let object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments), 90 | let dictionary = object as? [String : Any], 91 | let items = dictionary["items"] as? NSArray, 92 | let item = items.firstObject as? [String : String], 93 | let link = item["link"] 94 | else { return completion(nil) } 95 | 96 | self.image(from: URL(string: link), completion: completion) 97 | } 98 | } 99 | } 100 | 101 | private func productName(for barcode: String, completion: @escaping (Result) -> ()) -> () { 102 | let url = URL(string: self.barcodeBase + "name/\(barcode)") 103 | 104 | self.createDataTask(with: url) { data, response, error in 105 | completion(self.processDataTask(data: data, response: response, error: error)) 106 | } 107 | } 108 | 109 | private func productClass(for barcode: String, completion: @escaping (Result) -> ()) -> () { 110 | let url = URL(string: self.barcodeBase + "class/\(barcode)") 111 | 112 | self.createDataTask(with: url) { data, response, error in 113 | completion(self.processDataTask(data: data, response: response, error: error)) 114 | } 115 | } 116 | 117 | public func product(for barcode : String, completion: @escaping (Result) -> ()) -> () { 118 | var classification : String = "Не классифицирован" 119 | var name : String = "Наименование продукта" 120 | var image : UIImage? 121 | 122 | var error : NetworkError? 123 | 124 | let group : DispatchGroup = .init() 125 | 126 | group.enter() 127 | 128 | self.productClass(for: barcode) { result in 129 | switch result { 130 | case .success(let response): classification = response 131 | case .failure(_): classification = "Не классифицирован" 132 | } 133 | 134 | group.leave() 135 | } 136 | 137 | group.enter() 138 | 139 | self.productName(for: barcode) { result in 140 | switch result { 141 | case .success(let response): name = response 142 | case .failure(let response): error = response 143 | } 144 | 145 | group.leave() 146 | } 147 | 148 | group.enter() 149 | 150 | self.productImage(for: barcode) { response in 151 | image = response 152 | group.leave() 153 | } 154 | 155 | group.notify(queue: .main) { 156 | if let error = error { 157 | completion(.failure(error)) 158 | } else { 159 | let product : Product = .init(classification: classification, name: name, barcode: barcode, image: image) 160 | completion(.success(product)) 161 | } 162 | } 163 | } 164 | 165 | private init() { } 166 | } 167 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Error/View/ErrorViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ProximaNovaExCn-Bold 13 | 14 | 15 | ProximaNovaExCn-Regular 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /BarcodeScanner/Modules/Product/View/ProductViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ProximaNovaExCn-Light 14 | 15 | 16 | ProximaNovaExCn-Regular 17 | 18 | 19 | ProximaNovaExCn-Thin 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 104 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /BarcodeScanner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0806B0B326A2B96400489884 /* FlashlightStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0B226A2B96400489884 /* FlashlightStatus.swift */; }; 11 | 0806B0B726A2BBB600489884 /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0B626A2BBB600489884 /* MainRouter.swift */; }; 12 | 0806B0BB26A2BD7B00489884 /* MainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0BA26A2BD7B00489884 /* MainBuilder.swift */; }; 13 | 0806B0BF26A2C14700489884 /* STModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0BE26A2C14700489884 /* STModal.swift */; }; 14 | 0806B0C226A2C17000489884 /* STAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0C126A2C16F00489884 /* STAlert.swift */; }; 15 | 0806B0C526A2C2F900489884 /* ErrorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0C426A2C2F900489884 /* ErrorPresenter.swift */; }; 16 | 0806B0C826A2C3F700489884 /* ErrorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0C726A2C3F700489884 /* ErrorBuilder.swift */; }; 17 | 0806B0CB26A2C4B400489884 /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0CA26A2C4B400489884 /* NetworkError.swift */; }; 18 | 0806B0CE26A2CB8800489884 /* ProductPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0CD26A2CB8800489884 /* ProductPresenter.swift */; }; 19 | 0806B0D126A2CC0D00489884 /* ProductBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0D026A2CC0D00489884 /* ProductBuilder.swift */; }; 20 | 0806B0D526A2DE6D00489884 /* STScanArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0806B0D426A2DE6D00489884 /* STScanArea.swift */; }; 21 | 9220A0F0250132D4000562F3 /* MainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9220A0EA250132D4000562F3 /* MainPresenter.swift */; }; 22 | 9220A0F1250132D4000562F3 /* Product.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9220A0EC250132D4000562F3 /* Product.swift */; }; 23 | 9220A0F2250132D4000562F3 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9220A0EE250132D4000562F3 /* MainViewController.xib */; }; 24 | 9220A0F3250132D4000562F3 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9220A0EF250132D4000562F3 /* MainViewController.swift */; }; 25 | 9220A0F6250132EC000562F3 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9220A0F5250132EC000562F3 /* UIViewController.swift */; }; 26 | 9220A0FC250132F7000562F3 /* STCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9220A0F9250132F7000562F3 /* STCamera.swift */; }; 27 | 9220A0FD250132F7000562F3 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9220A0FB250132F7000562F3 /* NetworkService.swift */; }; 28 | 924521202427CCB00050F4DD /* ProductViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9245211F2427CCB00050F4DD /* ProductViewController.xib */; }; 29 | 924521222427CCDA0050F4DD /* ProductViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924521212427CCDA0050F4DD /* ProductViewController.swift */; }; 30 | 9254558024265D65007F5FD4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9254557F24265D65007F5FD4 /* AppDelegate.swift */; }; 31 | 9254558224265D65007F5FD4 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9254558124265D65007F5FD4 /* SceneDelegate.swift */; }; 32 | 9254558924265D66007F5FD4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9254558824265D66007F5FD4 /* Assets.xcassets */; }; 33 | 9254558C24265D66007F5FD4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9254558A24265D66007F5FD4 /* LaunchScreen.storyboard */; }; 34 | 92ECA710242920D000CCE0B7 /* ProximaNovaExCn-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 92ECA6E6242920D000CCE0B7 /* ProximaNovaExCn-Thin.ttf */; }; 35 | 92ECA711242920D000CCE0B7 /* ProximaNovaExCn-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 92ECA6E7242920D000CCE0B7 /* ProximaNovaExCn-Light.ttf */; }; 36 | 92ECA717242920D000CCE0B7 /* ProximaNovaExCn-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 92ECA6ED242920D000CCE0B7 /* ProximaNovaExCn-Regular.ttf */; }; 37 | 92ECA71C242920D000CCE0B7 /* ProximaNovaExCn-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 92ECA6F2242920D000CCE0B7 /* ProximaNovaExCn-Bold.ttf */; }; 38 | 92ECA7342429297E00CCE0B7 /* ErrorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 92ECA7332429297E00CCE0B7 /* ErrorViewController.xib */; }; 39 | 92ECA73624292C7F00CCE0B7 /* ErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92ECA73524292C7F00CCE0B7 /* ErrorViewController.swift */; }; 40 | 92ECA738242A347800CCE0B7 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92ECA737242A347800CCE0B7 /* UIView.swift */; }; 41 | E9EF20C0E411E9E836F053D9 /* libPods-BarcodeScanner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F63026D1ABCF9F9F9E9B3E1D /* libPods-BarcodeScanner.a */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 0806B0B226A2B96400489884 /* FlashlightStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashlightStatus.swift; sourceTree = ""; }; 46 | 0806B0B626A2BBB600489884 /* MainRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRouter.swift; sourceTree = ""; }; 47 | 0806B0BA26A2BD7B00489884 /* MainBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainBuilder.swift; sourceTree = ""; }; 48 | 0806B0BE26A2C14700489884 /* STModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STModal.swift; sourceTree = ""; }; 49 | 0806B0C126A2C16F00489884 /* STAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STAlert.swift; sourceTree = ""; }; 50 | 0806B0C426A2C2F900489884 /* ErrorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPresenter.swift; sourceTree = ""; }; 51 | 0806B0C726A2C3F700489884 /* ErrorBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorBuilder.swift; sourceTree = ""; }; 52 | 0806B0CA26A2C4B400489884 /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; 53 | 0806B0CD26A2CB8800489884 /* ProductPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductPresenter.swift; sourceTree = ""; }; 54 | 0806B0D026A2CC0D00489884 /* ProductBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductBuilder.swift; sourceTree = ""; }; 55 | 0806B0D426A2DE6D00489884 /* STScanArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STScanArea.swift; sourceTree = ""; }; 56 | 79180CF1F92ACB640AF74021 /* Pods-BarcodeScanner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BarcodeScanner.debug.xcconfig"; path = "Target Support Files/Pods-BarcodeScanner/Pods-BarcodeScanner.debug.xcconfig"; sourceTree = ""; }; 57 | 9220A0EA250132D4000562F3 /* MainPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainPresenter.swift; sourceTree = ""; }; 58 | 9220A0EC250132D4000562F3 /* Product.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Product.swift; sourceTree = ""; }; 59 | 9220A0EE250132D4000562F3 /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; 60 | 9220A0EF250132D4000562F3 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 61 | 9220A0F5250132EC000562F3 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; 62 | 9220A0F9250132F7000562F3 /* STCamera.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = STCamera.swift; sourceTree = ""; }; 63 | 9220A0FB250132F7000562F3 /* NetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; 64 | 9245211F2427CCB00050F4DD /* ProductViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProductViewController.xib; sourceTree = ""; }; 65 | 924521212427CCDA0050F4DD /* ProductViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductViewController.swift; sourceTree = ""; }; 66 | 9254557C24265D65007F5FD4 /* BarcodeScanner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BarcodeScanner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 9254557F24265D65007F5FD4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 68 | 9254558124265D65007F5FD4 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 69 | 9254558824265D66007F5FD4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 70 | 9254558B24265D66007F5FD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 71 | 9254558D24265D66007F5FD4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | 92ECA6E6242920D000CCE0B7 /* ProximaNovaExCn-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ProximaNovaExCn-Thin.ttf"; sourceTree = ""; }; 73 | 92ECA6E7242920D000CCE0B7 /* ProximaNovaExCn-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ProximaNovaExCn-Light.ttf"; sourceTree = ""; }; 74 | 92ECA6ED242920D000CCE0B7 /* ProximaNovaExCn-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ProximaNovaExCn-Regular.ttf"; sourceTree = ""; }; 75 | 92ECA6F2242920D000CCE0B7 /* ProximaNovaExCn-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ProximaNovaExCn-Bold.ttf"; sourceTree = ""; }; 76 | 92ECA7332429297E00CCE0B7 /* ErrorViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ErrorViewController.xib; sourceTree = ""; }; 77 | 92ECA73524292C7F00CCE0B7 /* ErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorViewController.swift; sourceTree = ""; }; 78 | 92ECA737242A347800CCE0B7 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; 79 | EF879855EA857755783B90DA /* Pods-BarcodeScanner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BarcodeScanner.release.xcconfig"; path = "Target Support Files/Pods-BarcodeScanner/Pods-BarcodeScanner.release.xcconfig"; sourceTree = ""; }; 80 | F63026D1ABCF9F9F9E9B3E1D /* libPods-BarcodeScanner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BarcodeScanner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | /* End PBXFileReference section */ 82 | 83 | /* Begin PBXFrameworksBuildPhase section */ 84 | 9254557924265D65007F5FD4 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | E9EF20C0E411E9E836F053D9 /* libPods-BarcodeScanner.a in Frameworks */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXFrameworksBuildPhase section */ 93 | 94 | /* Begin PBXGroup section */ 95 | 0806B0B026A2B95200489884 /* Components */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 0806B0C026A2C15900489884 /* STAlert */, 99 | 0806B0BD26A2C12E00489884 /* STModal */, 100 | 0806B0B126A2B95800489884 /* STCamera */, 101 | ); 102 | path = Components; 103 | sourceTree = ""; 104 | }; 105 | 0806B0B126A2B95800489884 /* STCamera */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 9220A0F9250132F7000562F3 /* STCamera.swift */, 109 | 0806B0D426A2DE6D00489884 /* STScanArea.swift */, 110 | 0806B0B226A2B96400489884 /* FlashlightStatus.swift */, 111 | ); 112 | path = STCamera; 113 | sourceTree = ""; 114 | }; 115 | 0806B0B526A2BBAD00489884 /* Router */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 0806B0B626A2BBB600489884 /* MainRouter.swift */, 119 | ); 120 | path = Router; 121 | sourceTree = ""; 122 | }; 123 | 0806B0B926A2BD7400489884 /* Builder */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 0806B0BA26A2BD7B00489884 /* MainBuilder.swift */, 127 | ); 128 | path = Builder; 129 | sourceTree = ""; 130 | }; 131 | 0806B0BD26A2C12E00489884 /* STModal */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 0806B0BE26A2C14700489884 /* STModal.swift */, 135 | ); 136 | path = STModal; 137 | sourceTree = ""; 138 | }; 139 | 0806B0C026A2C15900489884 /* STAlert */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 0806B0C126A2C16F00489884 /* STAlert.swift */, 143 | ); 144 | path = STAlert; 145 | sourceTree = ""; 146 | }; 147 | 0806B0C326A2C2EE00489884 /* Presenter */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 0806B0C426A2C2F900489884 /* ErrorPresenter.swift */, 151 | ); 152 | path = Presenter; 153 | sourceTree = ""; 154 | }; 155 | 0806B0C626A2C3E600489884 /* Builder */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 0806B0C726A2C3F700489884 /* ErrorBuilder.swift */, 159 | ); 160 | path = Builder; 161 | sourceTree = ""; 162 | }; 163 | 0806B0C926A2C48D00489884 /* Model */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 0806B0CA26A2C4B400489884 /* NetworkError.swift */, 167 | ); 168 | path = Model; 169 | sourceTree = ""; 170 | }; 171 | 0806B0CC26A2CB7C00489884 /* Presenter */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 0806B0CD26A2CB8800489884 /* ProductPresenter.swift */, 175 | ); 176 | path = Presenter; 177 | sourceTree = ""; 178 | }; 179 | 0806B0CF26A2CC0400489884 /* Builder */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 0806B0D026A2CC0D00489884 /* ProductBuilder.swift */, 183 | ); 184 | path = Builder; 185 | sourceTree = ""; 186 | }; 187 | 08FBAB7926A20BA000DF4592 /* Supporting Files */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 92ECA6DE242920D000CCE0B7 /* Font */, 191 | 9254558D24265D66007F5FD4 /* Info.plist */, 192 | 9254557F24265D65007F5FD4 /* AppDelegate.swift */, 193 | 9254558124265D65007F5FD4 /* SceneDelegate.swift */, 194 | 9254558824265D66007F5FD4 /* Assets.xcassets */, 195 | 9254558A24265D66007F5FD4 /* LaunchScreen.storyboard */, 196 | ); 197 | path = "Supporting Files"; 198 | sourceTree = ""; 199 | }; 200 | 08FBAB7A26A20C9100DF4592 /* Modules */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | 08FBAB8026A20DA200DF4592 /* Error */, 204 | 08FBAB7E26A20D5800DF4592 /* Product */, 205 | 08FBAB7B26A20C9500DF4592 /* Main */, 206 | ); 207 | path = Modules; 208 | sourceTree = ""; 209 | }; 210 | 08FBAB7B26A20C9500DF4592 /* Main */ = { 211 | isa = PBXGroup; 212 | children = ( 213 | 9220A0ED250132D4000562F3 /* View */, 214 | 9220A0E9250132D4000562F3 /* Presenter */, 215 | 0806B0B526A2BBAD00489884 /* Router */, 216 | 0806B0B926A2BD7400489884 /* Builder */, 217 | ); 218 | path = Main; 219 | sourceTree = ""; 220 | }; 221 | 08FBAB7C26A20CB100DF4592 /* Common */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 0806B0B026A2B95200489884 /* Components */, 225 | 9220A0F7250132F7000562F3 /* Services */, 226 | 08FBAB7D26A20CB500DF4592 /* Extensions */, 227 | ); 228 | path = Common; 229 | sourceTree = ""; 230 | }; 231 | 08FBAB7D26A20CB500DF4592 /* Extensions */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | 92ECA737242A347800CCE0B7 /* UIView.swift */, 235 | 9220A0F5250132EC000562F3 /* UIViewController.swift */, 236 | ); 237 | path = Extensions; 238 | sourceTree = ""; 239 | }; 240 | 08FBAB7E26A20D5800DF4592 /* Product */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 9220A0EB250132D4000562F3 /* Model */, 244 | 08FBAB7F26A20D6400DF4592 /* View */, 245 | 0806B0CC26A2CB7C00489884 /* Presenter */, 246 | 0806B0CF26A2CC0400489884 /* Builder */, 247 | ); 248 | path = Product; 249 | sourceTree = ""; 250 | }; 251 | 08FBAB7F26A20D6400DF4592 /* View */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 9245211F2427CCB00050F4DD /* ProductViewController.xib */, 255 | 924521212427CCDA0050F4DD /* ProductViewController.swift */, 256 | ); 257 | path = View; 258 | sourceTree = ""; 259 | }; 260 | 08FBAB8026A20DA200DF4592 /* Error */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | 0806B0C926A2C48D00489884 /* Model */, 264 | 08FBAB8126A20DA700DF4592 /* View */, 265 | 0806B0C326A2C2EE00489884 /* Presenter */, 266 | 0806B0C626A2C3E600489884 /* Builder */, 267 | ); 268 | path = Error; 269 | sourceTree = ""; 270 | }; 271 | 08FBAB8126A20DA700DF4592 /* View */ = { 272 | isa = PBXGroup; 273 | children = ( 274 | 92ECA7332429297E00CCE0B7 /* ErrorViewController.xib */, 275 | 92ECA73524292C7F00CCE0B7 /* ErrorViewController.swift */, 276 | ); 277 | path = View; 278 | sourceTree = ""; 279 | }; 280 | 1D168A74C45B9B979B0659DA /* Pods */ = { 281 | isa = PBXGroup; 282 | children = ( 283 | 79180CF1F92ACB640AF74021 /* Pods-BarcodeScanner.debug.xcconfig */, 284 | EF879855EA857755783B90DA /* Pods-BarcodeScanner.release.xcconfig */, 285 | ); 286 | path = Pods; 287 | sourceTree = ""; 288 | }; 289 | 9220A0E9250132D4000562F3 /* Presenter */ = { 290 | isa = PBXGroup; 291 | children = ( 292 | 9220A0EA250132D4000562F3 /* MainPresenter.swift */, 293 | ); 294 | path = Presenter; 295 | sourceTree = ""; 296 | }; 297 | 9220A0EB250132D4000562F3 /* Model */ = { 298 | isa = PBXGroup; 299 | children = ( 300 | 9220A0EC250132D4000562F3 /* Product.swift */, 301 | ); 302 | path = Model; 303 | sourceTree = ""; 304 | }; 305 | 9220A0ED250132D4000562F3 /* View */ = { 306 | isa = PBXGroup; 307 | children = ( 308 | 9220A0EE250132D4000562F3 /* MainViewController.xib */, 309 | 9220A0EF250132D4000562F3 /* MainViewController.swift */, 310 | ); 311 | path = View; 312 | sourceTree = ""; 313 | }; 314 | 9220A0F7250132F7000562F3 /* Services */ = { 315 | isa = PBXGroup; 316 | children = ( 317 | 9220A0FA250132F7000562F3 /* Network */, 318 | ); 319 | path = Services; 320 | sourceTree = ""; 321 | }; 322 | 9220A0FA250132F7000562F3 /* Network */ = { 323 | isa = PBXGroup; 324 | children = ( 325 | 9220A0FB250132F7000562F3 /* NetworkService.swift */, 326 | ); 327 | path = Network; 328 | sourceTree = ""; 329 | }; 330 | 9254557324265D65007F5FD4 = { 331 | isa = PBXGroup; 332 | children = ( 333 | 9254557E24265D65007F5FD4 /* BarcodeScanner */, 334 | 9254557D24265D65007F5FD4 /* Products */, 335 | 1D168A74C45B9B979B0659DA /* Pods */, 336 | ADF2B6EB63A2FEF070267165 /* Frameworks */, 337 | ); 338 | sourceTree = ""; 339 | }; 340 | 9254557D24265D65007F5FD4 /* Products */ = { 341 | isa = PBXGroup; 342 | children = ( 343 | 9254557C24265D65007F5FD4 /* BarcodeScanner.app */, 344 | ); 345 | name = Products; 346 | sourceTree = ""; 347 | }; 348 | 9254557E24265D65007F5FD4 /* BarcodeScanner */ = { 349 | isa = PBXGroup; 350 | children = ( 351 | 08FBAB7C26A20CB100DF4592 /* Common */, 352 | 08FBAB7A26A20C9100DF4592 /* Modules */, 353 | 08FBAB7926A20BA000DF4592 /* Supporting Files */, 354 | ); 355 | path = BarcodeScanner; 356 | sourceTree = ""; 357 | }; 358 | 92ECA6DE242920D000CCE0B7 /* Font */ = { 359 | isa = PBXGroup; 360 | children = ( 361 | 92ECA6E6242920D000CCE0B7 /* ProximaNovaExCn-Thin.ttf */, 362 | 92ECA6E7242920D000CCE0B7 /* ProximaNovaExCn-Light.ttf */, 363 | 92ECA6ED242920D000CCE0B7 /* ProximaNovaExCn-Regular.ttf */, 364 | 92ECA6F2242920D000CCE0B7 /* ProximaNovaExCn-Bold.ttf */, 365 | ); 366 | path = Font; 367 | sourceTree = ""; 368 | }; 369 | ADF2B6EB63A2FEF070267165 /* Frameworks */ = { 370 | isa = PBXGroup; 371 | children = ( 372 | F63026D1ABCF9F9F9E9B3E1D /* libPods-BarcodeScanner.a */, 373 | ); 374 | name = Frameworks; 375 | sourceTree = ""; 376 | }; 377 | /* End PBXGroup section */ 378 | 379 | /* Begin PBXNativeTarget section */ 380 | 9254557B24265D65007F5FD4 /* BarcodeScanner */ = { 381 | isa = PBXNativeTarget; 382 | buildConfigurationList = 9254559024265D66007F5FD4 /* Build configuration list for PBXNativeTarget "BarcodeScanner" */; 383 | buildPhases = ( 384 | DE18BDFE1ACC8162E13A9DD2 /* [CP] Check Pods Manifest.lock */, 385 | 9254557824265D65007F5FD4 /* Sources */, 386 | 9254557924265D65007F5FD4 /* Frameworks */, 387 | 9254557A24265D65007F5FD4 /* Resources */, 388 | ); 389 | buildRules = ( 390 | ); 391 | dependencies = ( 392 | ); 393 | name = BarcodeScanner; 394 | productName = BarcodeScanner; 395 | productReference = 9254557C24265D65007F5FD4 /* BarcodeScanner.app */; 396 | productType = "com.apple.product-type.application"; 397 | }; 398 | /* End PBXNativeTarget section */ 399 | 400 | /* Begin PBXProject section */ 401 | 9254557424265D65007F5FD4 /* Project object */ = { 402 | isa = PBXProject; 403 | attributes = { 404 | LastSwiftUpdateCheck = 1130; 405 | LastUpgradeCheck = 1130; 406 | ORGANIZATIONNAME = "onl1ner onl1ner"; 407 | TargetAttributes = { 408 | 9254557B24265D65007F5FD4 = { 409 | CreatedOnToolsVersion = 11.3.1; 410 | }; 411 | }; 412 | }; 413 | buildConfigurationList = 9254557724265D65007F5FD4 /* Build configuration list for PBXProject "BarcodeScanner" */; 414 | compatibilityVersion = "Xcode 9.3"; 415 | developmentRegion = en; 416 | hasScannedForEncodings = 0; 417 | knownRegions = ( 418 | en, 419 | Base, 420 | ); 421 | mainGroup = 9254557324265D65007F5FD4; 422 | productRefGroup = 9254557D24265D65007F5FD4 /* Products */; 423 | projectDirPath = ""; 424 | projectRoot = ""; 425 | targets = ( 426 | 9254557B24265D65007F5FD4 /* BarcodeScanner */, 427 | ); 428 | }; 429 | /* End PBXProject section */ 430 | 431 | /* Begin PBXResourcesBuildPhase section */ 432 | 9254557A24265D65007F5FD4 /* Resources */ = { 433 | isa = PBXResourcesBuildPhase; 434 | buildActionMask = 2147483647; 435 | files = ( 436 | 92ECA7342429297E00CCE0B7 /* ErrorViewController.xib in Resources */, 437 | 9254558C24265D66007F5FD4 /* LaunchScreen.storyboard in Resources */, 438 | 92ECA711242920D000CCE0B7 /* ProximaNovaExCn-Light.ttf in Resources */, 439 | 9254558924265D66007F5FD4 /* Assets.xcassets in Resources */, 440 | 92ECA717242920D000CCE0B7 /* ProximaNovaExCn-Regular.ttf in Resources */, 441 | 924521202427CCB00050F4DD /* ProductViewController.xib in Resources */, 442 | 92ECA71C242920D000CCE0B7 /* ProximaNovaExCn-Bold.ttf in Resources */, 443 | 9220A0F2250132D4000562F3 /* MainViewController.xib in Resources */, 444 | 92ECA710242920D000CCE0B7 /* ProximaNovaExCn-Thin.ttf in Resources */, 445 | ); 446 | runOnlyForDeploymentPostprocessing = 0; 447 | }; 448 | /* End PBXResourcesBuildPhase section */ 449 | 450 | /* Begin PBXShellScriptBuildPhase section */ 451 | DE18BDFE1ACC8162E13A9DD2 /* [CP] Check Pods Manifest.lock */ = { 452 | isa = PBXShellScriptBuildPhase; 453 | buildActionMask = 2147483647; 454 | files = ( 455 | ); 456 | inputFileListPaths = ( 457 | ); 458 | inputPaths = ( 459 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 460 | "${PODS_ROOT}/Manifest.lock", 461 | ); 462 | name = "[CP] Check Pods Manifest.lock"; 463 | outputFileListPaths = ( 464 | ); 465 | outputPaths = ( 466 | "$(DERIVED_FILE_DIR)/Pods-BarcodeScanner-checkManifestLockResult.txt", 467 | ); 468 | runOnlyForDeploymentPostprocessing = 0; 469 | shellPath = /bin/sh; 470 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 471 | showEnvVarsInLog = 0; 472 | }; 473 | /* End PBXShellScriptBuildPhase section */ 474 | 475 | /* Begin PBXSourcesBuildPhase section */ 476 | 9254557824265D65007F5FD4 /* Sources */ = { 477 | isa = PBXSourcesBuildPhase; 478 | buildActionMask = 2147483647; 479 | files = ( 480 | 924521222427CCDA0050F4DD /* ProductViewController.swift in Sources */, 481 | 0806B0CB26A2C4B400489884 /* NetworkError.swift in Sources */, 482 | 0806B0B726A2BBB600489884 /* MainRouter.swift in Sources */, 483 | 9220A0FD250132F7000562F3 /* NetworkService.swift in Sources */, 484 | 9254558024265D65007F5FD4 /* AppDelegate.swift in Sources */, 485 | 0806B0D126A2CC0D00489884 /* ProductBuilder.swift in Sources */, 486 | 0806B0D526A2DE6D00489884 /* STScanArea.swift in Sources */, 487 | 9220A0F3250132D4000562F3 /* MainViewController.swift in Sources */, 488 | 0806B0C826A2C3F700489884 /* ErrorBuilder.swift in Sources */, 489 | 9220A0FC250132F7000562F3 /* STCamera.swift in Sources */, 490 | 9220A0F0250132D4000562F3 /* MainPresenter.swift in Sources */, 491 | 9254558224265D65007F5FD4 /* SceneDelegate.swift in Sources */, 492 | 0806B0B326A2B96400489884 /* FlashlightStatus.swift in Sources */, 493 | 92ECA738242A347800CCE0B7 /* UIView.swift in Sources */, 494 | 0806B0CE26A2CB8800489884 /* ProductPresenter.swift in Sources */, 495 | 0806B0C526A2C2F900489884 /* ErrorPresenter.swift in Sources */, 496 | 0806B0BF26A2C14700489884 /* STModal.swift in Sources */, 497 | 0806B0C226A2C17000489884 /* STAlert.swift in Sources */, 498 | 0806B0BB26A2BD7B00489884 /* MainBuilder.swift in Sources */, 499 | 92ECA73624292C7F00CCE0B7 /* ErrorViewController.swift in Sources */, 500 | 9220A0F1250132D4000562F3 /* Product.swift in Sources */, 501 | 9220A0F6250132EC000562F3 /* UIViewController.swift in Sources */, 502 | ); 503 | runOnlyForDeploymentPostprocessing = 0; 504 | }; 505 | /* End PBXSourcesBuildPhase section */ 506 | 507 | /* Begin PBXVariantGroup section */ 508 | 9254558A24265D66007F5FD4 /* LaunchScreen.storyboard */ = { 509 | isa = PBXVariantGroup; 510 | children = ( 511 | 9254558B24265D66007F5FD4 /* Base */, 512 | ); 513 | name = LaunchScreen.storyboard; 514 | sourceTree = ""; 515 | }; 516 | /* End PBXVariantGroup section */ 517 | 518 | /* Begin XCBuildConfiguration section */ 519 | 9254558E24265D66007F5FD4 /* Debug */ = { 520 | isa = XCBuildConfiguration; 521 | buildSettings = { 522 | ALWAYS_SEARCH_USER_PATHS = NO; 523 | CLANG_ANALYZER_NONNULL = YES; 524 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 525 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 526 | CLANG_CXX_LIBRARY = "libc++"; 527 | CLANG_ENABLE_MODULES = YES; 528 | CLANG_ENABLE_OBJC_ARC = YES; 529 | CLANG_ENABLE_OBJC_WEAK = YES; 530 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 531 | CLANG_WARN_BOOL_CONVERSION = YES; 532 | CLANG_WARN_COMMA = YES; 533 | CLANG_WARN_CONSTANT_CONVERSION = YES; 534 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 535 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 536 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 537 | CLANG_WARN_EMPTY_BODY = YES; 538 | CLANG_WARN_ENUM_CONVERSION = YES; 539 | CLANG_WARN_INFINITE_RECURSION = YES; 540 | CLANG_WARN_INT_CONVERSION = YES; 541 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 542 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 543 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 544 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 545 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 546 | CLANG_WARN_STRICT_PROTOTYPES = YES; 547 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 548 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 549 | CLANG_WARN_UNREACHABLE_CODE = YES; 550 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 551 | COPY_PHASE_STRIP = NO; 552 | DEBUG_INFORMATION_FORMAT = dwarf; 553 | ENABLE_STRICT_OBJC_MSGSEND = YES; 554 | ENABLE_TESTABILITY = YES; 555 | GCC_C_LANGUAGE_STANDARD = gnu11; 556 | GCC_DYNAMIC_NO_PIC = NO; 557 | GCC_NO_COMMON_BLOCKS = YES; 558 | GCC_OPTIMIZATION_LEVEL = 0; 559 | GCC_PREPROCESSOR_DEFINITIONS = ( 560 | "DEBUG=1", 561 | "$(inherited)", 562 | ); 563 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 564 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 565 | GCC_WARN_UNDECLARED_SELECTOR = YES; 566 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 567 | GCC_WARN_UNUSED_FUNCTION = YES; 568 | GCC_WARN_UNUSED_VARIABLE = YES; 569 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 570 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 571 | MTL_FAST_MATH = YES; 572 | ONLY_ACTIVE_ARCH = YES; 573 | SDKROOT = iphoneos; 574 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 575 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 576 | }; 577 | name = Debug; 578 | }; 579 | 9254558F24265D66007F5FD4 /* Release */ = { 580 | isa = XCBuildConfiguration; 581 | buildSettings = { 582 | ALWAYS_SEARCH_USER_PATHS = NO; 583 | CLANG_ANALYZER_NONNULL = YES; 584 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 585 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 586 | CLANG_CXX_LIBRARY = "libc++"; 587 | CLANG_ENABLE_MODULES = YES; 588 | CLANG_ENABLE_OBJC_ARC = YES; 589 | CLANG_ENABLE_OBJC_WEAK = YES; 590 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 591 | CLANG_WARN_BOOL_CONVERSION = YES; 592 | CLANG_WARN_COMMA = YES; 593 | CLANG_WARN_CONSTANT_CONVERSION = YES; 594 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 595 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 596 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 597 | CLANG_WARN_EMPTY_BODY = YES; 598 | CLANG_WARN_ENUM_CONVERSION = YES; 599 | CLANG_WARN_INFINITE_RECURSION = YES; 600 | CLANG_WARN_INT_CONVERSION = YES; 601 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 602 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 603 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 604 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 605 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 606 | CLANG_WARN_STRICT_PROTOTYPES = YES; 607 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 608 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 609 | CLANG_WARN_UNREACHABLE_CODE = YES; 610 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 611 | COPY_PHASE_STRIP = NO; 612 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 613 | ENABLE_NS_ASSERTIONS = NO; 614 | ENABLE_STRICT_OBJC_MSGSEND = YES; 615 | GCC_C_LANGUAGE_STANDARD = gnu11; 616 | GCC_NO_COMMON_BLOCKS = YES; 617 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 618 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 619 | GCC_WARN_UNDECLARED_SELECTOR = YES; 620 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 621 | GCC_WARN_UNUSED_FUNCTION = YES; 622 | GCC_WARN_UNUSED_VARIABLE = YES; 623 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 624 | MTL_ENABLE_DEBUG_INFO = NO; 625 | MTL_FAST_MATH = YES; 626 | SDKROOT = iphoneos; 627 | SWIFT_COMPILATION_MODE = wholemodule; 628 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 629 | VALIDATE_PRODUCT = YES; 630 | }; 631 | name = Release; 632 | }; 633 | 9254559124265D66007F5FD4 /* Debug */ = { 634 | isa = XCBuildConfiguration; 635 | baseConfigurationReference = 79180CF1F92ACB640AF74021 /* Pods-BarcodeScanner.debug.xcconfig */; 636 | buildSettings = { 637 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 638 | CODE_SIGN_STYLE = Automatic; 639 | DEVELOPMENT_TEAM = H72YUS24CN; 640 | INFOPLIST_FILE = "BarcodeScanner/Supporting Files/Info.plist"; 641 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 642 | LD_RUNPATH_SEARCH_PATHS = ( 643 | "$(inherited)", 644 | "@executable_path/Frameworks", 645 | ); 646 | MARKETING_VERSION = 2.0; 647 | PRODUCT_BUNDLE_IDENTIFIER = com.ean.barcode.scanner; 648 | PRODUCT_NAME = "$(TARGET_NAME)"; 649 | SWIFT_VERSION = 5.0; 650 | TARGETED_DEVICE_FAMILY = 1; 651 | }; 652 | name = Debug; 653 | }; 654 | 9254559224265D66007F5FD4 /* Release */ = { 655 | isa = XCBuildConfiguration; 656 | baseConfigurationReference = EF879855EA857755783B90DA /* Pods-BarcodeScanner.release.xcconfig */; 657 | buildSettings = { 658 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 659 | CODE_SIGN_STYLE = Automatic; 660 | DEVELOPMENT_TEAM = H72YUS24CN; 661 | INFOPLIST_FILE = "BarcodeScanner/Supporting Files/Info.plist"; 662 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 663 | LD_RUNPATH_SEARCH_PATHS = ( 664 | "$(inherited)", 665 | "@executable_path/Frameworks", 666 | ); 667 | MARKETING_VERSION = 2.0; 668 | PRODUCT_BUNDLE_IDENTIFIER = com.ean.barcode.scanner; 669 | PRODUCT_NAME = "$(TARGET_NAME)"; 670 | SWIFT_VERSION = 5.0; 671 | TARGETED_DEVICE_FAMILY = 1; 672 | }; 673 | name = Release; 674 | }; 675 | /* End XCBuildConfiguration section */ 676 | 677 | /* Begin XCConfigurationList section */ 678 | 9254557724265D65007F5FD4 /* Build configuration list for PBXProject "BarcodeScanner" */ = { 679 | isa = XCConfigurationList; 680 | buildConfigurations = ( 681 | 9254558E24265D66007F5FD4 /* Debug */, 682 | 9254558F24265D66007F5FD4 /* Release */, 683 | ); 684 | defaultConfigurationIsVisible = 0; 685 | defaultConfigurationName = Release; 686 | }; 687 | 9254559024265D66007F5FD4 /* Build configuration list for PBXNativeTarget "BarcodeScanner" */ = { 688 | isa = XCConfigurationList; 689 | buildConfigurations = ( 690 | 9254559124265D66007F5FD4 /* Debug */, 691 | 9254559224265D66007F5FD4 /* Release */, 692 | ); 693 | defaultConfigurationIsVisible = 0; 694 | defaultConfigurationName = Release; 695 | }; 696 | /* End XCConfigurationList section */ 697 | }; 698 | rootObject = 9254557424265D65007F5FD4 /* Project object */; 699 | } 700 | --------------------------------------------------------------------------------