├── .swift-version
├── Example
├── Source
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── Menu Background.imageset
│ │ │ ├── Menu Background.jpg
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── ViewController.swift
│ ├── Info.plist
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
├── Screenshots
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ └── 04.png
├── Podfile
├── Example.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
├── Example.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Podfile.lock
├── Package.swift
├── swiftgen.yml
├── Resources
├── Base.lproj
│ └── Localizable.strings
├── en.lproj
│ └── Localizable.strings
├── fr.lproj
│ └── Localizable.strings
├── nl.lproj
│ └── Localizable.strings
└── PhoneVerificationController.xib
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── PhoneVerificationController.podspec
├── CHANGELOG.md
├── Source
├── Strings.swift
├── Phone Entry.swift
├── Code Entry.swift
├── Configuration.swift
└── PhoneVerificationController.swift
├── templates
└── strings.stencil
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.0
2 |
--------------------------------------------------------------------------------
/Example/Source/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Screenshots/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisemen-digital/PhoneVerificationController/HEAD/Example/Screenshots/01.png
--------------------------------------------------------------------------------
/Example/Screenshots/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisemen-digital/PhoneVerificationController/HEAD/Example/Screenshots/02.png
--------------------------------------------------------------------------------
/Example/Screenshots/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisemen-digital/PhoneVerificationController/HEAD/Example/Screenshots/03.png
--------------------------------------------------------------------------------
/Example/Screenshots/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisemen-digital/PhoneVerificationController/HEAD/Example/Screenshots/04.png
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(
4 | name: "PhoneVerificationController",
5 | dependencies: [
6 | ]
7 | )
8 |
--------------------------------------------------------------------------------
/swiftgen.yml:
--------------------------------------------------------------------------------
1 | input_dir: Resources
2 | output_dir: Source
3 | strings:
4 | inputs: Base.lproj/Localizable.strings
5 | outputs:
6 | templatePath: templates/strings.stencil
7 | output: Strings.swift
8 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '9.0'
2 |
3 | inhibit_all_warnings!
4 | source 'https://cdn.cocoapods.org/'
5 |
6 | target 'Example' do
7 | pod 'PhoneVerificationController', :path => '../'
8 | pod 'SwiftGen'
9 | end
10 |
--------------------------------------------------------------------------------
/Example/Source/Assets.xcassets/Menu Background.imageset/Menu Background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisemen-digital/PhoneVerificationController/HEAD/Example/Source/Assets.xcassets/Menu Background.imageset/Menu Background.jpg
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Example.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Resources/Base.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "button.cancel" = "Cancel";
2 | "button.send" = "Send";
3 | "button.try-again" = "Try again";
4 | "button.verify" = "Verify";
5 |
6 | "description.phone" = "Please enter your phone number (ex. +32 473123456)";
7 | "description.code" = "Please enter the verification code you will receive by SMS";
8 |
9 | "message.success" = "Success!";
10 |
11 | "placeholder.phone" = "Phone Number";
12 |
--------------------------------------------------------------------------------
/Resources/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "button.cancel" = "Cancel";
2 | "button.send" = "Send";
3 | "button.try-again" = "Try again";
4 | "button.verify" = "Verify";
5 |
6 | "description.phone" = "Please enter your phone number (ex. +32 473123456)";
7 | "description.code" = "Please enter the verification code you will receive by SMS";
8 |
9 | "message.success" = "Success!";
10 |
11 | "placeholder.phone" = "Phone Number";
12 |
--------------------------------------------------------------------------------
/Resources/fr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "button.cancel" = "Annuler";
2 | "button.send" = "Envoyer";
3 | "button.try-again" = "Réessayer";
4 | "button.verify" = "Vérifier";
5 |
6 | "description.phone" = "Entrez votre numéro de téléphone (par ex. +32 473123456)";
7 | "description.code" = "Entrez le code de vérification que vous recevrez par SMS";
8 |
9 | "message.success" = "Succes!";
10 |
11 | "placeholder.phone" = "Téléphone";
12 |
--------------------------------------------------------------------------------
/Resources/nl.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "button.cancel" = "Annuleren";
2 | "button.send" = "Versturen";
3 | "button.try-again" = "Opnieuw proberen";
4 | "button.verify" = "Verifiëren";
5 |
6 | "description.phone" = "Gelieve uw GSM nummer in te geven (vb. +32 473123456)";
7 | "description.code" = "Gelieve de verificatiecode in te geven die u via SMS ontvangen heeft";
8 |
9 | "message.success" = "Succes!";
10 |
11 | "placeholder.phone" = "gsm-nummer";
12 |
--------------------------------------------------------------------------------
/Example/Source/Assets.xcassets/Menu Background.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Menu Background.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/Source/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Example
4 | //
5 | // Created by David Jennes on 17/09/16.
6 | // Copyright © 2016 Appwise. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | final class AppDelegate: UIResponder, UIApplicationDelegate {
13 | var window: UIWindow?
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
16 | return true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build generated
2 | build/
3 | DerivedData/
4 |
5 | ## Various settings
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 |
16 | ## Other
17 | *.moved-aside
18 | *.xcuserstate
19 | *.xccheckout
20 | *.xcscmblueprint
21 |
22 | ## Obj-C/Swift specific
23 | *.hmap
24 | *.ipa
25 | *.dSYM.zip
26 | *.dSYM
27 |
28 | ## Playgrounds
29 | timeline.xctimeline
30 | playground.xcworkspace
31 |
32 | # CocoaPods
33 | Pods/
34 |
35 | # fastlane
36 | .env
37 | fastlane/README.md
38 | fastlane/report.xml
39 | fastlane/Preview.html
40 | fastlane/screenshots
41 | fastlane/test_output
42 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | All contributors are welcome. Please use issues and pull requests to contribute to the project. And update [CHANGELOG.md](CHANGELOG.md) when committing.
4 |
5 | ## Making a Change
6 |
7 | When you commit a change, please add a note to [CHANGELOG.md](CHANGELOG.md).
8 |
9 | ## Release Process
10 |
11 | 1. Confirm the build is [passing in travis](https://travis-ci.org/appwise-labs/PhoneVerificationController)
12 | 1. This automatically checks the Podfile is building
13 | 2. Push a release commit
14 | 1. Create a new Master section at the top
15 | 2. Rename the old Master section like:
16 | ## [1.0.5](https://github.com/appwise-labs/PhoneVerificationController/releases/tag/1.0.5)
17 | Released on 2016-02-14.
18 | 3. Update the Podspec version number
19 | 3. Create a GitHub release
20 | 1. Tag the release (like `1.0.5`)
21 | 2. Paste notes from [CHANGELOG.md](CHANGELOG.md)
22 | 3. Push the Podspec to CocoaPods
23 | 1. `pod trunk push`
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Appwise
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - CountryPickerSwift (1.8.2)
3 | - PhoneNumberKit (2.6.0):
4 | - PhoneNumberKit/PhoneNumberKitCore (= 2.6.0)
5 | - PhoneNumberKit/UIKit (= 2.6.0)
6 | - PhoneNumberKit/PhoneNumberKitCore (2.6.0)
7 | - PhoneNumberKit/UIKit (2.6.0):
8 | - PhoneNumberKit/PhoneNumberKitCore
9 | - PhoneVerificationController (2.0.2):
10 | - CountryPickerSwift (~> 1.8)
11 | - PhoneNumberKit (~> 2.6)
12 | - SwiftGen (6.1.0)
13 |
14 | DEPENDENCIES:
15 | - PhoneVerificationController (from `../`)
16 | - SwiftGen
17 |
18 | SPEC REPOS:
19 | https://cdn.cocoapods.org/:
20 | - CountryPickerSwift
21 | - PhoneNumberKit
22 | - SwiftGen
23 |
24 | EXTERNAL SOURCES:
25 | PhoneVerificationController:
26 | :path: "../"
27 |
28 | SPEC CHECKSUMS:
29 | CountryPickerSwift: b2cd8b391a0222bd9a97d09ea30426303adac810
30 | PhoneNumberKit: 167ee1f0bbb6efce7c62559e620eae745595532f
31 | PhoneVerificationController: 11a2f3e269bdcfef4a052eb1f44ec2f7a3b2c9ec
32 | SwiftGen: f872ca75cbd17bf7103c17f13dcfa0d9a15667b0
33 |
34 | PODFILE CHECKSUM: 4e2b6c4e976d8a0324162268626f427ec1d7ea99
35 |
36 | COCOAPODS: 1.7.3
37 |
--------------------------------------------------------------------------------
/PhoneVerificationController.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | # info
3 | s.name = 'PhoneVerificationController'
4 | s.version = '2.0.2'
5 | s.summary = 'A nicer UI for FireBase phone authentication.'
6 | s.description = <<-DESC
7 | This is a replacement for FireBaseUI for phone authentication. The UI is completely customizable using a configuration structure.
8 | DESC
9 | s.homepage = 'https://github.com/appwise-labs/PhoneVerificationController'
10 | s.authors = {
11 | 'David Jennes' => 'david.jennes@gmail.com',
12 | 'Tom Knapen' => 'tom@knapen.io',
13 | 'Yannick Winters' => 'wintersyannick@gmail.com'
14 | }
15 | s.license = {
16 | :type => 'MIT',
17 | :file => 'LICENSE'
18 | }
19 |
20 | # configuration
21 | s.ios.deployment_target = '9.0'
22 | s.swift_version = '5.0'
23 |
24 | # files
25 | s.source = {
26 | :git => 'https://github.com/appwise-labs/PhoneVerificationController.git',
27 | :tag => s.version
28 | }
29 | s.source_files = 'Source/*.swift'
30 | s.resource_bundles = {
31 | 'PhoneVerificationControllerResources' => ['Resources/**/*']
32 | }
33 |
34 | # dependencies
35 | s.dependency 'CountryPickerSwift', '~> 1.8'
36 | s.dependency 'PhoneNumberKit', '~> 2.6'
37 | end
38 |
--------------------------------------------------------------------------------
/Example/Source/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Example
4 | //
5 | // Created by David Jennes on 17/09/16.
6 | // Copyright © 2016 Appwise. All rights reserved.
7 | //
8 |
9 | import PhoneVerificationController
10 | import UIKit
11 |
12 | class ViewController: UIViewController {
13 | @IBAction func startVerification() {
14 | let configuration = Configuration(headerBackground: #imageLiteral(resourceName: "Menu Background"), requestCode: { _, completion in
15 | DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
16 | completion("1234567890", nil)
17 | }
18 | }, signIn: { _, _, completion in
19 | DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
20 | completion(nil)
21 | }
22 | })
23 |
24 | let vc = PhoneVerificationController(configuration: configuration)
25 | present(vc, animated: true)
26 | }
27 | }
28 |
29 | extension ViewController: PhoneVerificationDelegate {
30 | func cancelled(controller: PhoneVerificationController) {
31 | print("Cancelled verification")
32 | controller.dismiss(animated: true)
33 | }
34 |
35 | func verified(phoneNumber: String, controller: PhoneVerificationController) {
36 | print("Verified phone \(phoneNumber)")
37 | controller.dismiss(animated: true)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Example/Source/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | `PhoneVerificationController` adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [Master](https://github.com/djbe/PhoneVerificationController)
6 |
7 | ### New Features
8 |
9 | _None_
10 |
11 | ### Bug Fixes
12 |
13 | _None_
14 |
15 | ## [2.0.2](https://github.com/djbe/PhoneVerificationController/releases/tag/2.0.2)
16 |
17 | ### Bug Fixes
18 |
19 | - Fix an issue with the code field entry (sorting).
20 | - Some translation fixes (dutch language).
21 | - Minor layout tweaks.
22 |
23 | ## [2.0.1](https://github.com/djbe/PhoneVerificationController/releases/tag/2.0.1)
24 |
25 | ### Bug Fixes
26 |
27 | - Fix localizations not loading due to some weird UIKit bug.
28 |
29 | ## [2.0.0](https://github.com/djbe/PhoneVerificationController/releases/tag/2.0.0)
30 |
31 | ### New Features
32 |
33 | - Swift 4 compatibility.
34 | - Migration to [Appwise](https://github.com/appwise-labs) organisation.
35 |
36 | ## [1.2.1](https://github.com/djbe/PhoneVerificationController/releases/tag/1.2.1)
37 |
38 | ### Bug Fixes
39 |
40 | - Dismiss the keyboard before disappear.
41 | - Some fixes to UI color customization (button tints).
42 |
43 | ## [1.2.0](https://github.com/djbe/PhoneVerificationController/releases/tag/1.2.0)
44 |
45 | ### New Features
46 |
47 | - Add a header foreground image view (with aspect-fit content scale).
48 | - Document all configuration options.
49 |
50 | ### Bug Fixes
51 |
52 | ## [1.1.0](https://github.com/djbe/PhoneVerificationController/releases/tag/1.1.0)
53 |
54 | ### New Features
55 |
56 | - French & dutch translations.
57 |
58 | ### Bug Fixes
59 |
60 | - Fix delegate visibility.
61 |
62 | ## [1.0.0](https://github.com/djbe/PhoneVerificationController/releases/tag/1.0.0)
63 |
64 | Initial release.
65 |
--------------------------------------------------------------------------------
/Example/Source/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 |
27 |
28 |
--------------------------------------------------------------------------------
/Example/Source/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Source/Strings.swift:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | import Foundation
5 |
6 | // swiftlint:disable superfluous_disable_command
7 | // swiftlint:disable file_length
8 |
9 | // MARK: - Strings
10 |
11 | // swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
12 | // swiftlint:disable nesting type_body_length type_name
13 | internal enum L10n {
14 |
15 | internal enum Button {
16 | /// Cancel
17 | internal static let cancel = L10n.tr("Localizable", "button.cancel")
18 | /// Send
19 | internal static let send = L10n.tr("Localizable", "button.send")
20 | /// Try again
21 | internal static let tryAgain = L10n.tr("Localizable", "button.try-again")
22 | /// Verify
23 | internal static let verify = L10n.tr("Localizable", "button.verify")
24 | }
25 |
26 | internal enum Description {
27 | /// Please enter the verification code you will receive by SMS
28 | internal static let code = L10n.tr("Localizable", "description.code")
29 | /// Please enter your phone number (ex. +32 473123456)
30 | internal static let phone = L10n.tr("Localizable", "description.phone")
31 | }
32 |
33 | internal enum Message {
34 | /// Success!
35 | internal static let success = L10n.tr("Localizable", "message.success")
36 | }
37 |
38 | internal enum Placeholder {
39 | /// Phone Number
40 | internal static let phone = L10n.tr("Localizable", "placeholder.phone")
41 | }
42 | }
43 | // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
44 | // swiftlint:enable nesting type_body_length type_name
45 |
46 | // MARK: - Implementation Details
47 |
48 | extension L10n {
49 | private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
50 | // swiftlint:disable:next nslocalizedstring_key
51 | let format = NSLocalizedString(key, tableName: table, bundle: PhoneVerificationController.bundle, comment: "")
52 | return String(format: format, locale: Locale.current, arguments: args)
53 | }
54 | }
55 |
56 | private final class BundleToken {}
57 |
--------------------------------------------------------------------------------
/Source/Phone Entry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Phone Entry.swift
3 | // PhoneVerificationController
4 | //
5 | // Created by David Jennes on 30/08/2017.
6 | // Copyright © 2017 Appwise. All rights reserved.
7 | //
8 |
9 | import CountryPicker
10 | import PhoneNumberKit
11 | import UIKit
12 |
13 | extension PhoneVerificationController: CountryPickerDelegate {
14 | internal var phoneNumber: String {
15 | return "\(self.phoneCountryField.text ?? "")\(self.phoneNumberField.text ?? "")"
16 | }
17 |
18 | @IBAction func phoneFieldChanged(_ sender: UITextField) {
19 | let valid = (try? PhoneNumberKit().parse(phoneNumber)) != nil
20 |
21 | UIView.animate(withDuration: configuration.animationDuration) { [unowned self] in
22 | self.phoneSendButton.isEnabled = valid
23 | self.phoneSendButton.backgroundColor = valid ? self.configuration.buttonBackgroundEnabled : self.configuration.buttonBackgroundDisabled
24 | }
25 | }
26 |
27 | public func countryPhoneCodePicker(_ picker: CountryPicker, didSelectCountryWithName name: String, countryCode: String, phoneCode: String, flag: UIImage) {
28 | phoneCountryField.text = phoneCode
29 | phoneCountryImageView.image = flag
30 |
31 | phoneFieldChanged(phoneCountryField)
32 | }
33 |
34 | @IBAction func verifyPhoneNumber(_ sender: Any) {
35 | phoneActivityIndicator.startAnimating()
36 | configuration.requestCode(phoneNumber) { [weak self] verificationID, error in
37 | guard let strongSelf = self else { return }
38 |
39 | strongSelf.phoneActivityIndicator.stopAnimating()
40 | if let error = error {
41 | strongSelf.show(error: error, in: strongSelf.phoneDescriptionLabel, original: L10n.Description.phone)
42 | } else if let verificationID = verificationID {
43 | strongSelf.configuration.verificationID = verificationID
44 | strongSelf.switchToCodeVerification()
45 | }
46 | }
47 | }
48 |
49 | @IBAction func cancel() {
50 | if let delegate = delegate {
51 | delegate.cancelled(controller: self)
52 | } else {
53 | self.dismiss(animated: true, completion: nil)
54 | }
55 | }
56 |
57 | private func switchToCodeVerification() {
58 | UIView.animate(withDuration: configuration.animationDuration) { [unowned self] in
59 | self.phoneContainerView.isHidden = true
60 | self.phoneContainerView.alpha = 0
61 | self.codeContainerView.isHidden = false
62 | self.codeContainerView.alpha = 1
63 |
64 | for field in self.codeTextFields {
65 | field.text = ""
66 | field.backgroundColor = .clear
67 | }
68 | }
69 | self.codeTextFields.first?.becomeFirstResponder()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Example/Source/Base.lproj/Main.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 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/templates/strings.stencil:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | {% if tables.count > 0 %}
5 | {% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
6 | import Foundation
7 |
8 | // swiftlint:disable superfluous_disable_command
9 | // swiftlint:disable file_length
10 |
11 | // MARK: - Strings
12 |
13 | {% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
14 | {% for type in types %}
15 | _ p{{forloop.counter}}: {{type}}{{ ", " if not forloop.last }}
16 | {% endfor %}
17 | {% endfilter %}{% endmacro %}
18 | {% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
19 | {% for type in types %}
20 | {% if type == "UnsafeRawPointer" %}
21 | Int(bitPattern: p{{forloop.counter}})
22 | {% else %}
23 | p{{forloop.counter}}
24 | {% endif %}
25 | {{ ", " if not forloop.last }}
26 | {% endfor %}
27 | {% endfilter %}{% endmacro %}
28 | {% macro recursiveBlock table item %}
29 | {% for string in item.strings %}
30 | {% if not param.noComments %}
31 | /// {{string.translation}}
32 | {% endif %}
33 | {% if string.types %}
34 | {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String {
35 | return {{enumName}}.tr("{{table}}", "{{string.key}}", {% call argumentsBlock string.types %})
36 | }
37 | {% else %}
38 | {{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}")
39 | {% endif %}
40 | {% endfor %}
41 | {% for child in item.children %}
42 |
43 | {{accessModifier}} enum {{child.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
44 | {% filter indent:2 %}{% call recursiveBlock table child %}{% endfilter %}
45 | }
46 | {% endfor %}
47 | {% endmacro %}
48 | // swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
49 | // swiftlint:disable nesting type_body_length type_name
50 | {% set enumName %}{{param.enumName|default:"L10n"}}{% endset %}
51 | {{accessModifier}} enum {{enumName}} {
52 | {% if tables.count > 1 %}
53 | {% for table in tables %}
54 | {{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
55 | {% filter indent:2 %}{% call recursiveBlock table.name table.levels %}{% endfilter %}
56 | }
57 | {% endfor %}
58 | {% else %}
59 | {% call recursiveBlock tables.first.name tables.first.levels %}
60 | {% endif %}
61 | }
62 | // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
63 | // swiftlint:enable nesting type_body_length type_name
64 |
65 | // MARK: - Implementation Details
66 |
67 | extension {{enumName}} {
68 | private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
69 | // swiftlint:disable:next nslocalizedstring_key
70 | let format = NSLocalizedString(key, tableName: table, bundle: PhoneVerificationController.bundle, comment: "")
71 | return String(format: format, locale: Locale.current, arguments: args)
72 | }
73 | }
74 |
75 | private final class BundleToken {}
76 | {% else %}
77 | // No string found
78 | {% endif %}
79 |
--------------------------------------------------------------------------------
/Source/Code Entry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Code Entry.swift
3 | // PhoneVerificationController
4 | //
5 | // Created by David Jennes on 30/08/2017.
6 | // Copyright © 2017 Appwise. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension PhoneVerificationController: UITextFieldDelegate {
12 | @IBAction func enteredCodeCharacter(_ sender: UITextField) {
13 | // update field UI
14 | let filled = !(sender.text?.isEmpty ?? true)
15 | UIView.animate(withDuration: configuration.animationDuration) {
16 | sender.backgroundColor = filled ? self.configuration.codeFieldBackgroundFilled : self.configuration.codeFieldBackgroundEmpty
17 | }
18 |
19 | // update the verify button
20 | let allFilled = !codeTextFields.contains { ($0.text?.isEmpty ?? true) }
21 | UIView.animate(withDuration: configuration.animationDuration) { [unowned self] in
22 | self.codeSendButton.isEnabled = allFilled
23 | self.codeSendButton.backgroundColor = allFilled ? self.configuration.buttonBackgroundEnabled : self.configuration.buttonBackgroundDisabled
24 | }
25 |
26 | // transfer responder to next field
27 | sender.resignFirstResponder()
28 | codeTextFields.first { $0.text?.isEmpty ?? true }?.becomeFirstResponder()
29 | }
30 |
31 | @IBAction func focusOnLastField() {
32 | if let last = codeTextFields.first(where: { $0.text?.isEmpty ?? true }) {
33 | last.becomeFirstResponder()
34 | } else {
35 | codeTextFields.last?.becomeFirstResponder()
36 | }
37 | }
38 |
39 | func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
40 | guard let index = codeTextFields.index(of: textField), index > 0 else { return true }
41 | codeTextFields[index - 1].becomeFirstResponder()
42 | return true
43 | }
44 |
45 | public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
46 | guard let text = textField.text as NSString? else { return true }
47 | return text.replacingCharacters(in: range, with: string).count <= 1
48 | }
49 |
50 | @IBAction func tryAgain() {
51 | UIView.animate(withDuration: configuration.animationDuration) { [unowned self] in
52 | self.phoneContainerView.isHidden = false
53 | self.phoneContainerView.alpha = 1
54 | self.codeContainerView.isHidden = true
55 | self.codeContainerView.alpha = 0
56 | self.codeSendButton.isEnabled = false
57 | self.codeSendButton.backgroundColor = self.configuration.buttonBackgroundDisabled
58 | self.codeActivityIndicator.stopAnimating()
59 | }
60 | }
61 |
62 | @IBAction func verifyCode(_ sender: Any) {
63 | let code = codeTextFields.reduce("") { $0 + ($1.text ?? "") }
64 |
65 | codeActivityIndicator.startAnimating()
66 | configuration.signIn(configuration.verificationID ?? "", code) { [weak self] error in
67 | guard let strongSelf = self else { return }
68 |
69 | strongSelf.codeActivityIndicator.stopAnimating()
70 | if let error = error {
71 | strongSelf.show(error: error, in: strongSelf.codeDescriptionLabel, original: L10n.Description.code)
72 | } else {
73 | strongSelf.codeDescriptionLabel.text = L10n.Message.success
74 | if let delegate = strongSelf.delegate {
75 | delegate.verified(phoneNumber: strongSelf.phoneNumber, controller: strongSelf)
76 | } else {
77 | strongSelf.dismiss(animated: true, completion: nil)
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PhoneVerificationController
2 |
3 | [](https://cocoapods.org/pods/PhoneVerificationController)
4 | [](https://cocoapods.org/pods/PhoneVerificationController)
5 | [](https://cocoapods.org/pods/PhoneVerificationController)
6 | [](https://cocoapods.org/pods/CountryPickerSwift)
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Example
14 |
15 | To run the example project, clone the repo, and run `pod install` from the Example directory first.
16 |
17 |
18 | ## Requirements
19 |
20 |
21 | ## Installation
22 |
23 | ### CocoaPods
24 |
25 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
26 |
27 | ```bash
28 | $ gem install cocoapods
29 | ```
30 |
31 | To integrate PhoneVerificationController into your Xcode project using CocoaPods, specify it in your `Podfile`:
32 |
33 | ```ruby
34 | use_frameworks!
35 |
36 | pod 'FireBase/Auth'
37 | pod 'PhoneVerificationController'
38 | ```
39 |
40 | Note that you'll need to add `FireBase/Auth` as well (we can't depend on it as it's a static framework). Then, run the following command:
41 |
42 | ```bash
43 | $ pod install
44 | ```
45 |
46 | ## Usage
47 |
48 | Follow the first 2 steps for Firebase authentication on iOS as documenteded [here](https://firebase.google.com/docs/auth/ios/phone-auth). PhoneVerificationController will handle the rest, as long as you invoke it using:
49 |
50 | ```swift
51 | import FirebaseAuth
52 | import PhoneVerificationController
53 |
54 | let configuration = Configuration(requestCode: { phone, completion in
55 | PhoneAuthProvider.provider().verifyPhoneNumber(phone, completion: completion)
56 | }, signIn: { verificationID, verificationCode, completion in
57 | let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID, verificationCode: verificationCode)
58 | Auth.auth().signIn(with: credential) { _, error in completion(error) }
59 | })
60 | let vc = PhoneVerificationController(configuration: configuration)
61 | vc.delegate = self
62 | present(vc, animated: true)
63 | ```
64 |
65 | You'll receive a callback if the verification succeeds, or is cancelled.
66 |
67 | ## Authors
68 |
69 | - [David Jennes](https://github.com/djbe)
70 | - [Tom Knapen](https://github.com/wassup-)
71 | - [Yannick Winters](https://github.com/YWinters)
72 |
73 | ## License
74 |
75 | PhoneVerificationController is available under the MIT license. See the LICENSE file for more info.
76 |
--------------------------------------------------------------------------------
/Source/Configuration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Configuration.swift
3 | // PhoneVerificationController
4 | //
5 | // Created by David Jennes on 30/08/2017.
6 | // Copyright © 2017 Appwise. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public struct Configuration {
12 | /**
13 | Block that receives a phone number and is expected to call a completion block with a verification ID.
14 |
15 | - Parameter phoneNumber: the phone number to verify
16 | - Parameter completion: the completion block (must be called!)
17 | */
18 | public typealias RequestCodeBlock = (_ phoneNumber: String, _ completion: @escaping (_ verificationID: String?, _ error: Error?) -> Void) -> Void
19 |
20 | /**
21 | Block that receives a verification ID and code, and is expected to call a completion block with success (or an error).
22 |
23 | - Parameter verificationID: the verification session ID
24 | - Parameter verificationCode: the matching verification code
25 | - Parameter completion: the completion block (must be called!)
26 | */
27 | public typealias SignInBlock = (_ verificationID: String, _ verificationCode: String, _ completion: @escaping (_ error: Error?) -> Void) -> Void
28 |
29 | let statusBar: UIStatusBarStyle
30 | let keyboard: UIKeyboardAppearance
31 | let headerBackground: UIImage?
32 | let headerForeground: UIImage?
33 | let background: UIColor
34 | let text: UIColor
35 | let buttonTint: UIColor
36 | let buttonTextEnabled: UIColor
37 | let buttonTextDisabled: UIColor
38 | let buttonBackgroundEnabled: UIColor
39 | let buttonBackgroundDisabled: UIColor
40 | let codeFieldBackgroundEmpty: UIColor
41 | let codeFieldBackgroundFilled: UIColor
42 | let codeFieldText: UIColor
43 | let animationDuration: TimeInterval
44 | let errorDuration: TimeInterval
45 | let requestCode: RequestCodeBlock
46 | let signIn: SignInBlock
47 |
48 | /**
49 | If you already have a verification ID from FireBase, you can set it here to resume code verification.
50 |
51 | NOTE: not implemented yet.
52 | */
53 | public var verificationID: String?
54 |
55 | /**
56 | Create a configuration object used by the phone verification controller.
57 |
58 | - Parameter statusBar: The preferred status bar style for the controller. Default: lightContent
59 | - Parameter keyboard: The keyboard's appearance when focused on fields. Default: dark
60 | - Parameter headerBackground: The header's background image (aspect-fill). Default: nil
61 | - Parameter headerForeground: The header's foreground image (aspect-fit). Default: nil
62 | - Parameter background: The general background color. Default: black
63 | - Parameter text: The general foreground (text) color. Default: white
64 | - Parameter buttonTint: The tint color applied to all buttons and fields. Default: white
65 | - Parameter buttonTextEnabled: The text color for enabled buttons. Default: white
66 | - Parameter buttonTextDisabled: The text color for disabled buttons. Default: white
67 | - Parameter buttonBackgroundEnabled: The background color for enabled buttons. Default: red
68 | - Parameter buttonBackgroundDisabled: The background color for disabled buttons. Default: lightGray
69 | - Parameter codeFieldBackgroundEmpty: The background color for empty code fields. Default: clear
70 | - Parameter codeFieldBackgroundFilled: The background color for filled code fields (and their border). Default: white
71 | - Parameter codeFieldText: The text color for code fields. Default: black
72 | - Parameter animationDuration: The duration for all animations. Default: 0.3s
73 | - Parameter errorDuration: The duration for showing error messages. Default: 5s
74 | - Parameter requestCode: Block called for requesting the verification code from FireBase Auth API
75 | - Parameter signIn: Block called for verifying a code with the FireBase Auth API
76 | */
77 | public init(statusBar: UIStatusBarStyle = .lightContent,
78 | keyboard: UIKeyboardAppearance = .dark,
79 | headerBackground: UIImage? = nil,
80 | headerForeground: UIImage? = nil,
81 | background: UIColor = .black,
82 | text: UIColor = .white,
83 | buttonTint: UIColor = .white,
84 | buttonTextDisabled: UIColor = .lightGray,
85 | buttonTextEnabled: UIColor = .white,
86 | buttonBackgroundDisabled: UIColor = UIColor.lightGray.withAlphaComponent(0.6),
87 | buttonBackgroundEnabled: UIColor = .red,
88 | codeFieldBackgroundEmpty: UIColor = .clear,
89 | codeFieldBackgroundFilled: UIColor = .white,
90 | codeFieldText: UIColor = .black,
91 | animationDuration: TimeInterval = 0.3,
92 | errorDuration: TimeInterval = 5,
93 | requestCode: @escaping RequestCodeBlock,
94 | signIn: @escaping SignInBlock) {
95 | self.statusBar = statusBar
96 | self.keyboard = keyboard
97 | self.headerBackground = headerBackground
98 | self.headerForeground = headerForeground
99 | self.background = background
100 | self.text = text
101 | self.buttonTint = buttonTint
102 | self.buttonTextDisabled = buttonTextDisabled
103 | self.buttonTextEnabled = buttonTextEnabled
104 | self.buttonBackgroundDisabled = buttonBackgroundDisabled
105 | self.buttonBackgroundEnabled = buttonBackgroundEnabled
106 | self.codeFieldBackgroundEmpty = codeFieldBackgroundEmpty
107 | self.codeFieldBackgroundFilled = codeFieldBackgroundFilled
108 | self.codeFieldText = codeFieldText
109 | self.animationDuration = animationDuration
110 | self.errorDuration = errorDuration
111 | self.requestCode = requestCode
112 | self.signIn = signIn
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/Source/PhoneVerificationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhoneVerificationController.swift
3 | // PhoneVerificationController
4 | //
5 | // Created by David Jennes on 30/08/2017.
6 | // Copyright © 2017 Appwise. All rights reserved.
7 | //
8 |
9 | import CountryPicker
10 | import UIKit
11 |
12 | public protocol PhoneVerificationDelegate: class {
13 | func cancelled(controller: PhoneVerificationController)
14 | func verified(phoneNumber: String, controller: PhoneVerificationController)
15 | }
16 |
17 | open class PhoneVerificationController: UIViewController {
18 | @IBOutlet var headerBackgroundImageView: UIImageView!
19 | @IBOutlet var headerForegroundImageView: UIImageView!
20 | @IBOutlet var phoneContainerView: UIView!
21 | @IBOutlet var phoneActivityIndicator: UIActivityIndicatorView!
22 | @IBOutlet var phoneCountryImageView: UIImageView!
23 | @IBOutlet var phoneCountryField: UITextField!
24 | @IBOutlet var phoneNumberField: UITextField!
25 | @IBOutlet var phoneSendButton: UIButton!
26 | @IBOutlet var phoneCancelButton: UIButton!
27 | @IBOutlet var phoneDescriptionLabel: UILabel!
28 | @IBOutlet var codeContainerView: UIView!
29 | @IBOutlet var codeTextFields: [UITextField]!
30 | @IBOutlet var codeActivityIndicator: UIActivityIndicatorView!
31 | @IBOutlet var codeSendButton: UIButton!
32 | @IBOutlet var codeTryAgainButton: UIButton!
33 | @IBOutlet var codeDescriptionLabel: UILabel!
34 |
35 | static let bundle: Bundle = {
36 | guard let path = Bundle(for: PhoneVerificationController.self).path(forResource: "PhoneVerificationControllerResources", ofType: "bundle"),
37 | let bundle = Bundle(path: path) else {
38 | fatalError("Unable to find resources bundle path")
39 | }
40 | return bundle
41 | }()
42 | fileprivate lazy var countryPicker: CountryPicker = {
43 | let picker = CountryPicker()
44 |
45 | picker.countryPickerDelegate = self
46 | picker.showPhoneNumbers = true
47 | picker.setCountry(Locale.current.regionCode ?? "")
48 |
49 | return picker
50 | }()
51 | fileprivate var errorTask = [UILabel: DispatchWorkItem]()
52 | internal(set) var configuration: Configuration
53 | public weak var delegate: PhoneVerificationDelegate?
54 |
55 | public init(configuration: Configuration) {
56 | self.configuration = configuration
57 | super.init(nibName: nil, bundle: PhoneVerificationController.bundle)
58 | }
59 |
60 | public required init?(coder aDecoder: NSCoder) {
61 | configuration = Configuration(requestCode: { _, completion in completion(nil, nil) },
62 | signIn: { _, _, completion in completion(nil) })
63 | super.init(coder: aDecoder)
64 | }
65 | }
66 |
67 | // MARK: - Controller lifecycle
68 |
69 | extension PhoneVerificationController {
70 | override open func viewDidLoad() {
71 | super.viewDidLoad()
72 |
73 | // sort by x (outlet collections have no guaranteed order)
74 | if let stackView = codeTextFields.first?.superview as? UIStackView {
75 | codeTextFields.sort { left, right in
76 | let il = stackView.arrangedSubviews.index(of: left) ?? 0
77 | let ir = stackView.arrangedSubviews.index(of: right) ?? 0
78 | return il < ir
79 | }
80 | }
81 |
82 | // connect some stuff
83 | phoneCountryField.inputView = countryPicker
84 | for field in codeTextFields {
85 | field.delegate = self
86 | }
87 |
88 | // strings
89 | phoneSendButton.setTitle(L10n.Button.send, for: .normal)
90 | phoneCancelButton.setTitle(L10n.Button.cancel, for: .normal)
91 | codeSendButton.setTitle(L10n.Button.verify, for: .normal)
92 | codeTryAgainButton.setTitle(L10n.Button.tryAgain, for: .normal)
93 | phoneDescriptionLabel.text = L10n.Description.phone
94 | codeDescriptionLabel.text = L10n.Description.code
95 | phoneNumberField.placeholder = L10n.Placeholder.phone
96 |
97 | // apply configuration
98 | apply(configuration: configuration)
99 | codeContainerView.isHidden = true
100 | codeContainerView.alpha = 0
101 | }
102 |
103 | override open var preferredStatusBarStyle: UIStatusBarStyle {
104 | return configuration.statusBar
105 | }
106 |
107 | override open func viewWillAppear(_ animated: Bool) {
108 | super.viewWillAppear(animated)
109 | phoneNumberField.becomeFirstResponder()
110 | }
111 |
112 | override open func viewWillDisappear(_ animated: Bool) {
113 | super.viewWillDisappear(animated)
114 | view.endEditing(true)
115 | }
116 | }
117 |
118 | // MARK: - Helper methods
119 |
120 | extension PhoneVerificationController {
121 | fileprivate func apply(configuration: Configuration) {
122 | for view in [view, phoneContainerView, codeContainerView] {
123 | view?.backgroundColor = configuration.background
124 | }
125 | headerBackgroundImageView.image = configuration.headerBackground
126 | headerForegroundImageView.image = configuration.headerForeground
127 | for label in [phoneDescriptionLabel, codeDescriptionLabel] {
128 | label?.textColor = configuration.text
129 | }
130 | for button in [phoneCancelButton, codeTryAgainButton] {
131 | button?.tintColor = configuration.buttonTint
132 | }
133 | for button in [phoneSendButton, codeSendButton] {
134 | button?.setTitleColor(configuration.buttonTextEnabled, for: .normal)
135 | button?.setTitleColor(configuration.buttonTextDisabled, for: .disabled)
136 | button?.backgroundColor = configuration.buttonBackgroundDisabled
137 | }
138 | for field in [phoneCountryField, phoneNumberField] + codeTextFields {
139 | field?.keyboardAppearance = configuration.keyboard
140 | field?.tintColor = configuration.buttonTint
141 | field?.textColor = configuration.text
142 | }
143 | for field in codeTextFields {
144 | field.layer.borderColor = configuration.codeFieldBackgroundFilled.cgColor
145 | field.textColor = configuration.codeFieldText
146 | }
147 | }
148 |
149 | internal func show(error: Error, in label: UILabel, original: String) {
150 | errorTask[label]?.cancel()
151 | label.text = error.localizedDescription
152 |
153 | // enqueue error
154 | let task = DispatchWorkItem {
155 | label.text = original
156 | }
157 | DispatchQueue.main.asyncAfter(deadline: .now() + configuration.errorDuration, execute: task)
158 | errorTask[label] = task
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 5A9AB0995E376E2BB23DD56C /* libPods-Example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EF0BDEE180E4FF5343803C14 /* libPods-Example.a */; };
11 | D95E1C451D88E71A00F94976 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D95E1C441D88E71A00F94976 /* AppDelegate.swift */; };
12 | D95E1C471D88E71A00F94976 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D95E1C461D88E71A00F94976 /* ViewController.swift */; };
13 | D95E1C4A1D88E71A00F94976 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D95E1C481D88E71A00F94976 /* Main.storyboard */; };
14 | D95E1C4C1D88E71A00F94976 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D95E1C4B1D88E71A00F94976 /* Assets.xcassets */; };
15 | D95E1C4F1D88E71A00F94976 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D95E1C4D1D88E71A00F94976 /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 2F4EDAF2ED0A20F1ABEABB23 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; };
20 | 5B7F84F69C750E542715956A /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; };
21 | D95E1C411D88E71A00F94976 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
22 | D95E1C441D88E71A00F94976 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
23 | D95E1C461D88E71A00F94976 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
24 | D95E1C491D88E71A00F94976 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | D95E1C4B1D88E71A00F94976 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
26 | D95E1C4E1D88E71A00F94976 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
27 | D95E1C501D88E71A00F94976 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | EF0BDEE180E4FF5343803C14 /* libPods-Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | D95E1C3E1D88E71A00F94976 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | 5A9AB0995E376E2BB23DD56C /* libPods-Example.a in Frameworks */,
37 | );
38 | runOnlyForDeploymentPostprocessing = 0;
39 | };
40 | /* End PBXFrameworksBuildPhase section */
41 |
42 | /* Begin PBXGroup section */
43 | 5FE3BF921617E8AC7F96F5E2 /* Pods */ = {
44 | isa = PBXGroup;
45 | children = (
46 | 2F4EDAF2ED0A20F1ABEABB23 /* Pods-Example.debug.xcconfig */,
47 | 5B7F84F69C750E542715956A /* Pods-Example.release.xcconfig */,
48 | );
49 | name = Pods;
50 | sourceTree = "";
51 | };
52 | D95E1C381D88E71A00F94976 = {
53 | isa = PBXGroup;
54 | children = (
55 | D95E1C431D88E71A00F94976 /* Source */,
56 | D95E1C421D88E71A00F94976 /* Products */,
57 | D95E1C881D88F39300F94976 /* Frameworks */,
58 | 5FE3BF921617E8AC7F96F5E2 /* Pods */,
59 | );
60 | sourceTree = "";
61 | };
62 | D95E1C421D88E71A00F94976 /* Products */ = {
63 | isa = PBXGroup;
64 | children = (
65 | D95E1C411D88E71A00F94976 /* Example.app */,
66 | );
67 | name = Products;
68 | sourceTree = "";
69 | };
70 | D95E1C431D88E71A00F94976 /* Source */ = {
71 | isa = PBXGroup;
72 | children = (
73 | D95E1C441D88E71A00F94976 /* AppDelegate.swift */,
74 | D95E1C461D88E71A00F94976 /* ViewController.swift */,
75 | D95E1C481D88E71A00F94976 /* Main.storyboard */,
76 | D95E1C4B1D88E71A00F94976 /* Assets.xcassets */,
77 | D95E1C4D1D88E71A00F94976 /* LaunchScreen.storyboard */,
78 | D95E1C501D88E71A00F94976 /* Info.plist */,
79 | );
80 | path = Source;
81 | sourceTree = "";
82 | };
83 | D95E1C881D88F39300F94976 /* Frameworks */ = {
84 | isa = PBXGroup;
85 | children = (
86 | EF0BDEE180E4FF5343803C14 /* libPods-Example.a */,
87 | );
88 | name = Frameworks;
89 | sourceTree = "";
90 | };
91 | /* End PBXGroup section */
92 |
93 | /* Begin PBXNativeTarget section */
94 | D95E1C401D88E71A00F94976 /* Example */ = {
95 | isa = PBXNativeTarget;
96 | buildConfigurationList = D95E1C531D88E71A00F94976 /* Build configuration list for PBXNativeTarget "Example" */;
97 | buildPhases = (
98 | 40BA18CCB7AF367DADD141CF /* [CP] Check Pods Manifest.lock */,
99 | DDF741061FD04EBB008081A5 /* SwiftGen */,
100 | D95E1C3D1D88E71A00F94976 /* Sources */,
101 | D95E1C3E1D88E71A00F94976 /* Frameworks */,
102 | D95E1C3F1D88E71A00F94976 /* Resources */,
103 | 37F4C362923734EAF6F4DFC5 /* [CP] Copy Pods Resources */,
104 | );
105 | buildRules = (
106 | );
107 | dependencies = (
108 | );
109 | name = Example;
110 | productName = Example;
111 | productReference = D95E1C411D88E71A00F94976 /* Example.app */;
112 | productType = "com.apple.product-type.application";
113 | };
114 | /* End PBXNativeTarget section */
115 |
116 | /* Begin PBXProject section */
117 | D95E1C391D88E71A00F94976 /* Project object */ = {
118 | isa = PBXProject;
119 | attributes = {
120 | LastSwiftUpdateCheck = 0800;
121 | LastUpgradeCheck = 1020;
122 | ORGANIZATIONNAME = Appwise;
123 | TargetAttributes = {
124 | D95E1C401D88E71A00F94976 = {
125 | CreatedOnToolsVersion = 8.0;
126 | DevelopmentTeam = JF4JXY8D87;
127 | LastSwiftMigration = 0910;
128 | ProvisioningStyle = Automatic;
129 | };
130 | };
131 | };
132 | buildConfigurationList = D95E1C3C1D88E71A00F94976 /* Build configuration list for PBXProject "Example" */;
133 | compatibilityVersion = "Xcode 3.2";
134 | developmentRegion = en;
135 | hasScannedForEncodings = 0;
136 | knownRegions = (
137 | en,
138 | Base,
139 | );
140 | mainGroup = D95E1C381D88E71A00F94976;
141 | productRefGroup = D95E1C421D88E71A00F94976 /* Products */;
142 | projectDirPath = "";
143 | projectRoot = "";
144 | targets = (
145 | D95E1C401D88E71A00F94976 /* Example */,
146 | );
147 | };
148 | /* End PBXProject section */
149 |
150 | /* Begin PBXResourcesBuildPhase section */
151 | D95E1C3F1D88E71A00F94976 /* Resources */ = {
152 | isa = PBXResourcesBuildPhase;
153 | buildActionMask = 2147483647;
154 | files = (
155 | D95E1C4F1D88E71A00F94976 /* LaunchScreen.storyboard in Resources */,
156 | D95E1C4C1D88E71A00F94976 /* Assets.xcassets in Resources */,
157 | D95E1C4A1D88E71A00F94976 /* Main.storyboard in Resources */,
158 | );
159 | runOnlyForDeploymentPostprocessing = 0;
160 | };
161 | /* End PBXResourcesBuildPhase section */
162 |
163 | /* Begin PBXShellScriptBuildPhase section */
164 | 37F4C362923734EAF6F4DFC5 /* [CP] Copy Pods Resources */ = {
165 | isa = PBXShellScriptBuildPhase;
166 | buildActionMask = 2147483647;
167 | files = (
168 | );
169 | inputPaths = (
170 | "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources.sh",
171 | "${PODS_ROOT}/CountryPickerSwift/CountryPicker/Classes/CountryView.xib",
172 | "${PODS_ROOT}/CountryPickerSwift/CountryPicker/Assets/CountryPicker.bundle",
173 | "${PODS_ROOT}/CountryPickerSwift/CountryPicker/Classes/Flags.xcassets",
174 | "${PODS_ROOT}/PhoneNumberKit/PhoneNumberKit/Resources/PhoneNumberMetadata.json",
175 | "${PODS_CONFIGURATION_BUILD_DIR}/PhoneVerificationController/PhoneVerificationControllerResources.bundle",
176 | );
177 | name = "[CP] Copy Pods Resources";
178 | outputPaths = (
179 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/CountryView.nib",
180 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/CountryPicker.bundle",
181 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car",
182 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/PhoneNumberMetadata.json",
183 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/PhoneVerificationControllerResources.bundle",
184 | );
185 | runOnlyForDeploymentPostprocessing = 0;
186 | shellPath = /bin/sh;
187 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n";
188 | showEnvVarsInLog = 0;
189 | };
190 | 40BA18CCB7AF367DADD141CF /* [CP] Check Pods Manifest.lock */ = {
191 | isa = PBXShellScriptBuildPhase;
192 | buildActionMask = 2147483647;
193 | files = (
194 | );
195 | inputPaths = (
196 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
197 | "${PODS_ROOT}/Manifest.lock",
198 | );
199 | name = "[CP] Check Pods Manifest.lock";
200 | outputPaths = (
201 | "$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt",
202 | );
203 | runOnlyForDeploymentPostprocessing = 0;
204 | shellPath = /bin/sh;
205 | 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";
206 | showEnvVarsInLog = 0;
207 | };
208 | DDF741061FD04EBB008081A5 /* SwiftGen */ = {
209 | isa = PBXShellScriptBuildPhase;
210 | buildActionMask = 2147483647;
211 | files = (
212 | );
213 | inputPaths = (
214 | );
215 | name = SwiftGen;
216 | outputPaths = (
217 | );
218 | runOnlyForDeploymentPostprocessing = 0;
219 | shellPath = /bin/sh;
220 | shellScript = "cd ..\n./Example/Pods/Swiftgen/bin/swiftgen\n";
221 | };
222 | /* End PBXShellScriptBuildPhase section */
223 |
224 | /* Begin PBXSourcesBuildPhase section */
225 | D95E1C3D1D88E71A00F94976 /* Sources */ = {
226 | isa = PBXSourcesBuildPhase;
227 | buildActionMask = 2147483647;
228 | files = (
229 | D95E1C471D88E71A00F94976 /* ViewController.swift in Sources */,
230 | D95E1C451D88E71A00F94976 /* AppDelegate.swift in Sources */,
231 | );
232 | runOnlyForDeploymentPostprocessing = 0;
233 | };
234 | /* End PBXSourcesBuildPhase section */
235 |
236 | /* Begin PBXVariantGroup section */
237 | D95E1C481D88E71A00F94976 /* Main.storyboard */ = {
238 | isa = PBXVariantGroup;
239 | children = (
240 | D95E1C491D88E71A00F94976 /* Base */,
241 | );
242 | name = Main.storyboard;
243 | sourceTree = "";
244 | };
245 | D95E1C4D1D88E71A00F94976 /* LaunchScreen.storyboard */ = {
246 | isa = PBXVariantGroup;
247 | children = (
248 | D95E1C4E1D88E71A00F94976 /* Base */,
249 | );
250 | name = LaunchScreen.storyboard;
251 | sourceTree = "";
252 | };
253 | /* End PBXVariantGroup section */
254 |
255 | /* Begin XCBuildConfiguration section */
256 | D95E1C511D88E71A00F94976 /* Debug */ = {
257 | isa = XCBuildConfiguration;
258 | buildSettings = {
259 | ALWAYS_SEARCH_USER_PATHS = NO;
260 | CLANG_ANALYZER_NONNULL = YES;
261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
262 | CLANG_CXX_LIBRARY = "libc++";
263 | CLANG_ENABLE_MODULES = YES;
264 | CLANG_ENABLE_OBJC_ARC = YES;
265 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
266 | CLANG_WARN_BOOL_CONVERSION = YES;
267 | CLANG_WARN_COMMA = YES;
268 | CLANG_WARN_CONSTANT_CONVERSION = YES;
269 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
271 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
272 | CLANG_WARN_EMPTY_BODY = YES;
273 | CLANG_WARN_ENUM_CONVERSION = YES;
274 | CLANG_WARN_INFINITE_RECURSION = YES;
275 | CLANG_WARN_INT_CONVERSION = YES;
276 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
277 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
280 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
281 | CLANG_WARN_STRICT_PROTOTYPES = YES;
282 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
283 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
284 | CLANG_WARN_UNREACHABLE_CODE = YES;
285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
286 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
287 | COPY_PHASE_STRIP = NO;
288 | DEBUG_INFORMATION_FORMAT = dwarf;
289 | ENABLE_STRICT_OBJC_MSGSEND = YES;
290 | ENABLE_TESTABILITY = YES;
291 | GCC_C_LANGUAGE_STANDARD = gnu99;
292 | GCC_DYNAMIC_NO_PIC = NO;
293 | GCC_NO_COMMON_BLOCKS = YES;
294 | GCC_OPTIMIZATION_LEVEL = 0;
295 | GCC_PREPROCESSOR_DEFINITIONS = (
296 | "DEBUG=1",
297 | "$(inherited)",
298 | );
299 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
300 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
301 | GCC_WARN_UNDECLARED_SELECTOR = YES;
302 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
303 | GCC_WARN_UNUSED_FUNCTION = YES;
304 | GCC_WARN_UNUSED_VARIABLE = YES;
305 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
306 | MTL_ENABLE_DEBUG_INFO = YES;
307 | ONLY_ACTIVE_ARCH = YES;
308 | SDKROOT = iphoneos;
309 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
310 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
311 | TARGETED_DEVICE_FAMILY = "1,2";
312 | };
313 | name = Debug;
314 | };
315 | D95E1C521D88E71A00F94976 /* Release */ = {
316 | isa = XCBuildConfiguration;
317 | buildSettings = {
318 | ALWAYS_SEARCH_USER_PATHS = NO;
319 | CLANG_ANALYZER_NONNULL = YES;
320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
321 | CLANG_CXX_LIBRARY = "libc++";
322 | CLANG_ENABLE_MODULES = YES;
323 | CLANG_ENABLE_OBJC_ARC = YES;
324 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
325 | CLANG_WARN_BOOL_CONVERSION = YES;
326 | CLANG_WARN_COMMA = YES;
327 | CLANG_WARN_CONSTANT_CONVERSION = YES;
328 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
329 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
330 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
331 | CLANG_WARN_EMPTY_BODY = YES;
332 | CLANG_WARN_ENUM_CONVERSION = YES;
333 | CLANG_WARN_INFINITE_RECURSION = YES;
334 | CLANG_WARN_INT_CONVERSION = YES;
335 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
336 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
337 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
338 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
339 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
340 | CLANG_WARN_STRICT_PROTOTYPES = YES;
341 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
342 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
343 | CLANG_WARN_UNREACHABLE_CODE = YES;
344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
345 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
346 | COPY_PHASE_STRIP = NO;
347 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
348 | ENABLE_NS_ASSERTIONS = NO;
349 | ENABLE_STRICT_OBJC_MSGSEND = YES;
350 | GCC_C_LANGUAGE_STANDARD = gnu99;
351 | GCC_NO_COMMON_BLOCKS = YES;
352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
354 | GCC_WARN_UNDECLARED_SELECTOR = YES;
355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
356 | GCC_WARN_UNUSED_FUNCTION = YES;
357 | GCC_WARN_UNUSED_VARIABLE = YES;
358 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
359 | MTL_ENABLE_DEBUG_INFO = NO;
360 | SDKROOT = iphoneos;
361 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
362 | TARGETED_DEVICE_FAMILY = "1,2";
363 | VALIDATE_PRODUCT = YES;
364 | };
365 | name = Release;
366 | };
367 | D95E1C541D88E71A00F94976 /* Debug */ = {
368 | isa = XCBuildConfiguration;
369 | baseConfigurationReference = 2F4EDAF2ED0A20F1ABEABB23 /* Pods-Example.debug.xcconfig */;
370 | buildSettings = {
371 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
372 | DEVELOPMENT_TEAM = JF4JXY8D87;
373 | INFOPLIST_FILE = Source/Info.plist;
374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
375 | PRODUCT_BUNDLE_IDENTIFIER = be.appwise.Example;
376 | PRODUCT_NAME = "$(TARGET_NAME)";
377 | SWIFT_VERSION = 5.0;
378 | };
379 | name = Debug;
380 | };
381 | D95E1C551D88E71A00F94976 /* Release */ = {
382 | isa = XCBuildConfiguration;
383 | baseConfigurationReference = 5B7F84F69C750E542715956A /* Pods-Example.release.xcconfig */;
384 | buildSettings = {
385 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
386 | DEVELOPMENT_TEAM = JF4JXY8D87;
387 | INFOPLIST_FILE = Source/Info.plist;
388 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
389 | PRODUCT_BUNDLE_IDENTIFIER = be.appwise.Example;
390 | PRODUCT_NAME = "$(TARGET_NAME)";
391 | SWIFT_VERSION = 5.0;
392 | };
393 | name = Release;
394 | };
395 | /* End XCBuildConfiguration section */
396 |
397 | /* Begin XCConfigurationList section */
398 | D95E1C3C1D88E71A00F94976 /* Build configuration list for PBXProject "Example" */ = {
399 | isa = XCConfigurationList;
400 | buildConfigurations = (
401 | D95E1C511D88E71A00F94976 /* Debug */,
402 | D95E1C521D88E71A00F94976 /* Release */,
403 | );
404 | defaultConfigurationIsVisible = 0;
405 | defaultConfigurationName = Release;
406 | };
407 | D95E1C531D88E71A00F94976 /* Build configuration list for PBXNativeTarget "Example" */ = {
408 | isa = XCConfigurationList;
409 | buildConfigurations = (
410 | D95E1C541D88E71A00F94976 /* Debug */,
411 | D95E1C551D88E71A00F94976 /* Release */,
412 | );
413 | defaultConfigurationIsVisible = 0;
414 | defaultConfigurationName = Release;
415 | };
416 | /* End XCConfigurationList section */
417 | };
418 | rootObject = D95E1C391D88E71A00F94976 /* Project object */;
419 | }
420 |
--------------------------------------------------------------------------------
/Resources/PhoneVerificationController.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 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
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 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
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 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
--------------------------------------------------------------------------------