Эх сурвалжийг харах

feat: better camera, with photo selection

dignifiedquire 6 жил өмнө
parent
commit
648ec8c0fb
100 өөрчлөгдсөн 4926 нэмэгдсэн , 950 устгасан
  1. 3 9
      Podfile
  2. 13 1
      Podfile.lock
  3. 18 0
      Pods/ALCameraViewController/ALCameraViewController/CameraView.strings
  4. 6 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/Contents.json
  5. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/Contents.json
  6. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/cameraButton.png
  7. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/cameraButton@2x.png
  8. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/cameraButton@3x.png
  9. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/Contents.json
  10. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/cameraButtonHighlighted.png
  11. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/cameraButtonHighlighted@2x.png
  12. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/cameraButtonHighlighted@3x.png
  13. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/Contents.json
  14. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/closeButton.png
  15. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/closeButton@2x.png
  16. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/closeButton@3x.png
  17. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/Contents.json
  18. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/confirmButton.png
  19. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/confirmButton@2x.png
  20. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/confirmButton@3x.png
  21. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/Contents.json
  22. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/flashAutoIcon.png
  23. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/flashAutoIcon@2x.png
  24. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/flashAutoIcon@3x.png
  25. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/Contents.json
  26. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/flashOffIcon.png
  27. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/flashOffIcon@2x.png
  28. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/flashOffIcon@3x.png
  29. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/Contents.json
  30. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/flashOnIcon.png
  31. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/flashOnIcon@2x.png
  32. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/flashOnIcon@3x.png
  33. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/Contents.json
  34. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/libraryButton.png
  35. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/libraryButton@2x.png
  36. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/libraryButton@3x.png
  37. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/Contents.json
  38. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/libraryCancel.png
  39. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/libraryCancel@2x.png
  40. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/libraryCancel@3x.png
  41. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/Contents.json
  42. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/libraryConfirm.png
  43. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/libraryConfirm@2x.png
  44. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/libraryConfirm@3x.png
  45. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/Contents.json
  46. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/cameraPermissionsIcon.png
  47. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/cameraPermissionsIcon@2x.png
  48. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/cameraPermissionsIcon@3x.png
  49. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/Contents.json
  50. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/placeholder.png
  51. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/placeholder@2x.png
  52. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/placeholder@3x.png
  53. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/Contents.json
  54. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/retakeButton.png
  55. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/retakeButton@2x.png
  56. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/retakeButton@3x.png
  57. 23 0
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/Contents.json
  58. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/swapButton.png
  59. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/swapButton@2x.png
  60. BIN
      Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/swapButton@3x.png
  61. 24 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/CameraGlobals.swift
  62. 56 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/CameraShot.swift
  63. 39 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/CroppingParameters.swift
  64. 64 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/ImageFetcher.swift
  65. 47 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/PhotoLibraryAuthorizer.swift
  66. 95 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/SingleImageFetcher.swift
  67. 94 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/SingleImageSaver.swift
  68. 54 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/UIButtonExtensions.swift
  69. 9 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/UIViewExtensions.swift
  70. 126 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/Utilities.swift
  71. 49 0
      Pods/ALCameraViewController/ALCameraViewController/Utilities/VolumeControl.swift
  72. 649 0
      Pods/ALCameraViewController/ALCameraViewController/ViewController/CameraViewController.swift
  73. 528 0
      Pods/ALCameraViewController/ALCameraViewController/ViewController/CameraViewControllerConstraint.swift
  74. 365 0
      Pods/ALCameraViewController/ALCameraViewController/ViewController/ConfirmViewController.swift
  75. 210 0
      Pods/ALCameraViewController/ALCameraViewController/ViewController/ConfirmViewController.xib
  76. 127 0
      Pods/ALCameraViewController/ALCameraViewController/ViewController/PhotoLibraryViewController.swift
  77. 299 0
      Pods/ALCameraViewController/ALCameraViewController/Views/CameraView.swift
  78. 215 0
      Pods/ALCameraViewController/ALCameraViewController/Views/CropOverlay.swift
  79. 55 0
      Pods/ALCameraViewController/ALCameraViewController/Views/ImageCell.swift
  80. 123 0
      Pods/ALCameraViewController/ALCameraViewController/Views/PermissionsView.swift
  81. 22 0
      Pods/ALCameraViewController/LICENSE
  82. 149 0
      Pods/ALCameraViewController/README.md
  83. 27 0
      Pods/Local Podspecs/ALCameraViewController.podspec.json
  84. 13 1
      Pods/Manifest.lock
  85. 951 898
      Pods/Pods.xcodeproj/project.pbxproj
  86. 5 0
      Pods/Target Support Files/ALCameraViewController/ALCameraViewController-dummy.m
  87. 12 0
      Pods/Target Support Files/ALCameraViewController/ALCameraViewController-prefix.pch
  88. 16 0
      Pods/Target Support Files/ALCameraViewController/ALCameraViewController-umbrella.h
  89. 6 0
      Pods/Target Support Files/ALCameraViewController/ALCameraViewController.modulemap
  90. 10 0
      Pods/Target Support Files/ALCameraViewController/ALCameraViewController.xcconfig
  91. 26 0
      Pods/Target Support Files/ALCameraViewController/Info.plist
  92. 26 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.markdown
  93. 32 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.plist
  94. 2 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh
  95. 3 3
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.debug.xcconfig
  96. 3 3
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.release.xcconfig
  97. 2 0
      deltachat-ios.xcodeproj/project.pbxproj
  98. 1 6
      deltachat-ios/AppDelegate.swift
  99. 29 29
      deltachat-ios/ChatViewController.swift
  100. 1 0
      deltachat-ios/ContactProfileViewController.swift

+ 3 - 9
Podfile

@@ -1,5 +1,7 @@
 target 'deltachat-ios' do
   use_frameworks!
+  swift_version = '4.2'
+  pod 'ALCameraViewController', :git => 'https://github.com/dignifiedquire/ALCameraViewController'
   pod 'openssl-ios-bitcode', '1.0.210'
   pod 'ReachabilitySwift'
   pod 'QuickTableViewController'
@@ -7,13 +9,5 @@ target 'deltachat-ios' do
   pod 'SwiftyBeaver'
   pod 'DBDebugToolkit'
   pod 'MessageKit', '2.0.0'
-  post_install do |installer|
-      installer.pods_project.targets.each do |target|
-          if target.name == 'MessageKit'
-              target.build_configurations.each do |config|
-                  config.build_settings['SWIFT_VERSION'] = '4.2'
-              end
-          end
-      end
-  end
+
 end

+ 13 - 1
Podfile.lock

@@ -1,4 +1,5 @@
 PODS:
+  - ALCameraViewController (3.0.3)
   - DBDebugToolkit (0.5.0)
   - JGProgressHUD (2.0.3)
   - MessageInputBar/Core (0.4.1)
@@ -10,6 +11,7 @@ PODS:
   - SwiftyBeaver (1.6.1)
 
 DEPENDENCIES:
+  - ALCameraViewController (from `https://github.com/dignifiedquire/ALCameraViewController`)
   - DBDebugToolkit
   - JGProgressHUD
   - MessageKit (= 2.0.0)
@@ -29,7 +31,17 @@ SPEC REPOS:
     - ReachabilitySwift
     - SwiftyBeaver
 
+EXTERNAL SOURCES:
+  ALCameraViewController:
+    :git: https://github.com/dignifiedquire/ALCameraViewController
+
+CHECKOUT OPTIONS:
+  ALCameraViewController:
+    :commit: e0fcc4338276e4fc6240e8726ecc77aa39ce1385
+    :git: https://github.com/dignifiedquire/ALCameraViewController
+
 SPEC CHECKSUMS:
+  ALCameraViewController: dd13cf0a5b44a4d542c73bbcbebd02bc09e929c7
   DBDebugToolkit: c04bb6f618051d3de447a4b4323f37826116cfed
   JGProgressHUD: 12b20a8f4ffe05258f8635c1ab92816e451f904d
   MessageInputBar: e81c7535347f1f7b923de7080409a535a004b6e4
@@ -39,6 +51,6 @@ SPEC CHECKSUMS:
   ReachabilitySwift: 408477d1b6ed9779dba301953171e017c31241f3
   SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a
 
-PODFILE CHECKSUM: 68c148b02e1dc4050bbbf02257c1216b82641b16
+PODFILE CHECKSUM: 754ae089b2ba2b296811903f136cbcc4b8f52d5a
 
 COCOAPODS: 1.5.3

+ 18 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraView.strings

@@ -0,0 +1,18 @@
+/* 
+  ALCameraView.strings
+  ALCameraViewController
+
+  Created by Alex Littlejohn on 2015/06/25.
+  Copyright (c) 2015 zero. All rights reserved.
+*/
+
+"permissions.title" = "Camera Access Denied";
+"permissions.description" = "Please enable camera access in your privacy settings";
+
+"permissions.library.title" = "Photos Access Denied";
+"permissions.library.description" = "Please enable photo library access in your privacy settings";
+
+"permissions.settings" = "Settings";
+
+"error.cant-fetch-photo" = "Unable to fetch image";
+"error.cant-fetch-photo.description" = "Please check your network settings";

+ 6 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "cameraButton.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "cameraButton@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "cameraButton@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/cameraButton.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/cameraButton@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButton.imageset/cameraButton@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "cameraButtonHighlighted.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "cameraButtonHighlighted@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "cameraButtonHighlighted@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/cameraButtonHighlighted.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/cameraButtonHighlighted@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/cameraButtonHighlighted.imageset/cameraButtonHighlighted@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "closeButton.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "closeButton@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "closeButton@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/closeButton.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/closeButton@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/closeButton.imageset/closeButton@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "confirmButton.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "confirmButton@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "confirmButton@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/confirmButton.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/confirmButton@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/confirmButton.imageset/confirmButton@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "flashAutoIcon.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "flashAutoIcon@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "flashAutoIcon@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/flashAutoIcon.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/flashAutoIcon@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashAutoIcon.imageset/flashAutoIcon@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "flashOffIcon.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "flashOffIcon@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "flashOffIcon@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/flashOffIcon.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/flashOffIcon@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOffIcon.imageset/flashOffIcon@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "flashOnIcon.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "flashOnIcon@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "flashOnIcon@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/flashOnIcon.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/flashOnIcon@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/flashOnIcon.imageset/flashOnIcon@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "libraryButton.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "libraryButton@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "libraryButton@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/libraryButton.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/libraryButton@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryButton.imageset/libraryButton@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "libraryCancel.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "libraryCancel@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "libraryCancel@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/libraryCancel.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/libraryCancel@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryCancel.imageset/libraryCancel@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "libraryConfirm.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "libraryConfirm@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "libraryConfirm@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/libraryConfirm.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/libraryConfirm@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/libraryConfirm.imageset/libraryConfirm@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "cameraPermissionsIcon.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "cameraPermissionsIcon@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "cameraPermissionsIcon@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/cameraPermissionsIcon.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/cameraPermissionsIcon@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/permissionsIcon.imageset/cameraPermissionsIcon@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "placeholder.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "placeholder@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "placeholder@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/placeholder.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/placeholder@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/placeholder.imageset/placeholder@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "retakeButton.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "retakeButton@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "retakeButton@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/retakeButton.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/retakeButton@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/retakeButton.imageset/retakeButton@3x.png


+ 23 - 0
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x",
+      "filename" : "swapButton.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x",
+      "filename" : "swapButton@2x.png"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x",
+      "filename" : "swapButton@3x.png"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/swapButton.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/swapButton@2x.png


BIN
Pods/ALCameraViewController/ALCameraViewController/CameraViewAssets.xcassets/swapButton.imageset/swapButton@3x.png


+ 24 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/CameraGlobals.swift

@@ -0,0 +1,24 @@
+//
+//  CameraGlobals.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2016/02/16.
+//  Copyright © 2016 zero. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+
+internal let itemSpacing: CGFloat = 1
+internal let columns: CGFloat = 4
+internal let thumbnailDimension = (UIScreen.main.bounds.width - ((columns * itemSpacing) - itemSpacing))/columns
+internal let scale = UIScreen.main.scale
+
+public class CameraGlobals {
+    public static let shared = CameraGlobals()
+    
+    public var bundle = Bundle(for: CameraViewController.self)
+    public var stringsTable = "CameraView"
+    public var photoLibraryThumbnailSize = CGSize(width: thumbnailDimension, height: thumbnailDimension)
+    public var defaultCameraPosition = AVCaptureDevice.Position.back
+}

+ 56 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/CameraShot.swift

@@ -0,0 +1,56 @@
+//
+//  CameraShot.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2015/06/17.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+
+public typealias CameraShotCompletion = (UIImage?) -> Void
+
+public func takePhoto(_ stillImageOutput: AVCaptureStillImageOutput, videoOrientation: AVCaptureVideoOrientation, cameraPosition: AVCaptureDevice.Position, cropSize: CGSize, completion: @escaping CameraShotCompletion) {
+    
+    guard let videoConnection: AVCaptureConnection = stillImageOutput.connection(with: AVMediaType.video) else {
+        completion(nil)
+        return
+    }
+    
+    videoConnection.videoOrientation = videoOrientation
+    
+    stillImageOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: { buffer, error in
+        
+        guard let buffer = buffer,
+            let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer),
+            var image = UIImage(data: imageData) else {
+            completion(nil)
+            return
+        }
+
+        // flip the image to match the orientation of the preview
+        if cameraPosition == .front, let cgImage = image.cgImage {
+            switch image.imageOrientation {
+            case .leftMirrored:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .right)
+            case .left:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .rightMirrored)
+            case .rightMirrored:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .left)
+            case .right:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .leftMirrored)
+            case .up:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .upMirrored)
+            case .upMirrored:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .up)
+            case .down:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .downMirrored)
+            case .downMirrored:
+                image = UIImage(cgImage: cgImage, scale: image.scale, orientation: .down)
+            }
+        }
+        
+        completion(image)
+    })
+}

+ 39 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/CroppingParameters.swift

@@ -0,0 +1,39 @@
+//
+//  CroppingParameters.swift
+//  ALCameraViewController
+//
+//  Created by Guillaume Bellut on 02/09/2017.
+//  Copyright © 2017 zero. All rights reserved.
+//
+
+import UIKit
+
+public struct CroppingParameters {
+
+    /// Enable the cropping feature.
+    /// Default value is set to false.
+    var isEnabled: Bool
+
+    /// Allow the cropping area to be resized by the user.
+    /// Default value is set to true.
+    var allowResizing: Bool
+
+    /// Allow the cropping area to be moved by the user.
+    /// Default value is set to false.
+    var allowMoving: Bool
+
+    /// Prevent the user to resize the cropping area below a minimum size.
+    /// Default value is (60, 60). Below this value, corner buttons will overlap.
+    var minimumSize: CGSize
+
+    public init(isEnabled: Bool = false,
+                allowResizing: Bool = true,
+                allowMoving: Bool = true,
+         minimumSize: CGSize = CGSize(width: 60, height: 60)) {
+
+        self.isEnabled = isEnabled
+        self.allowResizing = allowResizing
+        self.allowMoving = allowMoving
+        self.minimumSize = minimumSize
+    }
+}

+ 64 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/ImageFetcher.swift

@@ -0,0 +1,64 @@
+//
+//  ALImageFetchingInteractor.swift
+//  ALImagePickerViewController
+//
+//  Created by Alex Littlejohn on 2015/06/09.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+public typealias ImageFetcherSuccess = (PHFetchResult<PHAsset>) -> ()
+public typealias ImageFetcherFailure = (NSError) -> ()
+
+//extension PHFetchResult: Sequence {
+//    public func makeIterator() -> NSFastEnumerationIterator {
+//        return NSFastEnumerationIterator(self)
+//    }
+//}
+
+public class ImageFetcher {
+
+    private var success: ImageFetcherSuccess?
+    private var failure: ImageFetcherFailure?
+    
+    private var authRequested = false
+    private let errorDomain = "com.zero.imageFetcher"
+    
+    let libraryQueue = DispatchQueue(label: "com.zero.ALCameraViewController.LibraryQueue");
+    
+    public init() { }
+    
+    public func onSuccess(_ success: @escaping ImageFetcherSuccess) -> Self {
+        self.success = success
+        return self
+    }
+    
+    public func onFailure(_ failure: @escaping ImageFetcherFailure) -> Self {
+        self.failure = failure
+        return self
+    }
+    
+    public func fetch() -> Self {
+        _ = PhotoLibraryAuthorizer { error in
+            if error == nil {
+                self.onAuthorized()
+            } else {
+                self.failure?(error!)
+            }
+        }
+        return self
+    }
+    
+    private func onAuthorized() {
+        let options = PHFetchOptions()
+        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
+        libraryQueue.async {
+            let assets = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: options)
+            DispatchQueue.main.async {
+                self.success?(assets)
+            }
+        }
+    }
+}

+ 47 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/PhotoLibraryAuthorizer.swift

@@ -0,0 +1,47 @@
+//
+//  PhotoLibraryAuthorizer.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2016/03/26.
+//  Copyright © 2016 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+public typealias PhotoLibraryAuthorizerCompletion = (NSError?) -> Void
+
+class PhotoLibraryAuthorizer {
+
+    private let errorDomain = "com.zero.imageFetcher"
+
+    private let completion: PhotoLibraryAuthorizerCompletion
+
+    init(completion: @escaping PhotoLibraryAuthorizerCompletion) {
+        self.completion = completion
+        handleAuthorization(status: PHPhotoLibrary.authorizationStatus())
+    }
+    
+    func onDeniedOrRestricted(completion: PhotoLibraryAuthorizerCompletion) {
+        let error = errorWithKey("error.access-denied", domain: errorDomain)
+        completion(error)
+    }
+    
+    func handleAuthorization(status: PHAuthorizationStatus) {
+        switch status {
+        case .notDetermined:
+            PHPhotoLibrary.requestAuthorization(handleAuthorization)
+            break
+        case .authorized:
+            DispatchQueue.main.async {
+                self.completion(nil)
+            }
+            break
+        case .denied, .restricted:
+            DispatchQueue.main.async {
+                self.onDeniedOrRestricted(completion: self.completion)
+            }
+            break
+        }
+    }
+}

+ 95 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/SingleImageFetcher.swift

@@ -0,0 +1,95 @@
+//
+//  SingleImageFetcher.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2016/02/16.
+//  Copyright © 2016 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+public typealias SingleImageFetcherSuccess = (UIImage) -> Void
+public typealias SingleImageFetcherFailure = (NSError) -> Void
+
+public class SingleImageFetcher {
+    private let errorDomain = "com.zero.singleImageSaver"
+    
+    private var success: SingleImageFetcherSuccess?
+    private var failure: SingleImageFetcherFailure?
+    
+    private var asset: PHAsset?
+    private var targetSize = PHImageManagerMaximumSize
+    private var cropRect: CGRect?
+    
+    public init() { }
+    
+    public func onSuccess(_ success: @escaping SingleImageFetcherSuccess) -> Self {
+        self.success = success
+        return self
+    }
+    
+    public func onFailure(_ failure: @escaping SingleImageFetcherFailure) -> Self {
+        self.failure = failure
+        return self
+    }
+    
+    public func setAsset(_ asset: PHAsset) -> Self {
+        self.asset = asset
+        return self
+    }
+    
+    public func setTargetSize(_ targetSize: CGSize) -> Self {
+        self.targetSize = targetSize
+        return self
+    }
+    
+    public func setCropRect(_ cropRect: CGRect) -> Self {
+        self.cropRect = cropRect
+        return self
+    }
+    
+    public func fetch() -> Self {
+        _ = PhotoLibraryAuthorizer { error in
+            if error == nil {
+                self._fetch()
+            } else {
+                self.failure?(error!)
+            }
+        }
+        return self
+    }
+    
+    private func _fetch() {
+    
+        guard let asset = asset else {
+            let error = errorWithKey("error.cant-fetch-photo", domain: errorDomain)
+            failure?(error)
+            return
+        }
+        
+        let options = PHImageRequestOptions()
+        options.deliveryMode = .highQualityFormat
+        options.isNetworkAccessAllowed = true
+
+        if let cropRect = cropRect {
+
+            options.normalizedCropRect = cropRect
+            options.resizeMode = .exact
+            
+            let targetWidth = floor(CGFloat(asset.pixelWidth) * cropRect.width)
+			let targetHeight = floor(CGFloat(asset.pixelHeight) * cropRect.height)
+			
+			targetSize = CGSize(width: targetWidth, height: targetHeight)
+        }
+		
+        PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, _ in
+            if let image = image {
+                self.success?(image)
+            } else {
+                let error = errorWithKey("error.cant-fetch-photo", domain: self.errorDomain)
+                self.failure?(error)
+            }
+        }
+    }
+}

+ 94 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/SingleImageSaver.swift

@@ -0,0 +1,94 @@
+//
+//  SingleImageSavingInteractor.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2016/02/16.
+//  Copyright © 2016 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+public typealias SingleImageSaverSuccess = (PHAsset) -> Void
+public typealias SingleImageSaverFailure = (NSError) -> Void
+
+public class SingleImageSaver {
+    private let errorDomain = "com.zero.singleImageSaver"
+    
+    private var success: SingleImageSaverSuccess?
+    private var failure: SingleImageSaverFailure?
+    
+    private var image: UIImage?
+    
+    public init() { }
+    
+    public func onSuccess(_ success: @escaping SingleImageSaverSuccess) -> Self {
+        self.success = success
+        return self
+    }
+    
+    public func onFailure(_ failure: @escaping SingleImageSaverFailure) -> Self {
+        self.failure = failure
+        return self
+    }
+    
+    public func setImage(_ image: UIImage) -> Self {
+        self.image = image
+        return self
+    }
+    
+    public func save() -> Self {
+        
+        _ = PhotoLibraryAuthorizer { error in
+            if error == nil {
+                self._save()
+            } else {
+                self.failure?(error!)
+            }
+        }
+
+        return self
+    }
+    
+    private func _save() {
+        guard let image = image else {
+            self.invokeFailure()
+            return
+        }
+        
+        var assetIdentifier: PHObjectPlaceholder?
+        
+        PHPhotoLibrary.shared()
+            .performChanges({
+                let request = PHAssetChangeRequest.creationRequestForAsset(from: image)
+                assetIdentifier = request.placeholderForCreatedAsset
+            }) { finished, error in
+                
+                guard let assetIdentifier = assetIdentifier, finished else {
+                    self.invokeFailure()
+                    return
+                }
+                
+                self.fetch(assetIdentifier)
+        }
+    }
+    
+    private func fetch(_ assetIdentifier: PHObjectPlaceholder) {
+        
+        let assets = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier.localIdentifier], options: nil)
+        
+        DispatchQueue.main.async {
+            guard let asset = assets.firstObject else {
+                self.invokeFailure()
+                return
+            }
+            
+            self.success?(asset)
+        }
+    }
+    
+    private func invokeFailure() {
+        let error = errorWithKey("error.cant-fetch-photo", domain: errorDomain)
+        failure?(error)
+    }
+}

+ 54 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/UIButtonExtensions.swift

@@ -0,0 +1,54 @@
+//
+//  UIButtonExtensions.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2016/03/26.
+//  Copyright © 2016 zero. All rights reserved.
+//
+
+import UIKit
+
+typealias ButtonAction = () -> Void
+
+extension UIButton {
+    
+    private struct AssociatedKeys {
+        static var ActionKey = "ActionKey"
+    }
+    
+    private class ActionWrapper {
+        let action: ButtonAction
+        init(action: @escaping ButtonAction) {
+            self.action = action
+        }
+    }
+    
+    var action: ButtonAction? {
+        set(newValue) {
+            removeTarget(self, action: #selector(performAction), for: .touchUpInside)
+            var wrapper: ActionWrapper? = nil
+            if let newValue = newValue {
+                wrapper = ActionWrapper(action: newValue)
+                addTarget(self, action: #selector(performAction), for: .touchUpInside)
+            }
+            
+            objc_setAssociatedObject(self, &AssociatedKeys.ActionKey, wrapper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+        }
+        get {
+            guard let wrapper = objc_getAssociatedObject(self, &AssociatedKeys.ActionKey) as? ActionWrapper else {
+                return nil
+            }
+            
+            return wrapper.action
+        }
+    }
+    
+    @objc func performAction() {
+        guard let action = action else {
+            return
+        }
+
+        action()
+    }
+}
+

+ 9 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/UIViewExtensions.swift

@@ -0,0 +1,9 @@
+import UIKit
+
+extension UIView {
+  func autoRemoveConstraint(_ constraint : NSLayoutConstraint?) {
+    if constraint != nil {
+      removeConstraint(constraint!)
+    }
+  }
+}

+ 126 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/Utilities.swift

@@ -0,0 +1,126 @@
+//
+//  ALUtilities.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2015/06/25.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+
+internal func radians(_ degrees: CGFloat) -> CGFloat {
+    return degrees / 180 * .pi
+}
+
+internal func localizedString(_ key: String) -> String {
+    var bundle: Bundle {
+        if Bundle.main.path(forResource: CameraGlobals.shared.stringsTable, ofType: "strings") != nil {
+            return Bundle.main
+        }
+        return CameraGlobals.shared.bundle
+    }
+
+    return NSLocalizedString(key, tableName: CameraGlobals.shared.stringsTable, bundle: bundle, comment: key)
+}
+
+internal func currentRotation(_ oldOrientation: UIInterfaceOrientation, newOrientation: UIInterfaceOrientation) -> CGFloat {
+    switch oldOrientation {
+        case .portrait:
+            switch newOrientation {
+                case .landscapeLeft: return 90
+                case .landscapeRight: return -90
+                case .portraitUpsideDown: return 180
+                default: return 0
+            }
+            
+        case .landscapeLeft:
+            switch newOrientation {
+                case .portrait: return -90
+                case .landscapeRight: return 180
+                case .portraitUpsideDown: return 90
+                default: return 0
+            }
+            
+        case .landscapeRight:
+            switch newOrientation {
+                case .portrait: return 90
+                case .landscapeLeft: return 180
+                case .portraitUpsideDown: return -90
+                default: return 0
+            }
+            
+        default: return 0
+    }
+}
+
+internal func largestPhotoSize() -> CGSize {
+    let scale = UIScreen.main.scale
+    let screenSize = UIScreen.main.bounds.size
+    let size = CGSize(width: screenSize.width * scale, height: screenSize.height * scale)
+    return size
+}
+
+internal func errorWithKey(_ key: String, domain: String) -> NSError {
+    let errorString = localizedString(key)
+    let errorInfo = [NSLocalizedDescriptionKey: errorString]
+    let error = NSError(domain: domain, code: 0, userInfo: errorInfo)
+    return error
+}
+
+internal func normalizedRect(_ rect: CGRect, orientation: UIImage.Orientation) -> CGRect {
+    let normalizedX = rect.origin.x
+    let normalizedY = rect.origin.y
+    
+    let normalizedWidth = rect.width
+    let normalizedHeight = rect.height
+    
+    var normalizedRect: CGRect
+    
+    switch orientation {
+    case .up, .upMirrored:
+        normalizedRect = CGRect(x: normalizedX, y: normalizedY, width: normalizedWidth, height: normalizedHeight)
+    case .down, .downMirrored:
+        normalizedRect = CGRect(x: 1-normalizedX-normalizedWidth, y: 1-normalizedY-normalizedHeight, width: normalizedWidth, height: normalizedHeight)
+    case .left, .leftMirrored:
+        normalizedRect = CGRect(x: 1-normalizedY-normalizedHeight, y: normalizedX, width: normalizedHeight, height: normalizedWidth)
+    case .right, .rightMirrored:
+        normalizedRect = CGRect(x: normalizedY, y: 1-normalizedX-normalizedWidth, width: normalizedHeight, height: normalizedWidth)
+    }
+    
+    return normalizedRect
+}
+
+internal func flashImage(_ mode: AVCaptureDevice.FlashMode) -> String {
+    let image: String
+    switch mode {
+    case .auto:
+        image = "flashAutoIcon"
+    case .on:
+        image = "flashOnIcon"
+    case .off:
+        image = "flashOffIcon"
+    }
+    return image
+}
+
+struct ScreenSize {
+    static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
+    static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
+    static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
+}
+
+struct DeviceConfig {
+    static let SCREEN_MULTIPLIER : CGFloat = {
+        if UIDevice.current.userInterfaceIdiom == .phone {
+            switch ScreenSize.SCREEN_MAX_LENGTH {
+                case 568.0: return 1.5
+                case 667.0: return 2.0
+                case 736.0: return 4.0
+                default: return 1.0
+            }
+        } else {
+            return 1.0
+        }
+    }()
+}

+ 49 - 0
Pods/ALCameraViewController/ALCameraViewController/Utilities/VolumeControl.swift

@@ -0,0 +1,49 @@
+//
+//  VolumeControl.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2016/03/26.
+//  Copyright © 2016 zero. All rights reserved.
+//
+
+import UIKit
+import MediaPlayer
+
+typealias VolumeChangeAction = (Float) -> Void
+
+public class VolumeControl {
+    
+    let changeKey = "AVSystemController_SystemVolumeDidChangeNotification"
+    
+    lazy var volumeView: MPVolumeView = {
+        let view = MPVolumeView()
+        view.frame = CGRect(x: 0, y: 0, width: 1, height: 1)
+        view.alpha = 0.01
+        return view
+    }()
+    
+    var onVolumeChange: VolumeChangeAction?
+    
+    init(view: UIView, onVolumeChange: VolumeChangeAction?) {
+        self.onVolumeChange = onVolumeChange
+        view.addSubview(volumeView)
+        view.sendSubviewToBack(volumeView)
+        
+        try? AVAudioSession.sharedInstance().setActive(true)
+        NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged), name: NSNotification.Name(rawValue: changeKey), object: nil)
+    }
+
+    deinit {
+        try? AVAudioSession.sharedInstance().setActive(false)
+        NotificationCenter.default.removeObserver(self)
+        onVolumeChange = nil
+        volumeView.removeFromSuperview()
+    }
+
+    @objc func volumeChanged() {
+        guard let slider = volumeView.subviews.filter({ $0 is UISlider }).first as? UISlider else { return }
+        let volume = AVAudioSession.sharedInstance().outputVolume
+        slider.setValue(volume, animated: false)
+        onVolumeChange?(volume)
+    }
+}

+ 649 - 0
Pods/ALCameraViewController/ALCameraViewController/ViewController/CameraViewController.swift

@@ -0,0 +1,649 @@
+//
+//  CameraViewController.swift
+//  CameraViewController
+//
+//  Created by Alex Littlejohn.
+//  Copyright (c) 2016 zero. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+import Photos
+
+public typealias CameraViewCompletion = (UIImage?, PHAsset?) -> Void
+
+public extension CameraViewController {
+    /// Provides an image picker wrapped inside a UINavigationController instance
+    public class func imagePickerViewController(croppingParameters: CroppingParameters, completion: @escaping CameraViewCompletion) -> UINavigationController {
+        let imagePicker = PhotoLibraryViewController()
+        let navigationController = UINavigationController(rootViewController: imagePicker)
+        
+        navigationController.navigationBar.barTintColor = UIColor.black
+        navigationController.navigationBar.barStyle = UIBarStyle.black
+        navigationController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
+
+        imagePicker.onSelectionComplete = { [weak imagePicker] asset in
+            if let asset = asset {
+                let confirmController = ConfirmViewController(asset: asset, croppingParameters: croppingParameters)
+                confirmController.onComplete = { [weak imagePicker] image, asset in
+                    if let image = image, let asset = asset {
+                        completion(image, asset)
+                    } else {
+                        imagePicker?.dismiss(animated: true, completion: nil)
+                    }
+                }
+                confirmController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
+                imagePicker?.present(confirmController, animated: true, completion: nil)
+            } else {
+                completion(nil, nil)
+            }
+        }
+        
+        return navigationController
+    }
+}
+
+open class CameraViewController: UIViewController {
+    
+    var didUpdateViews = false
+    var croppingParameters: CroppingParameters
+    var animationRunning = false
+    let allowVolumeButtonCapture: Bool
+    
+    var lastInterfaceOrientation : UIInterfaceOrientation?
+    open var onCompletion: CameraViewCompletion?
+    var volumeControl: VolumeControl?
+    
+    var animationDuration: TimeInterval = 0.5
+    var animationSpring: CGFloat = 0.5
+    var rotateAnimation: UIView.AnimationOptions = .curveLinear
+    
+    var cameraButtonEdgeConstraint: NSLayoutConstraint?
+    var cameraButtonGravityConstraint: NSLayoutConstraint?
+    
+    var closeButtonEdgeConstraint: NSLayoutConstraint?
+    var closeButtonGravityConstraint: NSLayoutConstraint?
+    
+    var containerButtonsEdgeOneConstraint: NSLayoutConstraint?
+    var containerButtonsEdgeTwoConstraint: NSLayoutConstraint?
+    var containerButtonsGravityConstraint: NSLayoutConstraint?
+    
+    var swapButtonEdgeOneConstraint: NSLayoutConstraint?
+    var swapButtonEdgeTwoConstraint: NSLayoutConstraint?
+    var swapButtonGravityConstraint: NSLayoutConstraint?
+    
+    var libraryButtonEdgeOneConstraint: NSLayoutConstraint?
+    var libraryButtonEdgeTwoConstraint: NSLayoutConstraint?
+    var libraryButtonGravityConstraint: NSLayoutConstraint?
+    
+    var flashButtonEdgeConstraint: NSLayoutConstraint?
+    var flashButtonGravityConstraint: NSLayoutConstraint?
+    
+    var cameraOverlayEdgeOneConstraint: NSLayoutConstraint?
+    var cameraOverlayEdgeTwoConstraint: NSLayoutConstraint?
+    var cameraOverlayWidthConstraint: NSLayoutConstraint?
+    var cameraOverlayCenterConstraint: NSLayoutConstraint?
+    
+    let cameraView : CameraView = {
+        let cameraView = CameraView()
+        cameraView.translatesAutoresizingMaskIntoConstraints = false
+        return cameraView
+    }()
+
+    let cameraOverlay : CropOverlay = {
+        let cameraOverlay = CropOverlay()
+        cameraOverlay.translatesAutoresizingMaskIntoConstraints = false
+        return cameraOverlay
+    }()
+    
+    let cameraButton : UIButton = {
+        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 64, height: 64))
+        button.translatesAutoresizingMaskIntoConstraints = false
+        button.isEnabled = false
+        button.setImage(UIImage(named: "cameraButton",
+                                in: CameraGlobals.shared.bundle,
+                                compatibleWith: nil),
+                        for: .normal)
+        button.setImage(UIImage(named: "cameraButtonHighlighted",
+                                in: CameraGlobals.shared.bundle,
+                                compatibleWith: nil),
+                        for: .highlighted)
+        return button
+    }()
+    
+    let closeButton : UIButton = {
+        let button = UIButton()
+        button.translatesAutoresizingMaskIntoConstraints = false
+        button.setImage(UIImage(named: "closeButton",
+                                in: CameraGlobals.shared.bundle,
+                                compatibleWith: nil),
+                        for: .normal)
+        return button
+    }()
+    
+    let swapButton : UIButton = {
+        let button = UIButton()
+        button.translatesAutoresizingMaskIntoConstraints = false
+        button.setImage(UIImage(named: "swapButton",
+                                in: CameraGlobals.shared.bundle,
+                                compatibleWith: nil),
+                        for: .normal)
+        return button
+    }()
+    
+    let libraryButton : UIButton = {
+        let button = UIButton()
+        button.translatesAutoresizingMaskIntoConstraints = false
+        button.setImage(UIImage(named: "libraryButton",
+                                in: CameraGlobals.shared.bundle,
+                                compatibleWith: nil),
+                        for: .normal)
+        return button
+    }()
+    
+    let flashButton : UIButton = {
+        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
+        button.translatesAutoresizingMaskIntoConstraints = false
+        button.setImage(UIImage(named: "flashAutoIcon",
+                                in: CameraGlobals.shared.bundle,
+                                compatibleWith: nil),
+                        for: .normal)
+        return button
+    }()
+    
+    let containerSwapLibraryButton : UIView = {
+        let view = UIView()
+        view.translatesAutoresizingMaskIntoConstraints = false
+        return view
+    }()
+	
+	private let allowsLibraryAccess: Bool
+  
+    public init(croppingParameters: CroppingParameters = CroppingParameters(),
+                allowsLibraryAccess: Bool = true,
+                allowsSwapCameraOrientation: Bool = true,
+                allowVolumeButtonCapture: Bool = true,
+                completion: @escaping CameraViewCompletion) {
+
+        self.croppingParameters = croppingParameters
+        self.allowsLibraryAccess = allowsLibraryAccess
+        self.allowVolumeButtonCapture = allowVolumeButtonCapture
+        super.init(nibName: nil, bundle: nil)
+        onCompletion = completion
+        cameraOverlay.isHidden = !croppingParameters.isEnabled
+        cameraOverlay.isUserInteractionEnabled = false
+        libraryButton.isEnabled = allowsLibraryAccess
+        libraryButton.isHidden = !allowsLibraryAccess
+		swapButton.isEnabled = allowsSwapCameraOrientation
+		swapButton.isHidden = !allowsSwapCameraOrientation
+    }
+	
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    open override var prefersStatusBarHidden: Bool {
+        return true
+    }
+    
+    open override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
+        return UIStatusBarAnimation.slide
+    }
+    
+    /**
+     * Configure the background of the superview to black
+     * and add the views on this superview. Then, request
+     * the update of constraints for this superview.
+     */
+    open override func loadView() {
+        super.loadView()
+        view.backgroundColor = UIColor.black
+        [cameraView,
+            cameraOverlay,
+            cameraButton,
+            closeButton,
+            flashButton,
+            containerSwapLibraryButton].forEach({ view.addSubview($0) })
+        [swapButton, libraryButton].forEach({ containerSwapLibraryButton.addSubview($0) })
+        view.setNeedsUpdateConstraints()
+    }
+    
+    /**
+     * Setup the constraints when the app is starting or rotating
+     * the screen.
+     * To avoid the override/conflict of stable constraint, these
+     * stable constraint are one time configurable.
+     * Any other dynamic constraint are configurable when the
+     * device is rotating, based on the device orientation.
+     */
+    override open func updateViewConstraints() {
+
+        if !didUpdateViews {
+            configCameraViewConstraints()
+            didUpdateViews = true
+        }
+        
+        let statusBarOrientation = UIApplication.shared.statusBarOrientation
+        let portrait = statusBarOrientation.isPortrait
+        
+        configCameraButtonEdgeConstraint(statusBarOrientation)
+        configCameraButtonGravityConstraint(portrait)
+        
+        removeCloseButtonConstraints()
+        configCloseButtonEdgeConstraint(statusBarOrientation)
+        configCloseButtonGravityConstraint(statusBarOrientation)
+        
+        removeContainerConstraints()
+        configContainerEdgeConstraint(statusBarOrientation)
+        configContainerGravityConstraint(statusBarOrientation)
+        
+        removeSwapButtonConstraints()
+        configSwapButtonEdgeConstraint(statusBarOrientation)
+        configSwapButtonGravityConstraint(portrait)
+
+        removeLibraryButtonConstraints()
+        configLibraryEdgeButtonConstraint(statusBarOrientation)
+        configLibraryGravityButtonConstraint(portrait)
+        
+        configFlashEdgeButtonConstraint(statusBarOrientation)
+        configFlashGravityButtonConstraint(statusBarOrientation)
+        
+        let padding : CGFloat = portrait ? 16.0 : -16.0
+        removeCameraOverlayEdgesConstraints()
+        configCameraOverlayEdgeOneContraint(portrait, padding: padding)
+        configCameraOverlayEdgeTwoConstraint(portrait, padding: padding)
+        configCameraOverlayWidthConstraint(portrait)
+        configCameraOverlayCenterConstraint(portrait)
+        
+        rotate(actualInterfaceOrientation: statusBarOrientation)
+        
+        super.updateViewConstraints()
+    }
+    
+    /**
+     * Add observer to check when the camera has started,
+     * enable the volume buttons to take the picture,
+     * configure the actions of the buttons on the screen,
+     * check the permissions of access of the camera and
+     * the photo library.
+     * Configure the camera focus when the application
+     * start, to avoid any bluried image.
+     */
+    open override func viewDidLoad() {
+        super.viewDidLoad()
+        setupActions()
+        checkPermissions()
+        cameraView.configureFocus()
+        cameraView.configureZoom()
+    }
+
+    /**
+     * Start the session of the camera.
+     */
+    open override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        cameraView.startSession()
+        addCameraObserver()
+        addRotateObserver()
+
+        if allowVolumeButtonCapture {
+            setupVolumeControl()
+        }
+    }
+    
+    /**
+     * Enable the button to take the picture when the
+     * camera is ready.
+     */
+    open override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        if cameraView.session?.isRunning == true {
+            notifyCameraReady()
+        }
+    }
+
+    open override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        NotificationCenter.default.removeObserver(self)
+        volumeControl = nil
+    }
+
+    /**
+     * This method will disable the rotation of the
+     */
+    override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
+        super.viewWillTransition(to: size, with: coordinator)
+
+        lastInterfaceOrientation = UIApplication.shared.statusBarOrientation
+        if animationRunning {
+            return
+        }
+
+        CATransaction.begin()
+        CATransaction.setDisableActions(true)
+        coordinator.animate(alongsideTransition: { [weak self] animation in
+            self?.view.setNeedsUpdateConstraints()
+            }, completion: { _ in
+                CATransaction.commit()
+        })
+    }
+    
+    /**
+     * Observer the camera status, when it is ready,
+     * it calls the method cameraReady to enable the
+     * button to take the picture.
+     */
+    private func addCameraObserver() {
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(notifyCameraReady),
+            name: NSNotification.Name.AVCaptureSessionDidStartRunning,
+            object: nil)
+    }
+    
+    /**
+     * Observer the device orientation to update the
+     * orientation of CameraView.
+     */
+    private func addRotateObserver() {
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(rotateCameraView),
+            name: UIDevice.orientationDidChangeNotification,
+            object: nil)
+    }
+    
+    @objc internal func notifyCameraReady() {
+        cameraButton.isEnabled = true
+    }
+    
+    /**
+     * Attach the take of picture for any volume button.
+     */
+    private func setupVolumeControl() {
+        volumeControl = VolumeControl(view: view) { [weak self] _ in
+            guard let enabled = self?.cameraButton.isEnabled, enabled else {
+                return
+            }
+            self?.capturePhoto()
+        }
+    }
+    
+    /**
+     * Configure the action for every button on this
+     * layout.
+     */
+    private func setupActions() {
+        cameraButton.action = { [weak self] in self?.capturePhoto() }
+        swapButton.action = { [weak self] in self?.swapCamera() }
+        libraryButton.action = { [weak self] in self?.showLibrary() }
+        closeButton.action = { [weak self] in self?.close() }
+        flashButton.action = { [weak self] in self?.toggleFlash() }
+    }
+    
+    /**
+     * Toggle the buttons status, based on the actual
+     * state of the camera.
+     */
+    private func toggleButtons(enabled: Bool) {
+        [cameraButton,
+            closeButton,
+            swapButton,
+            libraryButton].forEach({ $0.isEnabled = enabled })
+    }
+    
+    @objc func rotateCameraView() {
+        cameraView.rotatePreview()
+    }
+    
+    /**
+     * This method will rotate the buttons based on
+     * the last and actual orientation of the device.
+     */
+    internal func rotate(actualInterfaceOrientation: UIInterfaceOrientation) {
+        
+        if lastInterfaceOrientation != nil {
+            let lastTransform = CGAffineTransform(rotationAngle: radians(currentRotation(
+                lastInterfaceOrientation!, newOrientation: actualInterfaceOrientation)))
+            setTransform(transform: lastTransform)
+        }
+
+        let transform = CGAffineTransform(rotationAngle: 0)
+        animationRunning = true
+        
+        /**
+         * Dispatch delay to avoid any conflict between the CATransaction of rotation of the screen
+         * and CATransaction of animation of buttons.
+         */
+
+        let duration = animationDuration
+        let spring = animationSpring
+        let options = rotateAnimation
+
+        let time: DispatchTime = DispatchTime.now() + Double(1 * UInt64(NSEC_PER_SEC)/10)
+        DispatchQueue.main.asyncAfter(deadline: time) { [weak self] in
+
+            guard let _ = self else {
+                return
+            }
+            
+            CATransaction.begin()
+            CATransaction.setDisableActions(false)
+            CATransaction.commit()
+            
+            UIView.animate(
+                withDuration: duration,
+                delay: 0.1,
+                usingSpringWithDamping: spring,
+                initialSpringVelocity: 0,
+                options: options,
+                animations: { [weak self] in
+                self?.setTransform(transform: transform)
+                }, completion: { [weak self] _ in
+                    self?.animationRunning = false
+            })
+            
+        }
+    }
+    
+    func setTransform(transform: CGAffineTransform) {
+        closeButton.transform = transform
+        swapButton.transform = transform
+        libraryButton.transform = transform
+        flashButton.transform = transform
+    }
+    
+    /**
+     * Validate the permissions of the camera and
+     * library, if the user do not accept these
+     * permissions, it shows an view that notifies
+     * the user that it not allow the permissions.
+     */
+    private func checkPermissions() {
+        if AVCaptureDevice.authorizationStatus(for: AVMediaType.video) != .authorized {
+            AVCaptureDevice.requestAccess(for: AVMediaType.video) { granted in
+                DispatchQueue.main.async() { [weak self] in
+                    if !granted {
+                        self?.showNoPermissionsView()
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Generate the view of no permission.
+     */
+    private func showNoPermissionsView(library: Bool = false) {
+        let permissionsView = PermissionsView(frame: view.bounds)
+        let title: String
+        let desc: String
+        
+        if library {
+            title = localizedString("permissions.library.title")
+            desc = localizedString("permissions.library.description")
+        } else {
+            title = localizedString("permissions.title")
+            desc = localizedString("permissions.description")
+        }
+        
+        permissionsView.configureInView(view, title: title, description: desc, completion: { [weak self] in self?.close() })
+    }
+    
+    /**
+     * This method will be called when the user
+     * try to take the picture.
+     * It will lock any button while the shot is
+     * taken, then, realease the buttons and save
+     * the picture on the device.
+     */
+    internal func capturePhoto() {
+        guard let output = cameraView.imageOutput,
+            let connection = output.connection(with: AVMediaType.video) else {
+            return
+        }
+        
+        if connection.isEnabled {
+            toggleButtons(enabled: false)
+            cameraView.capturePhoto { [weak self] image in
+                guard let image = image else {
+                    self?.toggleButtons(enabled: true)
+                    return
+                }
+                self?.saveImage(image: image)
+            }
+        }
+    }
+    
+    internal func saveImage(image: UIImage) {
+        let spinner = showSpinner()
+        cameraView.preview.isHidden = true
+
+		if allowsLibraryAccess {
+        _ = SingleImageSaver()
+            .setImage(image)
+            .onSuccess { [weak self] asset in
+                self?.layoutCameraResult(asset: asset)
+                self?.hideSpinner(spinner)
+            }
+            .onFailure { [weak self] error in
+                self?.toggleButtons(enabled: true)
+                self?.showNoPermissionsView(library: true)
+                self?.cameraView.preview.isHidden = false
+                self?.hideSpinner(spinner)
+            }
+            .save()
+		} else {
+			layoutCameraResult(uiImage: image)
+			hideSpinner(spinner)
+		}
+    }
+	
+    internal func close() {
+        onCompletion?(nil, nil)
+        onCompletion = nil
+    }
+    
+    internal func showLibrary() {
+        let imagePicker = CameraViewController.imagePickerViewController(croppingParameters: croppingParameters) { [weak self] image, asset in
+            defer {
+                self?.dismiss(animated: true, completion: nil)
+            }
+
+            guard let image = image, let asset = asset else {
+                return
+            }
+
+            self?.onCompletion?(image, asset)
+        }
+        
+        present(imagePicker, animated: true) { [weak self] in
+            self?.cameraView.stopSession()
+        }
+    }
+    
+    internal func toggleFlash() {
+        cameraView.cycleFlash()
+        
+        guard let device = cameraView.device else {
+            return
+        }
+  
+        let image = UIImage(named: flashImage(device.flashMode),
+                            in: CameraGlobals.shared.bundle,
+                            compatibleWith: nil)
+        
+        flashButton.setImage(image, for: .normal)
+    }
+    
+    internal func swapCamera() {
+        cameraView.swapCameraInput()
+        flashButton.isHidden = cameraView.currentPosition == AVCaptureDevice.Position.front
+    }
+	
+	internal func layoutCameraResult(uiImage: UIImage) {
+		cameraView.stopSession()
+		startConfirmController(uiImage: uiImage)
+		toggleButtons(enabled: true)
+	}
+	
+    internal func layoutCameraResult(asset: PHAsset) {
+        cameraView.stopSession()
+        startConfirmController(asset: asset)
+        toggleButtons(enabled: true)
+    }
+	
+	private func startConfirmController(uiImage: UIImage) {
+		let confirmViewController = ConfirmViewController(image: uiImage, croppingParameters: croppingParameters)
+		confirmViewController.onComplete = { [weak self] image, asset in
+			defer {
+				self?.dismiss(animated: true, completion: nil)
+			}
+			
+			guard let image = image else {
+				return
+			}
+			
+			self?.onCompletion?(image, asset)
+			self?.onCompletion = nil
+		}
+		confirmViewController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
+		present(confirmViewController, animated: true, completion: nil)
+	}
+	
+    private func startConfirmController(asset: PHAsset) {
+        let confirmViewController = ConfirmViewController(asset: asset, croppingParameters: croppingParameters)
+        confirmViewController.onComplete = { [weak self] image, asset in
+            defer {
+                self?.dismiss(animated: true, completion: nil)
+            }
+
+            guard let image = image, let asset = asset else {
+                return
+            }
+
+            self?.onCompletion?(image, asset)
+            self?.onCompletion = nil
+        }
+        confirmViewController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
+        present(confirmViewController, animated: true, completion: nil)
+    }
+
+    private func showSpinner() -> UIActivityIndicatorView {
+        let spinner = UIActivityIndicatorView()
+        spinner.style = .white
+        spinner.center = view.center
+        spinner.startAnimating()
+        
+        view.addSubview(spinner)
+        view.bringSubviewToFront(spinner)
+        
+        return spinner
+    }
+    
+    private func hideSpinner(_ spinner: UIActivityIndicatorView) {
+        spinner.stopAnimating()
+        spinner.removeFromSuperview()
+    }
+    
+}

+ 528 - 0
Pods/ALCameraViewController/ALCameraViewController/ViewController/CameraViewControllerConstraint.swift

@@ -0,0 +1,528 @@
+//
+//  CameraViewControllerConstraint.swift
+//  CameraViewControllerConstraint
+//
+//  Created by Pedro Paulo de Amorim.
+//  Copyright (c) 2016 zero. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+
+/**
+ * This extension provides the configuration of
+ * constraints for CameraViewController.
+ */
+extension CameraViewController {
+    
+    /**
+     * To attach the view to the edges of the superview, it needs
+     to be pinned on the sides of the self.view, based on the
+     edges of this superview.
+     * This configure the cameraView to show, in real time, the
+     * camera.
+     */
+    func configCameraViewConstraints() {
+        [.left, .right, .top, .bottom].forEach({
+            view.addConstraint(NSLayoutConstraint(
+                item: cameraView,
+                attribute: $0,
+                relatedBy: .equal,
+                toItem: view,
+                attribute: $0,
+                multiplier: 1.0,
+                constant: 0))
+        })
+    }
+    
+    /**
+     * Add the constraints based on the device orientation,
+     * this pin the button on the bottom part of the screen
+     * when the device is portrait, when landscape, pin
+     * the button on the right part of the screen.
+     */
+    func configCameraButtonEdgeConstraint(_ statusBarOrientation: UIInterfaceOrientation) {
+        view.autoRemoveConstraint(cameraButtonEdgeConstraint)
+        
+        let attribute : NSLayoutConstraint.Attribute = {
+            switch statusBarOrientation {
+            case .portrait: return .bottomMargin
+            case .landscapeRight: return .rightMargin
+            case .landscapeLeft: return .leftMargin
+            default: return .topMargin
+            }
+        }()
+        
+        cameraButtonEdgeConstraint = NSLayoutConstraint(
+            item: cameraButton,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: -8)
+        view.addConstraint(cameraButtonEdgeConstraint!)
+    }
+    
+    /**
+     * Add the constraints based on the device orientation,
+     * centerX the button based on the width of screen.
+     * When the device is landscape orientation, centerY
+     * the button based on the height of screen.
+     */
+    func configCameraButtonGravityConstraint(_ portrait: Bool) {
+        view.autoRemoveConstraint(cameraButtonGravityConstraint)
+        let attribute : NSLayoutConstraint.Attribute = portrait ? .centerX : .centerY
+        cameraButtonGravityConstraint = NSLayoutConstraint(
+            item: cameraButton,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(cameraButtonGravityConstraint!)
+    }
+    
+    /**
+     * Remove the constraints of container.
+     */
+    func removeContainerConstraints() {
+        view.autoRemoveConstraint(containerButtonsEdgeOneConstraint)
+        view.autoRemoveConstraint(containerButtonsEdgeTwoConstraint)
+        view.autoRemoveConstraint(containerButtonsGravityConstraint)
+    }
+    
+    /**
+     * Configure the edges constraints of container that 
+     * handle the center position of SwapButton and
+     * LibraryButton.
+     */
+    func configContainerEdgeConstraint(_ statusBarOrientation : UIInterfaceOrientation) {
+        
+        let attributeOne : NSLayoutConstraint.Attribute
+        let attributeTwo : NSLayoutConstraint.Attribute
+        
+        switch statusBarOrientation {
+        case .portrait:
+            attributeOne = .left
+            attributeTwo = .right
+            break
+        case .landscapeRight:
+            attributeOne = .bottom
+            attributeTwo = .top
+            break
+        case .landscapeLeft:
+            attributeOne = .top
+            attributeTwo = .bottom
+            break
+        default:
+            attributeOne = .right
+            attributeTwo = .left
+            break
+        }
+        
+        containerButtonsEdgeOneConstraint = NSLayoutConstraint(
+            item: containerSwapLibraryButton,
+            attribute: attributeOne,
+            relatedBy: .equal,
+            toItem: cameraButton,
+            attribute: attributeTwo,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(containerButtonsEdgeOneConstraint!)
+        
+        containerButtonsEdgeTwoConstraint = NSLayoutConstraint(
+            item: containerSwapLibraryButton,
+            attribute: attributeTwo,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attributeTwo,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(containerButtonsEdgeTwoConstraint!)
+
+    }
+    
+    /**
+     * Configure the gravity of container, based on the
+     * orientation of the device.
+     */
+    func configContainerGravityConstraint(_ statusBarOrientation : UIInterfaceOrientation) {
+        let attributeCenter : NSLayoutConstraint.Attribute = statusBarOrientation.isPortrait ? .centerY : .centerX
+        containerButtonsGravityConstraint = NSLayoutConstraint(
+            item: containerSwapLibraryButton,
+            attribute: attributeCenter,
+            relatedBy: .equal,
+            toItem: cameraButton,
+            attribute: attributeCenter,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(containerButtonsGravityConstraint!)
+    }
+    
+    /**
+     * Remove the SwapButton constraints to be updated when
+     * the device was rotated.
+     */
+    func removeSwapButtonConstraints() {
+        view.autoRemoveConstraint(swapButtonEdgeOneConstraint)
+        view.autoRemoveConstraint(swapButtonEdgeTwoConstraint)
+        view.autoRemoveConstraint(swapButtonGravityConstraint)
+    }
+    
+    /**
+     * If the device is portrait, pin the SwapButton on the
+     * right side of the CameraButton.
+     * If landscape, pin the SwapButton on the top of the
+     * CameraButton.
+     */
+    func configSwapButtonEdgeConstraint(_ statusBarOrientation : UIInterfaceOrientation) {
+        
+        let attributeOne : NSLayoutConstraint.Attribute
+        let attributeTwo : NSLayoutConstraint.Attribute
+
+        switch statusBarOrientation {
+        case .portrait:
+            attributeOne = .top
+            attributeTwo = .bottom
+            break
+        case .landscapeRight:
+            attributeOne = .left
+            attributeTwo = .right
+            break
+        case .landscapeLeft:
+            attributeOne = .right
+            attributeTwo = .left
+            break
+        default:
+            attributeOne = .bottom
+            attributeTwo = .top
+            break
+        }
+        
+        swapButtonEdgeOneConstraint = NSLayoutConstraint(
+            item: swapButton,
+            attribute: attributeOne,
+            relatedBy: .equal,
+            toItem: containerSwapLibraryButton,
+            attribute: attributeOne,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(swapButtonEdgeOneConstraint!)
+        
+        swapButtonEdgeTwoConstraint = NSLayoutConstraint(
+            item: swapButton,
+            attribute: attributeTwo,
+            relatedBy: .equal,
+            toItem: containerSwapLibraryButton,
+            attribute: attributeTwo,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(swapButtonEdgeTwoConstraint!)
+        
+    }
+    
+    /**
+     * Configure the center of SwapButton, based on the
+     * axis center of CameraButton.
+     */
+    func configSwapButtonGravityConstraint(_ portrait: Bool) {
+        swapButtonGravityConstraint = NSLayoutConstraint(
+            item: swapButton,
+            attribute: portrait ? .right : .bottom,
+            relatedBy: .lessThanOrEqual,
+            toItem: containerSwapLibraryButton,
+            attribute: portrait ? .centerX : .centerY,
+            multiplier: 1.0,
+            constant: -4.0 * DeviceConfig.SCREEN_MULTIPLIER)
+        view.addConstraint(swapButtonGravityConstraint!)
+    }
+    
+    func removeCloseButtonConstraints() {
+        view.autoRemoveConstraint(closeButtonEdgeConstraint)
+        view.autoRemoveConstraint(closeButtonGravityConstraint)
+    }
+    
+    /**
+     * Pin the close button to the left of the superview.
+     */
+    func configCloseButtonEdgeConstraint(_ statusBarOrientation : UIInterfaceOrientation) {
+        
+        let attribute : NSLayoutConstraint.Attribute = {
+            switch statusBarOrientation {
+            case .portrait: return .left
+            case .landscapeRight, .landscapeLeft: return .centerX
+            default: return .right
+            }
+        }()
+
+        closeButtonEdgeConstraint = NSLayoutConstraint(
+            item: closeButton,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: attribute != .centerX ? view : cameraButton,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: attribute != .centerX ? 16 : 0)
+        view.addConstraint(closeButtonEdgeConstraint!)
+    }
+    
+    /**
+     * Add the constraint for the CloseButton, based on
+     * the device orientation.
+     * If portrait, it pin the CloseButton on the CenterY
+     * of the CameraButton.
+     * Else if landscape, pin this button on the Bottom
+     * of superview.
+     */
+    func configCloseButtonGravityConstraint(_ statusBarOrientation : UIInterfaceOrientation) {
+        
+        let attribute : NSLayoutConstraint.Attribute
+        let constant : CGFloat
+        
+        switch statusBarOrientation {
+        case .portrait:
+            attribute = .centerY
+            constant = 0.0
+            break
+        case .landscapeRight:
+            attribute = .bottom
+            constant = -16.0
+            break
+        case .landscapeLeft:
+            attribute = .top
+            constant = 16.0
+            break
+        default:
+            attribute = .centerX
+            constant = 0.0
+            break
+        }
+        
+        closeButtonGravityConstraint = NSLayoutConstraint(
+            item: closeButton,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: attribute == .bottom || attribute == .top ? view : cameraButton,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: constant)
+        
+        view.addConstraint(closeButtonGravityConstraint!)
+    }
+    
+    /**
+     * Remove the LibraryButton constraints to be updated when
+     * the device was rotated.
+     */
+    func removeLibraryButtonConstraints() {
+        view.autoRemoveConstraint(libraryButtonEdgeOneConstraint)
+        view.autoRemoveConstraint(libraryButtonEdgeTwoConstraint)
+        view.autoRemoveConstraint(libraryButtonGravityConstraint)
+    }
+    
+    /**
+     * Add the constraint of the LibraryButton, if the device
+     * orientation is portrait, pin the right side of SwapButton
+     * to the left side of LibraryButton.
+     * If landscape, pin the bottom side of CameraButton on the
+     * top side of LibraryButton.
+     */
+    func configLibraryEdgeButtonConstraint(_ statusBarOrientation : UIInterfaceOrientation) {
+
+        let attributeOne : NSLayoutConstraint.Attribute
+        let attributeTwo : NSLayoutConstraint.Attribute
+        
+        switch statusBarOrientation {
+        case .portrait:
+            attributeOne = .top
+            attributeTwo = .bottom
+            break
+        case .landscapeRight:
+            attributeOne = .left
+            attributeTwo = .right
+            break
+        case .landscapeLeft:
+            attributeOne = .right
+            attributeTwo = .left
+            break
+        default:
+            attributeOne = .bottom
+            attributeTwo = .top
+            break
+        }
+        
+        libraryButtonEdgeOneConstraint = NSLayoutConstraint(
+            item: libraryButton,
+            attribute: attributeOne,
+            relatedBy: .equal,
+            toItem: containerSwapLibraryButton,
+            attribute: attributeOne,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(libraryButtonEdgeOneConstraint!)
+        
+        libraryButtonEdgeTwoConstraint = NSLayoutConstraint(
+            item: libraryButton,
+            attribute: attributeTwo,
+            relatedBy: .equal,
+            toItem: containerSwapLibraryButton,
+            attribute: attributeTwo,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(libraryButtonEdgeTwoConstraint!)
+        
+    }
+    
+    /**
+     * Set the center gravity of the LibraryButton based
+     * on the position of CameraButton.
+     */
+    func configLibraryGravityButtonConstraint(_ portrait: Bool) {
+        libraryButtonGravityConstraint = NSLayoutConstraint(
+            item: libraryButton,
+            attribute: portrait ? .left : .top,
+            relatedBy: .lessThanOrEqual,
+            toItem: containerSwapLibraryButton,
+            attribute: portrait ? .centerX : .centerY,
+            multiplier: 1.0,
+            constant: 4.0 * DeviceConfig.SCREEN_MULTIPLIER)
+        view.addConstraint(libraryButtonGravityConstraint!)
+    }
+    
+    /**
+     * If the device orientation is portrait, pin the top of
+     * FlashButton to the top side of superview.
+     * Else if, pin the FlashButton bottom side on the top side
+     * of SwapButton.
+     */
+    func configFlashEdgeButtonConstraint(_ statusBarOrientation: UIInterfaceOrientation) {
+        view.autoRemoveConstraint(flashButtonEdgeConstraint)
+        
+        let constraintRight = statusBarOrientation == .portrait || statusBarOrientation == .landscapeRight
+        let attribute : NSLayoutConstraint.Attribute = constraintRight ? .topMargin : .bottomMargin
+        
+        flashButtonEdgeConstraint = NSLayoutConstraint(
+            item: flashButton,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: constraintRight ? 8 : -8)
+        view.addConstraint(flashButtonEdgeConstraint!)
+    }
+    
+    /**
+     * If the device orientation is portrait, pin the
+     right side of FlashButton to the right side of
+     * superview.
+     * Else if, centerX the FlashButton on the CenterX
+     * of CameraButton.
+     */
+    func configFlashGravityButtonConstraint(_ statusBarOrientation: UIInterfaceOrientation) {
+        view.autoRemoveConstraint(flashButtonGravityConstraint)
+        
+        let constraintRight = statusBarOrientation == .portrait || statusBarOrientation == .landscapeLeft
+        let attribute : NSLayoutConstraint.Attribute = constraintRight ? .right : .left
+        
+        flashButtonGravityConstraint = NSLayoutConstraint(
+            item: flashButton,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: constraintRight ? -8 : 8)
+        view.addConstraint(flashButtonGravityConstraint!)
+    }
+    
+    /**
+     * Used to create a perfect square for CameraOverlay.
+     * This method will determinate the size of CameraOverlay,
+     * if portrait, it will use the width of superview to
+     * determinate the height of the view. Else if landscape,
+     * it uses the height of the superview to create the width
+     * of the CameraOverlay.
+     */
+    func configCameraOverlayWidthConstraint(_ portrait: Bool) {
+        view.autoRemoveConstraint(cameraOverlayWidthConstraint)
+        cameraOverlayWidthConstraint = NSLayoutConstraint(
+            item: cameraOverlay,
+            attribute: portrait ? .height : .width,
+            relatedBy: .equal,
+            toItem: cameraOverlay,
+            attribute: portrait ? .width : .height,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(cameraOverlayWidthConstraint!)
+    }
+    
+    /**
+     * This method will center the relative position of
+     * CameraOverlay, based on the biggest size of the
+     * superview.
+     */
+    func configCameraOverlayCenterConstraint(_ portrait: Bool) {
+        view.autoRemoveConstraint(cameraOverlayCenterConstraint)
+        let attribute : NSLayoutConstraint.Attribute = portrait ? .centerY : .centerX
+        cameraOverlayCenterConstraint = NSLayoutConstraint(
+            item: cameraOverlay,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: 0)
+        view.addConstraint(cameraOverlayCenterConstraint!)
+    }
+    
+    /**
+     * Remove the CameraOverlay constraints to be updated when
+     * the device was rotated.
+     */
+    func removeCameraOverlayEdgesConstraints() {
+        view.autoRemoveConstraint(cameraOverlayEdgeOneConstraint)
+        view.autoRemoveConstraint(cameraOverlayEdgeTwoConstraint)
+    }
+    
+    /**
+     * It needs to get a determined smallest size of the screen
+     to create the smallest size to be used on CameraOverlay.
+     It uses the orientation of the screen to determinate where
+     the view will be pinned.
+     */
+    func configCameraOverlayEdgeOneContraint(_ portrait: Bool, padding: CGFloat) {
+        let attribute : NSLayoutConstraint.Attribute = portrait ? .left : .bottom
+        cameraOverlayEdgeOneConstraint = NSLayoutConstraint(
+            item: cameraOverlay,
+            attribute: attribute,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attribute,
+            multiplier: 1.0,
+            constant: padding)
+        view.addConstraint(cameraOverlayEdgeOneConstraint!)
+    }
+    
+    /**
+     * It needs to get a determined smallest size of the screen
+     to create the smallest size to be used on CameraOverlay.
+     It uses the orientation of the screen to determinate where
+     the view will be pinned.
+     */
+    func configCameraOverlayEdgeTwoConstraint(_ portrait: Bool, padding: CGFloat) {
+        let attributeTwo : NSLayoutConstraint.Attribute = portrait ? .right : .top
+        cameraOverlayEdgeTwoConstraint = NSLayoutConstraint(
+            item: cameraOverlay,
+            attribute: attributeTwo,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: attributeTwo,
+            multiplier: 1.0,
+            constant: -padding)
+        view.addConstraint(cameraOverlayEdgeTwoConstraint!)
+    }
+    
+}

+ 365 - 0
Pods/ALCameraViewController/ALCameraViewController/ViewController/ConfirmViewController.swift

@@ -0,0 +1,365 @@
+//
+//  ALConfirmViewController.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2015/06/30.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+public class ConfirmViewController: UIViewController, UIScrollViewDelegate {
+	
+	let imageView = UIImageView()
+	@IBOutlet weak var scrollView: UIScrollView!
+	@IBOutlet weak var cropOverlay: CropOverlay!
+	@IBOutlet weak var cancelButton: UIButton!
+	@IBOutlet weak var confirmButton: UIButton!
+	@IBOutlet weak var centeringView: UIView!
+	
+    var croppingParameters: CroppingParameters {
+        didSet {
+            cropOverlay.isResizable = croppingParameters.allowResizing
+            cropOverlay.minimumSize = croppingParameters.minimumSize
+        }
+    }
+
+	var verticalPadding: CGFloat = 30
+	var horizontalPadding: CGFloat = 30
+	
+	public var onComplete: CameraViewCompletion?
+
+	let asset: PHAsset?
+	let image: UIImage?
+	
+	public init(image: UIImage, croppingParameters: CroppingParameters) {
+		self.croppingParameters = croppingParameters
+		self.asset = nil
+		self.image = image
+		super.init(nibName: "ConfirmViewController", bundle: CameraGlobals.shared.bundle)
+	}
+	
+	public init(asset: PHAsset, croppingParameters: CroppingParameters) {
+		self.croppingParameters = croppingParameters
+		self.asset = asset
+		self.image = nil
+		super.init(nibName: "ConfirmViewController", bundle: CameraGlobals.shared.bundle)
+	}
+	
+    public required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+	}
+	
+	public override var prefersStatusBarHidden: Bool {
+		return true
+	}
+	
+	public override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
+		return UIStatusBarAnimation.slide
+	}
+	
+	public override func viewDidLoad() {
+		super.viewDidLoad()
+
+		view.backgroundColor = UIColor.black
+		
+		scrollView.addSubview(imageView)
+		scrollView.delegate = self
+		scrollView.maximumZoomScale = 1
+		
+        cropOverlay.isHidden = true
+        cropOverlay.isResizable = croppingParameters.allowResizing
+        cropOverlay.isMovable = croppingParameters.allowMoving
+        cropOverlay.minimumSize = croppingParameters.minimumSize
+
+		let spinner = showSpinner()
+		
+		disable()
+		
+		if let asset = asset {
+			_ = SingleImageFetcher()
+				.setAsset(asset)
+				.setTargetSize(largestPhotoSize())
+				.onSuccess { [weak self] image in
+					self?.configureWithImage(image)
+					self?.hideSpinner(spinner)
+					self?.enable()
+				}
+				.onFailure { [weak self] error in
+					self?.hideSpinner(spinner)
+				}
+				.fetch()
+		} else if let image = image {
+			configureWithImage(image)
+			hideSpinner(spinner)
+			enable()
+		}
+	}
+	
+	public override func viewWillLayoutSubviews() {
+		super.viewWillLayoutSubviews()
+		let scale = calculateMinimumScale(view.frame.size)
+		let frame = croppingParameters.isEnabled ? cropOverlay.frame : view.bounds
+		
+		scrollView.contentInset = calculateScrollViewInsets(frame)
+		scrollView.minimumZoomScale = scale
+		scrollView.zoomScale = scale
+		centerScrollViewContents()
+	}
+	
+	public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
+		super.viewWillTransition(to: size, with: coordinator)
+		
+		let scale = calculateMinimumScale(size)
+		var frame = view.bounds
+		
+		if croppingParameters.isEnabled {
+			frame = cropOverlay.frame
+			let centeringFrame = centeringView.frame
+			var origin: CGPoint
+			
+			if size.width > size.height { // landscape
+				let offset = (size.width - centeringFrame.height)
+				let expectedX = (centeringFrame.height/2 - frame.height/2) + offset
+				origin = CGPoint(x: expectedX, y: frame.origin.x)
+			} else {
+				let expectedY = (centeringFrame.width/2 - frame.width/2)
+				origin = CGPoint(x: frame.origin.y, y: expectedY)
+			}
+			
+			frame.origin = origin
+		} else {
+			frame.size = size
+		}
+		
+		let insets = calculateScrollViewInsets(frame)
+		
+		coordinator.animate(alongsideTransition: { [weak self] context in
+			self?.scrollView.contentInset = insets
+			self?.scrollView.minimumZoomScale = scale
+			self?.scrollView.zoomScale = scale
+			self?.centerScrollViewContents()
+			self?.centerImageViewOnRotate()
+			}, completion: nil)
+	}
+	
+	private func configureWithImage(_ image: UIImage) {
+		cropOverlay.isHidden = !croppingParameters.isEnabled
+		
+		buttonActions()
+		
+		imageView.image = image
+		imageView.sizeToFit()
+		view.setNeedsLayout()
+	}
+	
+	private func calculateMinimumScale(_ size: CGSize) -> CGFloat {
+		var _size = size
+		
+		if croppingParameters.isEnabled {
+			_size = cropOverlay.frame.size
+		}
+		
+		guard let image = imageView.image else {
+            return 1
+		}
+		
+		let scaleWidth = _size.width / image.size.width
+		let scaleHeight = _size.height / image.size.height
+
+		return min(scaleWidth, scaleHeight)
+	}
+	
+	private func calculateScrollViewInsets(_ frame: CGRect) -> UIEdgeInsets {
+		let bottom = view.frame.height - (frame.origin.y + frame.height)
+		let right = view.frame.width - (frame.origin.x + frame.width)
+		let insets = UIEdgeInsets(top: frame.origin.y, left: frame.origin.x, bottom: bottom, right: right)
+		return insets
+	}
+	
+	private func centerImageViewOnRotate() {
+		if croppingParameters.isEnabled {
+			let size = cropOverlay.frame.size
+			let scrollInsets = scrollView.contentInset
+			let imageSize = imageView.frame.size
+			var contentOffset = CGPoint(x: -scrollInsets.left, y: -scrollInsets.top)
+			contentOffset.x -= (size.width - imageSize.width) / 2
+			contentOffset.y -= (size.height - imageSize.height) / 2
+			scrollView.contentOffset = contentOffset
+		}
+	}
+	
+	private func centerScrollViewContents() {
+		let size = croppingParameters.isEnabled ? cropOverlay.frame.size : scrollView.frame.size
+		let imageSize = imageView.frame.size
+		var imageOrigin = CGPoint.zero
+		
+		if imageSize.width < size.width {
+			imageOrigin.x = (size.width - imageSize.width) / 2
+		}
+		
+		if imageSize.height < size.height {
+			imageOrigin.y = (size.height - imageSize.height) / 2
+		}
+		
+		imageView.frame.origin = imageOrigin
+	}
+	
+	private func buttonActions() {
+		confirmButton.action = { [weak self] in self?.confirmPhoto() }
+		cancelButton.action = { [weak self] in self?.cancel() }
+	}
+	
+	internal func cancel() {
+		onComplete?(nil, nil)
+	}
+	
+	internal func confirmPhoto() {
+		
+		guard let image = imageView.image else {
+			return
+		}
+		
+		disable()
+		
+		imageView.isHidden = true
+		
+		let spinner = showSpinner()
+		
+		if let asset = asset {
+			var fetcher = SingleImageFetcher()
+				.onSuccess { [weak self] image in
+					self?.onComplete?(image, self?.asset)
+					self?.hideSpinner(spinner)
+					self?.enable()
+				}
+				.onFailure { [weak self] error in
+					self?.hideSpinner(spinner)
+					self?.showNoImageScreen(error)
+				}
+				.setAsset(asset)
+			if croppingParameters.isEnabled {
+				let rect = normalizedRect(makeProportionalCropRect(), orientation: image.imageOrientation)
+				fetcher = fetcher.setCropRect(rect)
+			}
+			
+			fetcher = fetcher.fetch()
+		} else {
+			var newImage = image
+			
+			if croppingParameters.isEnabled {
+				let cropRect = makeProportionalCropRect()
+				let resizedCropRect = CGRect(x: (image.size.width) * cropRect.origin.x,
+				                     y: (image.size.height) * cropRect.origin.y,
+				                     width: (image.size.width * cropRect.width),
+				                     height: (image.size.height * cropRect.height))
+				newImage = image.crop(rect: resizedCropRect)
+			}
+			
+			onComplete?(newImage, nil)
+			hideSpinner(spinner)
+			enable()
+		}
+	}
+	
+	public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
+		return imageView
+	}
+	
+	public func scrollViewDidZoom(_ scrollView: UIScrollView) {
+		centerScrollViewContents()
+	}
+	
+	func showSpinner() -> UIActivityIndicatorView {
+		let spinner = UIActivityIndicatorView()
+        spinner.style = .white
+		spinner.center = view.center
+		spinner.startAnimating()
+		
+		view.addSubview(spinner)
+        view.bringSubviewToFront(spinner)
+		
+		return spinner
+	}
+	
+	func hideSpinner(_ spinner: UIActivityIndicatorView) {
+		spinner.stopAnimating()
+		spinner.removeFromSuperview()
+	}
+	
+	func disable() {
+		confirmButton.isEnabled = false
+	}
+	
+	func enable() {
+		confirmButton.isEnabled = true
+	}
+	
+	func showNoImageScreen(_ error: NSError) {
+		let permissionsView = PermissionsView(frame: view.bounds)
+		
+		let desc = localizedString("error.cant-fetch-photo.description")
+		
+		permissionsView.configureInView(view, title: error.localizedDescription, description: desc, completion: { [weak self] in self?.cancel() })
+	}
+	
+	private func makeProportionalCropRect() -> CGRect {
+		var cropRect = CGRect(x: cropOverlay.frame.origin.x + cropOverlay.outterGap,
+		                      y: cropOverlay.frame.origin.y + cropOverlay.outterGap,
+		                      width: cropOverlay.frame.size.width - 2 * cropOverlay.outterGap,
+		                      height: cropOverlay.frame.size.height - 2 * cropOverlay.outterGap)
+        cropRect.origin.x += scrollView.contentOffset.x - imageView.frame.origin.x
+        cropRect.origin.y += scrollView.contentOffset.y - imageView.frame.origin.y
+
+		let normalizedX = max(0, cropRect.origin.x / imageView.frame.width)
+		let normalizedY = max(0, cropRect.origin.y / imageView.frame.height)
+
+        let extraWidth = min(0, cropRect.origin.x)
+        let extraHeight = min(0, cropRect.origin.y)
+
+		let normalizedWidth = min(1, (cropRect.width + extraWidth) / imageView.frame.width)
+		let normalizedHeight = min(1, (cropRect.height + extraHeight) / imageView.frame.height)
+		
+		return CGRect(x: normalizedX, y: normalizedY, width: normalizedWidth, height: normalizedHeight)
+	}
+	
+}
+
+extension UIImage {
+	func crop(rect: CGRect) -> UIImage {
+
+		var rectTransform: CGAffineTransform
+		switch imageOrientation {
+		case .left:
+			rectTransform = CGAffineTransform(rotationAngle: radians(90)).translatedBy(x: 0, y: -size.height)
+		case .right:
+			rectTransform = CGAffineTransform(rotationAngle: radians(-90)).translatedBy(x: -size.width, y: 0)
+		case .down:
+			rectTransform = CGAffineTransform(rotationAngle: radians(-180)).translatedBy(x: -size.width, y: -size.height)
+		default:
+			rectTransform = CGAffineTransform.identity
+		}
+		
+		rectTransform = rectTransform.scaledBy(x: scale, y: scale)
+		
+		if let cropped = cgImage?.cropping(to: rect.applying(rectTransform)) {
+			return UIImage(cgImage: cropped, scale: scale, orientation: imageOrientation).fixOrientation()
+		}
+		
+		return self
+	}
+	
+	func fixOrientation() -> UIImage {
+		if imageOrientation == .up {
+			return self
+		}
+		
+		UIGraphicsBeginImageContextWithOptions(size, false, scale)
+		draw(in: CGRect(origin: .zero, size: size))
+		let normalizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() ?? self
+		UIGraphicsEndImageContext()
+		
+		return normalizedImage
+	}
+}

+ 210 - 0
Pods/ALCameraViewController/ALCameraViewController/ViewController/ConfirmViewController.xib

@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina4_0" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
+        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ConfirmViewController" customModule="ALCameraViewController" customModuleProvider="target">
+            <connections>
+                <outlet property="cancelButton" destination="yRi-ES-LfN" id="PUm-mc-H7R"/>
+                <outlet property="centeringView" destination="KYd-D9-K5d" id="CmX-BA-VtZ"/>
+                <outlet property="confirmButton" destination="ASf-ZD-cIs" id="mpH-Eg-IbA"/>
+                <outlet property="cropOverlay" destination="lnA-tb-Sap" id="34E-zk-Axd"/>
+                <outlet property="scrollView" destination="oUR-U3-uEM" id="rF0-ZM-RmA"/>
+                <outlet property="view" destination="iN0-l3-epB" id="FcS-Dy-kqF"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oUR-U3-uEM">
+                    <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+                </scrollView>
+                <view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KYd-D9-K5d">
+                    <rect key="frame" x="0.0" y="0.0" width="320" height="474"/>
+                    <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lnA-tb-Sap" customClass="CropOverlay" customModule="ALCameraViewController" customModuleProvider="target">
+                    <rect key="frame" x="15" y="92" width="290" height="290"/>
+                    <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="width" secondItem="lnA-tb-Sap" secondAttribute="height" multiplier="1:1" id="lv8-l9-lJq"/>
+                    </constraints>
+                </view>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ASf-ZD-cIs">
+                    <rect key="frame" x="74" y="474" width="64" height="64"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="64" id="J7n-mn-Ebe"/>
+                        <constraint firstAttribute="width" constant="64" id="YWt-e6-Bvy"/>
+                    </constraints>
+                    <state key="normal" image="confirmButton"/>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yRi-ES-LfN">
+                    <rect key="frame" x="198" y="474" width="64" height="64"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="64" id="FdJ-mW-Tx6"/>
+                        <constraint firstAttribute="width" constant="64" id="urS-JS-i1S"/>
+                    </constraints>
+                    <state key="normal" image="retakeButton"/>
+                </button>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="centerY" secondItem="KYd-D9-K5d" secondAttribute="centerY" id="1uu-Bd-bz3"/>
+                <constraint firstAttribute="trailing" secondItem="oUR-U3-uEM" secondAttribute="trailing" id="7A6-HH-MEu"/>
+                <constraint firstAttribute="bottom" secondItem="yRi-ES-LfN" secondAttribute="bottom" constant="30" id="7jo-lC-34t"/>
+                <constraint firstItem="ASf-ZD-cIs" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" constant="-45" id="89L-rE-rmd"/>
+                <constraint firstAttribute="bottom" secondItem="oUR-U3-uEM" secondAttribute="bottom" id="8mU-82-Hf6"/>
+                <constraint firstItem="oUR-U3-uEM" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="92s-g3-wfK"/>
+                <constraint firstItem="KYd-D9-K5d" firstAttribute="leading" secondItem="yRi-ES-LfN" secondAttribute="trailing" id="CcA-mG-BLU"/>
+                <constraint firstItem="yRi-ES-LfN" firstAttribute="top" secondItem="KYd-D9-K5d" secondAttribute="bottom" id="Ck2-xk-HbG"/>
+                <constraint firstItem="oUR-U3-uEM" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Cuy-cw-jOk"/>
+                <constraint firstAttribute="bottom" secondItem="ASf-ZD-cIs" secondAttribute="bottom" constant="30" id="DZ5-WA-3ZQ"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="top" relation="greaterThanOrEqual" secondItem="oUR-U3-uEM" secondAttribute="top" constant="100" id="GAL-ck-d0B"/>
+                <constraint firstAttribute="bottom" secondItem="yRi-ES-LfN" secondAttribute="bottom" constant="60" id="H4a-3r-r5r"/>
+                <constraint firstItem="oUR-U3-uEM" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="J3N-Vr-euu"/>
+                <constraint firstAttribute="trailing" secondItem="KYd-D9-K5d" secondAttribute="trailing" id="JLk-PT-5kn"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="15" id="P5N-Xh-C1z"/>
+                <constraint firstItem="ASf-ZD-cIs" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="30" id="Rwi-4K-QRb"/>
+                <constraint firstItem="ASf-ZD-cIs" firstAttribute="bottom" secondItem="yRi-ES-LfN" secondAttribute="top" constant="-60" id="TLl-L0-yLb"/>
+                <constraint firstItem="ASf-ZD-cIs" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" constant="-54" id="WSF-pa-4wb"/>
+                <constraint firstAttribute="trailing" secondItem="KYd-D9-K5d" secondAttribute="trailing" id="YBv-2a-KdQ"/>
+                <constraint firstItem="KYd-D9-K5d" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Yhb-Y3-ngX"/>
+                <constraint firstItem="KYd-D9-K5d" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="aj9-Xh-WHL"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="leading" secondItem="oUR-U3-uEM" secondAttribute="leading" priority="999" constant="100" id="bRR-fN-fEb"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="centerY" secondItem="KYd-D9-K5d" secondAttribute="centerY" id="dbm-T2-OgB"/>
+                <constraint firstAttribute="bottom" secondItem="lnA-tb-Sap" secondAttribute="bottom" constant="15" id="eMF-sY-QhQ"/>
+                <constraint firstAttribute="trailing" secondItem="lnA-tb-Sap" secondAttribute="trailing" constant="15" id="efC-ff-52c"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="centerX" secondItem="KYd-D9-K5d" secondAttribute="centerX" id="fPc-8D-E0O"/>
+                <constraint firstItem="KYd-D9-K5d" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="hPp-8q-A1p"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="centerX" secondItem="KYd-D9-K5d" secondAttribute="centerX" id="hpa-Qn-uzT"/>
+                <constraint firstItem="ASf-ZD-cIs" firstAttribute="top" secondItem="KYd-D9-K5d" secondAttribute="bottom" id="iar-0y-gBe"/>
+                <constraint firstAttribute="bottom" secondItem="oUR-U3-uEM" secondAttribute="bottom" id="iw9-Cg-Kkk"/>
+                <constraint firstItem="oUR-U3-uEM" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="kDN-mM-6KE"/>
+                <constraint firstItem="yRi-ES-LfN" firstAttribute="leading" secondItem="ASf-ZD-cIs" secondAttribute="trailing" constant="60" id="m1F-XR-hgU"/>
+                <constraint firstAttribute="trailing" secondItem="oUR-U3-uEM" secondAttribute="trailing" id="mL3-PM-TEd"/>
+                <constraint firstAttribute="bottom" secondItem="KYd-D9-K5d" secondAttribute="bottom" id="o6j-Qo-hB5"/>
+                <constraint firstItem="lnA-tb-Sap" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="15" id="ohf-4f-yKs"/>
+                <constraint firstItem="ASf-ZD-cIs" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" constant="-54" id="pNU-uB-Igt"/>
+                <constraint firstItem="yRi-ES-LfN" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="30" id="v0q-tU-ywG"/>
+                <constraint firstItem="KYd-D9-K5d" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="vnU-ey-3GX"/>
+                <constraint firstAttribute="trailing" secondItem="KYd-D9-K5d" secondAttribute="trailing" id="wTn-DN-uQO"/>
+                <constraint firstItem="KYd-D9-K5d" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="wn3-We-BBK"/>
+                <constraint firstItem="yRi-ES-LfN" firstAttribute="top" secondItem="ASf-ZD-cIs" secondAttribute="top" id="xFS-1L-oa4"/>
+                <constraint firstItem="yRi-ES-LfN" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" constant="45" id="xFc-F1-V7I"/>
+            </constraints>
+            <variation key="default">
+                <mask key="constraints">
+                    <exclude reference="CcA-mG-BLU"/>
+                    <exclude reference="JLk-PT-5kn"/>
+                    <exclude reference="YBv-2a-KdQ"/>
+                    <exclude reference="Yhb-Y3-ngX"/>
+                    <exclude reference="aj9-Xh-WHL"/>
+                    <exclude reference="hPp-8q-A1p"/>
+                    <exclude reference="o6j-Qo-hB5"/>
+                    <exclude reference="vnU-ey-3GX"/>
+                    <exclude reference="wTn-DN-uQO"/>
+                    <exclude reference="wn3-We-BBK"/>
+                    <exclude reference="1uu-Bd-bz3"/>
+                    <exclude reference="GAL-ck-d0B"/>
+                    <exclude reference="P5N-Xh-C1z"/>
+                    <exclude reference="bRR-fN-fEb"/>
+                    <exclude reference="dbm-T2-OgB"/>
+                    <exclude reference="eMF-sY-QhQ"/>
+                    <exclude reference="efC-ff-52c"/>
+                    <exclude reference="fPc-8D-E0O"/>
+                    <exclude reference="hpa-Qn-uzT"/>
+                    <exclude reference="ohf-4f-yKs"/>
+                    <exclude reference="7A6-HH-MEu"/>
+                    <exclude reference="8mU-82-Hf6"/>
+                    <exclude reference="92s-g3-wfK"/>
+                    <exclude reference="Cuy-cw-jOk"/>
+                    <exclude reference="89L-rE-rmd"/>
+                    <exclude reference="DZ5-WA-3ZQ"/>
+                    <exclude reference="Rwi-4K-QRb"/>
+                    <exclude reference="TLl-L0-yLb"/>
+                    <exclude reference="WSF-pa-4wb"/>
+                    <exclude reference="iar-0y-gBe"/>
+                    <exclude reference="pNU-uB-Igt"/>
+                    <exclude reference="7jo-lC-34t"/>
+                    <exclude reference="Ck2-xk-HbG"/>
+                    <exclude reference="H4a-3r-r5r"/>
+                    <exclude reference="m1F-XR-hgU"/>
+                    <exclude reference="v0q-tU-ywG"/>
+                    <exclude reference="xFS-1L-oa4"/>
+                    <exclude reference="xFc-F1-V7I"/>
+                </mask>
+            </variation>
+            <variation key="heightClass=compact">
+                <mask key="subviews">
+                    <include reference="KYd-D9-K5d"/>
+                    <include reference="lnA-tb-Sap"/>
+                </mask>
+                <mask key="constraints">
+                    <include reference="CcA-mG-BLU"/>
+                    <include reference="Yhb-Y3-ngX"/>
+                    <include reference="o6j-Qo-hB5"/>
+                    <include reference="wTn-DN-uQO"/>
+                    <include reference="P5N-Xh-C1z"/>
+                    <include reference="eMF-sY-QhQ"/>
+                    <include reference="hpa-Qn-uzT"/>
+                    <include reference="Rwi-4K-QRb"/>
+                    <include reference="TLl-L0-yLb"/>
+                    <include reference="pNU-uB-Igt"/>
+                    <include reference="v0q-tU-ywG"/>
+                </mask>
+            </variation>
+            <variation key="heightClass=regular-widthClass=compact">
+                <mask key="subviews">
+                    <include reference="KYd-D9-K5d"/>
+                    <include reference="lnA-tb-Sap"/>
+                </mask>
+                <mask key="constraints">
+                    <include reference="JLk-PT-5kn"/>
+                    <include reference="aj9-Xh-WHL"/>
+                    <include reference="wn3-We-BBK"/>
+                    <include reference="1uu-Bd-bz3"/>
+                    <include reference="efC-ff-52c"/>
+                    <include reference="ohf-4f-yKs"/>
+                    <include reference="DZ5-WA-3ZQ"/>
+                    <include reference="WSF-pa-4wb"/>
+                    <include reference="7jo-lC-34t"/>
+                    <include reference="Ck2-xk-HbG"/>
+                    <include reference="m1F-XR-hgU"/>
+                </mask>
+            </variation>
+            <variation key="heightClass=regular-widthClass=regular">
+                <mask key="constraints">
+                    <include reference="YBv-2a-KdQ"/>
+                    <include reference="hPp-8q-A1p"/>
+                    <include reference="vnU-ey-3GX"/>
+                    <include reference="GAL-ck-d0B"/>
+                    <include reference="bRR-fN-fEb"/>
+                    <include reference="dbm-T2-OgB"/>
+                    <include reference="fPc-8D-E0O"/>
+                    <include reference="7A6-HH-MEu"/>
+                    <include reference="8mU-82-Hf6"/>
+                    <include reference="92s-g3-wfK"/>
+                    <include reference="Cuy-cw-jOk"/>
+                    <include reference="89L-rE-rmd"/>
+                    <include reference="iar-0y-gBe"/>
+                    <include reference="H4a-3r-r5r"/>
+                    <include reference="xFS-1L-oa4"/>
+                    <include reference="xFc-F1-V7I"/>
+                </mask>
+            </variation>
+        </view>
+    </objects>
+    <resources>
+        <image name="confirmButton" width="44" height="44"/>
+        <image name="retakeButton" width="44" height="44"/>
+    </resources>
+</document>

+ 127 - 0
Pods/ALCameraViewController/ALCameraViewController/ViewController/PhotoLibraryViewController.swift

@@ -0,0 +1,127 @@
+//
+//  ALImagePickerViewController.swift
+//  ALImagePickerViewController
+//
+//  Created by Alex Littlejohn on 2015/06/09.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+internal let ImageCellIdentifier = "ImageCell"
+
+internal let defaultItemSpacing: CGFloat = 1
+
+public typealias PhotoLibraryViewSelectionComplete = (PHAsset?) -> Void
+
+public class PhotoLibraryViewController: UIViewController {
+    
+    internal var assets: PHFetchResult<PHAsset>? = nil
+    
+    public var onSelectionComplete: PhotoLibraryViewSelectionComplete?
+    
+    private lazy var collectionView: UICollectionView = {
+        let layout = UICollectionViewFlowLayout()
+        
+        layout.itemSize = CameraGlobals.shared.photoLibraryThumbnailSize
+        layout.minimumInteritemSpacing = defaultItemSpacing
+        layout.minimumLineSpacing = defaultItemSpacing
+        layout.sectionInset = UIEdgeInsets.zero
+      
+        let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
+        collectionView.translatesAutoresizingMaskIntoConstraints = false
+        collectionView.backgroundColor = UIColor.clear
+        return collectionView
+    }()
+    
+    public override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        setNeedsStatusBarAppearanceUpdate()
+        
+        let buttonImage = UIImage(named: "libraryCancel", in: CameraGlobals.shared.bundle, compatibleWith: nil)?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
+        
+        navigationItem.leftBarButtonItem = UIBarButtonItem(image: buttonImage,
+                                                           style: UIBarButtonItem.Style.plain,
+                                                           target: self,
+                                                           action: #selector(dismissLibrary))
+        
+        view.backgroundColor = UIColor(white: 0.2, alpha: 1)
+        view.addSubview(collectionView)
+        
+        _ = ImageFetcher()
+            .onFailure(onFailure)
+            .onSuccess(onSuccess)
+            .fetch()
+    }
+    
+    public override func viewWillLayoutSubviews() {
+        super.viewWillLayoutSubviews()
+        collectionView.frame = view.bounds
+    }
+    
+    public override var preferredStatusBarStyle: UIStatusBarStyle {
+        return UIStatusBarStyle.lightContent
+    }
+    
+    public func present(_ inViewController: UIViewController, animated: Bool) {
+        let navigationController = UINavigationController(rootViewController: self)
+        navigationController.navigationBar.barTintColor = UIColor.black
+        navigationController.navigationBar.barStyle = UIBarStyle.black
+        inViewController.present(navigationController, animated: animated, completion: nil)
+    }
+    
+    @objc public func dismissLibrary() {
+        onSelectionComplete?(nil)
+    }
+    
+    private func onSuccess(_ photos: PHFetchResult<PHAsset>) {
+        assets = photos
+        configureCollectionView()
+    }
+    
+    private func onFailure(_ error: NSError) {
+        let permissionsView = PermissionsView(frame: view.bounds)
+        permissionsView.titleLabel.text = localizedString("permissions.library.title")
+        permissionsView.descriptionLabel.text = localizedString("permissions.library.description")
+        
+        view.addSubview(permissionsView)
+    }
+    
+    private func configureCollectionView() {
+        collectionView.register(ImageCell.self, forCellWithReuseIdentifier: ImageCellIdentifier)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+    }
+    
+    internal func itemAtIndexPath(_ indexPath: IndexPath) -> PHAsset? {
+        return assets?[(indexPath as NSIndexPath).row]
+    }
+}
+
+// MARK: - UICollectionViewDataSource -
+extension PhotoLibraryViewController : UICollectionViewDataSource {
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return assets?.count ?? 0
+    }
+
+    @objc(collectionView:willDisplayCell:forItemAtIndexPath:) public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
+        if cell is ImageCell {
+            if let model = itemAtIndexPath(indexPath) {
+                (cell as! ImageCell).configureWithModel(model)
+            }
+        }
+    }
+
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        return collectionView.dequeueReusableCell(withReuseIdentifier: ImageCellIdentifier, for: indexPath)
+    }
+}
+
+// MARK: - UICollectionViewDelegate -
+extension PhotoLibraryViewController : UICollectionViewDelegateFlowLayout {
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        onSelectionComplete?(itemAtIndexPath(indexPath))
+    }
+}

+ 299 - 0
Pods/ALCameraViewController/ALCameraViewController/Views/CameraView.swift

@@ -0,0 +1,299 @@
+//
+//  CameraView.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2015/06/17.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+
+public class CameraView: UIView {
+    
+    var session: AVCaptureSession!
+    var input: AVCaptureDeviceInput!
+    var device: AVCaptureDevice!
+    var imageOutput: AVCaptureStillImageOutput!
+    var preview: AVCaptureVideoPreviewLayer!
+    
+    let cameraQueue = DispatchQueue(label: "com.zero.ALCameraViewController.Queue")
+    
+    let focusView = CropOverlay(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
+    
+    public var currentPosition = CameraGlobals.shared.defaultCameraPosition
+    
+    public func startSession() {
+        session = AVCaptureSession()
+        session.sessionPreset = AVCaptureSession.Preset.photo
+
+        device = cameraWithPosition(position: currentPosition)
+        if let device = device , device.hasFlash {
+            do {
+                try device.lockForConfiguration()
+                device.flashMode = .auto
+                device.unlockForConfiguration()
+            } catch _ {}
+        }
+
+        let outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
+
+        do {
+            input = try AVCaptureDeviceInput(device: device)
+        } catch let error as NSError {
+            input = nil
+            print("Error: \(error.localizedDescription)")
+            return
+        }
+
+        if session.canAddInput(input) {
+            session.addInput(input)
+        }
+
+        imageOutput = AVCaptureStillImageOutput()
+        imageOutput.outputSettings = outputSettings
+
+        session.addOutput(imageOutput)
+
+        cameraQueue.sync {
+            session.startRunning()
+            DispatchQueue.main.async() { [weak self] in
+                self?.createPreview()
+                self?.rotatePreview()
+            }
+        }
+    }
+    
+    public func stopSession() {
+        cameraQueue.sync {
+            session?.stopRunning()
+            preview?.removeFromSuperlayer()
+            
+            session = nil
+            input = nil
+            imageOutput = nil
+            preview = nil
+            device = nil
+        }
+    }
+    
+    public override func layoutSubviews() {
+        super.layoutSubviews()
+        preview?.frame = bounds
+    }
+    
+    public func configureFocus() {
+        
+        if let gestureRecognizers = gestureRecognizers {
+            gestureRecognizers.forEach({ removeGestureRecognizer($0) })
+        }
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(focus(gesture:)))
+        addGestureRecognizer(tapGesture)
+        isUserInteractionEnabled = true
+        addSubview(focusView)
+        
+        focusView.isHidden = true
+        
+        let lines = focusView.horizontalLines + focusView.verticalLines + focusView.outerLines
+        
+        lines.forEach { line in
+            line.alpha = 0
+        }
+    }
+
+    public func configureZoom() {
+        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinch(gesture:)))
+        addGestureRecognizer(pinchGesture)
+    }
+    
+    @objc internal func focus(gesture: UITapGestureRecognizer) {
+        let point = gesture.location(in: self)
+        
+        guard focusCamera(toPoint: point) else {
+            return
+        }
+        
+        focusView.isHidden = false
+        focusView.center = point
+        focusView.alpha = 0
+        focusView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
+        
+        bringSubviewToFront(focusView)
+        
+        UIView.animateKeyframes(withDuration: 1.5, delay: 0, options: UIView.KeyframeAnimationOptions(), animations: {
+            
+            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.15, animations: { [weak self] in
+                self?.focusView.alpha = 1
+                self?.focusView.transform = CGAffineTransform.identity
+            })
+            
+            UIView.addKeyframe(withRelativeStartTime: 0.80, relativeDuration: 0.20, animations: { [weak self] in
+                self?.focusView.alpha = 0
+                self?.focusView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
+            })
+            
+            
+            }, completion: { [weak self] finished in
+                if finished {
+                    self?.focusView.isHidden = true
+                }
+        })
+    }
+
+    @objc internal func pinch(gesture: UIPinchGestureRecognizer) {
+        guard let device = device else { return }
+
+        // Return zoom value between the minimum and maximum zoom values
+        func minMaxZoom(_ factor: CGFloat) -> CGFloat {
+            return min(max(factor, 1.0), device.activeFormat.videoMaxZoomFactor)
+        }
+
+        func update(scale factor: CGFloat) {
+            do {
+                try device.lockForConfiguration()
+                defer { device.unlockForConfiguration() }
+                device.videoZoomFactor = factor
+            } catch {
+                print("\(error.localizedDescription)")
+            }
+        }
+
+        let velocity = gesture.velocity
+        let velocityFactor: CGFloat = 8.0
+        let desiredZoomFactor = device.videoZoomFactor + atan2(velocity, velocityFactor)
+
+        let newScaleFactor = minMaxZoom(desiredZoomFactor)
+        switch gesture.state {
+        case .began, .changed:
+            update(scale: newScaleFactor)
+        case _:
+            break
+        }
+    }
+    
+    private func createPreview() {
+        
+        preview = AVCaptureVideoPreviewLayer(session: session)
+        preview.videoGravity = AVLayerVideoGravity.resizeAspectFill
+        preview.frame = bounds
+
+        layer.addSublayer(preview)
+    }
+    
+    private func cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
+        let devices = AVCaptureDevice.devices(for: AVMediaType.video)
+        return devices.filter { $0.position == position }.first
+    }
+    
+    public func capturePhoto(completion: @escaping CameraShotCompletion) {
+        isUserInteractionEnabled = false
+
+        guard let output = imageOutput, let orientation = AVCaptureVideoOrientation(rawValue: UIDevice.current.orientation.rawValue) else {
+            completion(nil)
+            return
+        }
+
+        let size = frame.size
+
+        cameraQueue.sync {
+            takePhoto(output, videoOrientation: orientation, cameraPosition: device.position, cropSize: size) { image in
+                DispatchQueue.main.async() { [weak self] in
+                    self?.isUserInteractionEnabled = true
+                    completion(image)
+                }
+            }
+        }
+    }
+    
+    public func focusCamera(toPoint: CGPoint) -> Bool {
+        
+        guard let device = device, let preview = preview, device.isFocusModeSupported(.continuousAutoFocus) else {
+            return false
+        }
+        
+        do { try device.lockForConfiguration() } catch {
+            return false
+        }
+        
+        let focusPoint = preview.captureDevicePointConverted(fromLayerPoint: toPoint)
+
+        device.focusPointOfInterest = focusPoint
+        device.focusMode = .continuousAutoFocus
+
+        device.exposurePointOfInterest = focusPoint
+        device.exposureMode = .continuousAutoExposure
+
+        device.unlockForConfiguration()
+        
+        return true
+    }
+    
+    public func cycleFlash() {
+        guard let device = device, device.hasFlash else {
+            return
+        }
+        
+        do {
+            try device.lockForConfiguration()
+            if device.flashMode == .on {
+                device.flashMode = .off
+            } else if device.flashMode == .off {
+                device.flashMode = .auto
+            } else {
+                device.flashMode = .on
+            }
+            device.unlockForConfiguration()
+        } catch _ { }
+    }
+
+    public func swapCameraInput() {
+        
+        guard let session = session, let currentInput = input else {
+            return
+        }
+        
+        session.beginConfiguration()
+        session.removeInput(currentInput)
+        
+        if currentInput.device.position == AVCaptureDevice.Position.back {
+            currentPosition = AVCaptureDevice.Position.front
+            device = cameraWithPosition(position: currentPosition)
+        } else {
+            currentPosition = AVCaptureDevice.Position.back
+            device = cameraWithPosition(position: currentPosition)
+        }
+        
+        guard let newInput = try? AVCaptureDeviceInput(device: device) else {
+            return
+        }
+        
+        input = newInput
+        
+        session.addInput(newInput)
+        session.commitConfiguration()
+    }
+  
+    public func rotatePreview() {
+      
+        guard preview != nil else {
+            return
+        }
+        switch UIApplication.shared.statusBarOrientation {
+            case .portrait:
+              preview?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
+              break
+            case .portraitUpsideDown:
+              preview?.connection?.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
+              break
+            case .landscapeRight:
+              preview?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
+              break
+            case .landscapeLeft:
+              preview?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
+              break
+            default: break
+        }
+    }
+    
+}

+ 215 - 0
Pods/ALCameraViewController/ALCameraViewController/Views/CropOverlay.swift

@@ -0,0 +1,215 @@
+//
+//  CropOverlay.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2015/06/30.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+
+internal class CropOverlay: UIView {
+
+    var outerLines = [UIView]()
+    var horizontalLines = [UIView]()
+    var verticalLines = [UIView]()
+    
+    var topLeftCornerLines = [UIView]()
+    var topRightCornerLines = [UIView]()
+    var bottomLeftCornerLines = [UIView]()
+    var bottomRightCornerLines = [UIView]()
+
+    var cornerButtons = [UIButton]()
+
+    let cornerLineDepth: CGFloat = 3
+    let cornerLineWidth: CGFloat = 22.5
+    var cornerButtonWidth: CGFloat {
+        return self.cornerLineWidth * 2
+    }
+
+    let lineWidth: CGFloat = 1
+
+    let outterGapRatio: CGFloat = 1/3
+    var outterGap: CGFloat {
+        return self.cornerButtonWidth * self.outterGapRatio
+    }
+
+    var isResizable: Bool = false
+    var isMovable: Bool = false
+    var minimumSize: CGSize = CGSize.zero
+
+    internal override init(frame: CGRect) {
+        super.init(frame: frame)
+        createLines()
+    }
+
+    internal required init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+        createLines()
+    }
+    
+    override func layoutSubviews() {
+        
+        for i in 0..<outerLines.count {
+            let line = outerLines[i]
+            var lineFrame: CGRect
+            switch (i) {
+            case 0:
+                lineFrame = CGRect(x: outterGap, y: outterGap, width: bounds.width - outterGap * 2, height: lineWidth)
+                break
+            case 1:
+                lineFrame = CGRect(x: bounds.width - lineWidth - outterGap, y: outterGap, width: lineWidth, height: bounds.height - outterGap * 2)
+                break
+            case 2:
+                lineFrame = CGRect(x: outterGap, y: bounds.height - lineWidth - outterGap, width: bounds.width - outterGap * 2, height: lineWidth)
+                break
+            case 3:
+                lineFrame = CGRect(x: outterGap, y: outterGap, width: lineWidth, height: bounds.height - outterGap * 2)
+                break
+            default:
+                lineFrame = CGRect.zero
+                break
+            }
+            
+            line.frame = lineFrame
+        }
+        
+        let corners = [topLeftCornerLines, topRightCornerLines, bottomLeftCornerLines, bottomRightCornerLines]
+        for i in 0..<corners.count {
+            let corner = corners[i]
+			
+			var horizontalFrame: CGRect
+			var verticalFrame: CGRect
+			var buttonFrame: CGRect
+			let buttonSize = CGSize(width: cornerButtonWidth, height: cornerButtonWidth)
+			
+            switch (i) {
+			case 0:	// Top Left
+				verticalFrame = CGRect(x: outterGap, y: outterGap, width: cornerLineDepth, height: cornerLineWidth)
+				horizontalFrame = CGRect(x: outterGap, y: outterGap, width: cornerLineWidth, height: cornerLineDepth)
+				buttonFrame = CGRect(origin: CGPoint(x: 0, y: 0), size: buttonSize)
+			case 1:	// Top Right
+				verticalFrame = CGRect(x: bounds.width - cornerLineDepth - outterGap, y: outterGap, width: cornerLineDepth, height: cornerLineWidth)
+				horizontalFrame = CGRect(x: bounds.width - cornerLineWidth - outterGap, y: outterGap, width: cornerLineWidth, height: cornerLineDepth)
+				buttonFrame = CGRect(origin: CGPoint(x: bounds.width - cornerButtonWidth, y: 0), size: buttonSize)
+			case 2:	// Bottom Left
+				verticalFrame = CGRect(x: outterGap, y:  bounds.height - cornerLineWidth - outterGap, width: cornerLineDepth, height: cornerLineWidth)
+				horizontalFrame = CGRect(x: outterGap, y:  bounds.height - cornerLineDepth - outterGap, width: cornerLineWidth, height: cornerLineDepth)
+				buttonFrame = CGRect(origin: CGPoint(x: 0, y: bounds.height - cornerButtonWidth), size: buttonSize)
+			case 3:	// Bottom Right
+				verticalFrame = CGRect(x: bounds.width - cornerLineDepth - outterGap, y: bounds.height - cornerLineWidth - outterGap, width: cornerLineDepth, height: cornerLineWidth)
+				horizontalFrame = CGRect(x: bounds.width - cornerLineWidth - outterGap, y: bounds.height - cornerLineDepth - outterGap, width: cornerLineWidth, height: cornerLineDepth)
+				buttonFrame = CGRect(origin: CGPoint(x: bounds.width - cornerButtonWidth, y: bounds.height - cornerButtonWidth), size: buttonSize)
+
+            default:
+                verticalFrame = CGRect.zero
+                horizontalFrame = CGRect.zero
+				buttonFrame = CGRect.zero
+            }
+			
+            corner[0].frame = verticalFrame
+            corner[1].frame = horizontalFrame
+			cornerButtons[i].frame = buttonFrame
+        }
+		
+		let lineThickness = lineWidth / UIScreen.main.scale
+		let vPadding = (bounds.height - outterGap * 2 - (lineThickness * CGFloat(horizontalLines.count))) / CGFloat(horizontalLines.count + 1)
+		let hPadding = (bounds.width - outterGap * 2 - (lineThickness * CGFloat(verticalLines.count))) / CGFloat(verticalLines.count + 1)
+		
+        for i in 0..<horizontalLines.count {
+            let hLine = horizontalLines[i]
+            let vLine = verticalLines[i]
+			
+			let vSpacing = (vPadding * CGFloat(i + 1)) + (lineThickness * CGFloat(i))
+			let hSpacing = (hPadding * CGFloat(i + 1)) + (lineThickness * CGFloat(i))
+			
+			hLine.frame = CGRect(x: outterGap, y: vSpacing + outterGap, width: bounds.width - outterGap * 2, height:  lineThickness)
+			vLine.frame = CGRect(x: hSpacing + outterGap, y: outterGap, width: lineThickness, height: bounds.height - outterGap * 2)
+        }
+		
+    }
+	
+    func createLines() {
+        
+        outerLines = [createLine(), createLine(), createLine(), createLine()]
+        horizontalLines = [createLine(), createLine()]
+        verticalLines = [createLine(), createLine()]
+        
+        topLeftCornerLines = [createLine(), createLine()]
+        topRightCornerLines = [createLine(), createLine()]
+        bottomLeftCornerLines = [createLine(), createLine()]
+        bottomRightCornerLines = [createLine(), createLine()]
+        
+		cornerButtons = [createButton(), createButton(), createButton(), createButton()]
+		
+		let dragGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(moveCropOverlay))
+		addGestureRecognizer(dragGestureRecognizer)
+    }
+    
+    func createLine() -> UIView {
+        let line = UIView()
+        line.backgroundColor = UIColor.white
+        addSubview(line)
+        return line
+    }
+	
+	func createButton() -> UIButton {
+		let button = UIButton()
+		button.backgroundColor = UIColor.clear
+		
+		let dragGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(moveCropOverlay))
+		button.addGestureRecognizer(dragGestureRecognizer)
+
+		addSubview(button)
+		return button
+	}
+	
+	@objc func moveCropOverlay(gestureRecognizer: UIPanGestureRecognizer) {
+		if isResizable, let button = gestureRecognizer.view as? UIButton {
+			if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
+				let translation = gestureRecognizer.translation(in: self)
+				
+				var newFrame: CGRect
+				
+				switch button {
+				case cornerButtons[0]:	// Top Left
+                    newFrame = CGRect(x: frame.origin.x + translation.x, y: frame.origin.y + translation.y, width: frame.size.width - translation.x, height: frame.size.height - translation.y)
+				case cornerButtons[1]:	// Top Right
+					newFrame = CGRect(x: frame.origin.x, y: frame.origin.y + translation.y, width: frame.size.width + translation.x, height: frame.size.height - translation.y)
+				case cornerButtons[2]:	// Bottom Left
+					newFrame = CGRect(x: frame.origin.x + translation.x, y: frame.origin.y, width: frame.size.width - translation.x, height: frame.size.height + translation.y)
+				case cornerButtons[3]:	// Bottom Right
+					newFrame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width + translation.x, height: frame.size.height + translation.y)
+				default:
+					newFrame = CGRect.zero
+				}
+
+                let minimumFrame = CGRect(x: newFrame.origin.x, y: newFrame.origin.y, width: max(newFrame.size.width, minimumSize.width + 2 * outterGap), height: max(newFrame.size.height, minimumSize.height + 2 * outterGap))
+				frame = minimumFrame
+				layoutSubviews()
+
+				gestureRecognizer.setTranslation(CGPoint.zero, in: self)
+			}
+		} else if isMovable {
+			if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
+				let translation = gestureRecognizer.translation(in: self)
+				
+				gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
+				gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self)
+			}
+		}
+	}
+
+    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
+        let view = super.hitTest(point, with: event)
+
+        if !isMovable && isResizable && view != nil {
+            let isButton = cornerButtons.reduce(false) { $1.hitTest(convert(point, to: $1), with: event) != nil || $0 }
+            if !isButton {
+                return nil
+            }
+        }
+
+        return view
+    }
+}

+ 55 - 0
Pods/ALCameraViewController/ALCameraViewController/Views/ImageCell.swift

@@ -0,0 +1,55 @@
+//
+//  ImageCell.swift
+//  ALImagePickerViewController
+//
+//  Created by Alex Littlejohn on 2015/06/09.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+import Photos
+
+class ImageCell: UICollectionViewCell {
+    
+    let imageView : UIImageView = {
+        let imageView = UIImageView()
+        imageView.contentMode = .scaleAspectFill
+        imageView.layer.masksToBounds = true
+        imageView.image = UIImage(named: "placeholder",
+                                  in: CameraGlobals.shared.bundle,
+                                  compatibleWith: nil)
+        return imageView
+    }()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.addSubview(imageView)
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+    }
+    
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        imageView.frame = bounds
+    }
+    
+    override func prepareForReuse() {
+        super.prepareForReuse()
+        imageView.image = UIImage(named: "placeholder",
+                                  in: CameraGlobals.shared.bundle,
+                                  compatibleWith: nil)
+    }
+    
+    func configureWithModel(_ model: PHAsset) {
+        
+        if tag != 0 {
+            PHImageManager.default().cancelImageRequest(PHImageRequestID(tag))
+        }
+        
+        tag = Int(PHImageManager.default().requestImage(for: model, targetSize: contentView.bounds.size, contentMode: .aspectFill, options: nil) { image, info in
+            self.imageView.image = image
+        })
+    }
+}

+ 123 - 0
Pods/ALCameraViewController/ALCameraViewController/Views/PermissionsView.swift

@@ -0,0 +1,123 @@
+//
+//  PermissionsView.swift
+//  ALCameraViewController
+//
+//  Created by Alex Littlejohn on 2015/06/24.
+//  Copyright (c) 2015 zero. All rights reserved.
+//
+
+import UIKit
+
+internal class PermissionsView: UIView {
+   
+    let iconView = UIImageView()
+    let titleLabel = UILabel()
+    let descriptionLabel = UILabel()
+    let settingsButton = UIButton()
+    
+    let horizontalPadding: CGFloat = 50
+    let verticalPadding: CGFloat = 50
+    let verticalSpacing: CGFloat = 10
+    
+    required init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+        commonInit()
+    }
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        commonInit()
+    }
+    
+    func configureInView(_ view: UIView, title: String, description: String, completion: @escaping ButtonAction) {
+        let closeButton = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
+        
+        view.addSubview(self)
+        addSubview(closeButton)
+        
+        titleLabel.text = title
+        descriptionLabel.text = description
+        
+        closeButton.action = completion
+        closeButton.setImage(UIImage(named: "retakeButton", in: CameraGlobals.shared.bundle, compatibleWith: nil), for: UIControl.State())
+        closeButton.sizeToFit()
+        
+        let size = view.frame.size
+        let closeSize = closeButton.frame.size
+        let closeX = horizontalPadding
+        let closeY = size.height - (closeSize.height + verticalPadding)
+        
+        closeButton.frame.origin = CGPoint(x: closeX, y: closeY)
+    }
+    
+    func commonInit() {
+        
+        backgroundColor = UIColor(white: 0.2, alpha: 1)
+        
+        titleLabel.textColor = UIColor.white
+        titleLabel.numberOfLines = 0
+        titleLabel.textAlignment = NSTextAlignment.center
+        titleLabel.font = UIFont(name: "AppleSDGothicNeo-Light", size: 22)
+        titleLabel.text = localizedString("permissions.title")
+        
+        descriptionLabel.textColor = UIColor.lightGray
+        descriptionLabel.numberOfLines = 0
+        descriptionLabel.textAlignment = NSTextAlignment.center
+        descriptionLabel.font = UIFont(name: "AppleSDGothicNeo-Regular", size: 16)
+        descriptionLabel.text = localizedString("permissions.description")
+        
+        let icon = UIImage(named: "permissionsIcon", in: CameraGlobals.shared.bundle, compatibleWith: nil)!
+        iconView.image = icon
+        
+        settingsButton.contentEdgeInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12)
+        settingsButton.setTitle(localizedString("permissions.settings"), for: UIControl.State())
+        settingsButton.setTitleColor(UIColor.white, for: UIControl.State())
+        settingsButton.layer.cornerRadius = 4
+        settingsButton.titleLabel?.font = UIFont(name: "AppleSDGothicNeo-Regular", size: 14)
+        settingsButton.backgroundColor = UIColor(red: 52.0/255.0, green: 183.0/255.0, blue: 250.0/255.0, alpha: 1)
+        settingsButton.addTarget(self, action: #selector(PermissionsView.openSettings), for: UIControl.Event.touchUpInside)
+        
+        addSubview(iconView)
+        addSubview(titleLabel)
+        addSubview(descriptionLabel)
+        addSubview(settingsButton)
+    }
+    
+    @objc func openSettings() {
+        if let appSettings = URL(string: UIApplication.openSettingsURLString) {
+            UIApplication.shared.openURL(appSettings)
+        }
+    }
+    
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        
+        let maxLabelWidth = frame.width - horizontalPadding * 2
+        
+        let iconSize = iconView.image!.size
+        let constrainedTextSize = CGSize(width: maxLabelWidth, height: CGFloat.greatestFiniteMagnitude)
+        let titleSize = titleLabel.sizeThatFits(constrainedTextSize)
+        let descriptionSize = descriptionLabel.sizeThatFits(constrainedTextSize)
+        let settingsSize = settingsButton.sizeThatFits(constrainedTextSize)
+        
+        let iconX = frame.width/2 - iconSize.width/2
+        let iconY: CGFloat = frame.height/2 - (iconSize.height + verticalSpacing + verticalSpacing + titleSize.height + verticalSpacing + descriptionSize.height)/2;
+        
+        iconView.frame = CGRect(x: iconX, y: iconY, width: iconSize.width, height: iconSize.height)
+        
+        let titleX = frame.width/2 - titleSize.width/2
+        let titleY = iconY + iconSize.height + verticalSpacing + verticalSpacing
+        
+        titleLabel.frame = CGRect(x: titleX, y: titleY, width: titleSize.width, height: titleSize.height)
+        
+        let descriptionX = frame.width/2 - descriptionSize.width/2
+        let descriptionY = titleY + titleSize.height + verticalSpacing
+        
+        descriptionLabel.frame = CGRect(x: descriptionX, y: descriptionY, width: descriptionSize.width, height: descriptionSize.height)
+        
+        let settingsX = frame.width/2 - settingsSize.width/2
+        let settingsY = descriptionY + descriptionSize.height + verticalSpacing
+        
+        settingsButton.frame = CGRect(x: settingsX, y: settingsY, width: settingsSize.width, height: settingsSize.height)
+    }
+}

+ 22 - 0
Pods/ALCameraViewController/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Alex Littlejohn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+

+ 149 - 0
Pods/ALCameraViewController/README.md

@@ -0,0 +1,149 @@
+# ALCameraViewController
+A camera view controller with custom image picker and image cropping.
+
+![camera](https://cloud.githubusercontent.com/assets/932822/8455694/c61de812-2006-11e5-85c0-a57e3d980561.jpg)
+![cropper](https://cloud.githubusercontent.com/assets/932822/8455697/c627ac44-2006-11e5-82be-7f96e73d9b1f.jpg)
+![library](https://cloud.githubusercontent.com/assets/932822/8455695/c620ebb6-2006-11e5-9c61-75a81870c9de.jpg)
+![permissions](https://cloud.githubusercontent.com/assets/932822/8455696/c62157fe-2006-11e5-958f-849cabf541ca.jpg)
+
+### Features
+
+- [x] Front facing and rear facing camera
+- [x] Simple and clean look
+- [x] Custom image picker with permission checking
+- [x] Image cropping
+- [x] Flash light
+- [x] Zoom
+- [x] Tap to focus
+
+### Installation & Requirements
+This project requires Xcode 9 to run and compiles with swift 4
+> Note: This library makes use of the AVFoundation camera API's which are unavailable on the iOS simulator. You'll need a real device to run it.
+
+CocoaPods:
+Add the following to your Podfile:
+
+```ruby
+pod 'ALCameraViewController'
+```
+> For swift 3.2 support
+
+```ruby
+pod 'ALCameraViewController', '~> 2.0.3'
+```
+
+Carthage:
+
+```ruby
+github "alexlittlejohn/ALCameraViewController"
+```
+
+
+### Privacy (iOS 10) ###
+If you are building your app with iOS 10 or newer, you need to add two privacy keys to your app to allow the usage of the camera and photo library, or your app will crash.
+
+Add the keys below to your `Info.plist`, adding strings with the description you want to provide when prompting the user.
+
+```
+    NSPhotoLibraryUsageDescription
+    NSCameraUsageDescription
+```
+
+### Usage
+
+To use this component couldn't be simpler.
+Add `import ALCameraViewController` to the top of your controller file.
+
+In the viewController
+```swift
+
+let cameraViewController = CameraViewController { [weak self] image, asset in
+	// Do something with your image here.
+	self?.dismiss(animated: true, completion: nil)
+}
+
+present(cameraViewController, animated: true, completion: nil)
+```
+
+### Parameters
+
+There are a number of configurable options available for `CameraViewController`
+
+```swift
+init(croppingParameters: CroppingParameters = CroppingParameters(),
+     allowsLibraryAccess: Bool = true,
+     allowsSwapCameraOrientation: Bool = true,
+     allowVolumeButtonCapture: Bool = true,
+     completion: @escaping CameraViewCompletion)
+```
+
+The Cropping Parameters struct accepts the following parameters
+
+```swift
+init(isEnabled: Bool = false,
+     allowResizing: Bool = true,
+     allowMoving: Bool = true,
+     minimumSize: CGSize = CGSize(width: 60, height: 60))
+```
+
+The success parameter returns a `UIImage?` and a `PHAsset?` for more advanced use cases.
+If the user canceled photo capture then both of these options will be `nil`
+
+```swift
+typealias CameraViewCompletion = (UIImage?, PHAsset?) -> Void
+```
+> Note: To prevent retain cycles, it is best to use a `[weak self]` reference within the success parameter
+
+### Other usage options
+
+You can also instantiate the image picker component by itself as well.
+```swift
+
+let croppingEnabled = true
+
+/// Provides an image picker wrapped inside a UINavigationController instance
+let imagePickerViewController = CameraViewController.imagePickerViewController(croppingEnabled: croppingEnabled) { [weak self] image, asset in
+		// Do something with your image here.
+	 	// If cropping is enabled this image will be the cropped version
+
+    self?.dismiss(animated: true, completion: nil)
+}
+
+present(imagePickerViewController, animated: true, completion: nil)
+
+```
+
+For more control you can create it directly.
+> Note: This approach requires some familiarity with the PhotoKit library provided by apple
+
+```swift
+import Photos
+
+let imagePickerViewController = PhotoLibraryViewController()
+imagePickerViewController.onSelectionComplete = { asset in
+
+		// The asset could be nil if the user doesn't select anything
+		guard let asset = asset else {
+			return
+		}
+
+    // Provides a PHAsset object
+		// Retrieve a UIImage from a PHAsset using
+		let options = PHImageRequestOptions()
+    options.deliveryMode = .highQualityFormat
+    options.isNetworkAccessAllowed = true
+
+		PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: options) { image, _ in
+        if let image = image {
+						// Do something with your image here
+        }
+    }
+}
+
+present(imagePickerViewController, animated: true, completion: nil)
+
+```
+
+
+## License
+ALCameraViewController is available under the MIT license. See the LICENSE file for more info.

+ 27 - 0
Pods/Local Podspecs/ALCameraViewController.podspec.json

@@ -0,0 +1,27 @@
+{
+  "name": "ALCameraViewController",
+  "version": "3.0.3",
+  "summary": "A camera view controller with custom image picker and image cropping.",
+  "source": {
+    "git": "https://github.com/AlexLittlejohn/ALCameraViewController.git",
+    "tag": "3.0.3"
+  },
+  "requires_arc": true,
+  "platforms": {
+    "ios": "8.0"
+  },
+  "license": "MIT",
+  "source_files": "ALCameraViewController/**/*.{swift}",
+  "resources": [
+    "ALCameraViewController/ViewController/ConfirmViewController.xib",
+    "ALCameraViewController/CameraViewAssets.xcassets",
+    "ALCameraViewController/CameraView.strings"
+  ],
+  "homepage": "https://github.com/AlexLittlejohn/ALCameraViewController",
+  "authors": {
+    "Alex Littlejohn": "alexlittlejohn@me.com"
+  },
+  "pod_target_xcconfig": {
+    "SWIFT_VERSION": "4.2"
+  }
+}

+ 13 - 1
Pods/Manifest.lock

@@ -1,4 +1,5 @@
 PODS:
+  - ALCameraViewController (3.0.3)
   - DBDebugToolkit (0.5.0)
   - JGProgressHUD (2.0.3)
   - MessageInputBar/Core (0.4.1)
@@ -10,6 +11,7 @@ PODS:
   - SwiftyBeaver (1.6.1)
 
 DEPENDENCIES:
+  - ALCameraViewController (from `https://github.com/dignifiedquire/ALCameraViewController`)
   - DBDebugToolkit
   - JGProgressHUD
   - MessageKit (= 2.0.0)
@@ -29,7 +31,17 @@ SPEC REPOS:
     - ReachabilitySwift
     - SwiftyBeaver
 
+EXTERNAL SOURCES:
+  ALCameraViewController:
+    :git: https://github.com/dignifiedquire/ALCameraViewController
+
+CHECKOUT OPTIONS:
+  ALCameraViewController:
+    :commit: e0fcc4338276e4fc6240e8726ecc77aa39ce1385
+    :git: https://github.com/dignifiedquire/ALCameraViewController
+
 SPEC CHECKSUMS:
+  ALCameraViewController: dd13cf0a5b44a4d542c73bbcbebd02bc09e929c7
   DBDebugToolkit: c04bb6f618051d3de447a4b4323f37826116cfed
   JGProgressHUD: 12b20a8f4ffe05258f8635c1ab92816e451f904d
   MessageInputBar: e81c7535347f1f7b923de7080409a535a004b6e4
@@ -39,6 +51,6 @@ SPEC CHECKSUMS:
   ReachabilitySwift: 408477d1b6ed9779dba301953171e017c31241f3
   SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a
 
-PODFILE CHECKSUM: 68c148b02e1dc4050bbbf02257c1216b82641b16
+PODFILE CHECKSUM: 754ae089b2ba2b296811903f136cbcc4b8f52d5a
 
 COCOAPODS: 1.5.3

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 951 - 898
Pods/Pods.xcodeproj/project.pbxproj


+ 5 - 0
Pods/Target Support Files/ALCameraViewController/ALCameraViewController-dummy.m

@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_ALCameraViewController : NSObject
+@end
+@implementation PodsDummy_ALCameraViewController
+@end

+ 12 - 0
Pods/Target Support Files/ALCameraViewController/ALCameraViewController-prefix.pch

@@ -0,0 +1,12 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+

+ 16 - 0
Pods/Target Support Files/ALCameraViewController/ALCameraViewController-umbrella.h

@@ -0,0 +1,16 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+
+
+FOUNDATION_EXPORT double ALCameraViewControllerVersionNumber;
+FOUNDATION_EXPORT const unsigned char ALCameraViewControllerVersionString[];
+

+ 6 - 0
Pods/Target Support Files/ALCameraViewController/ALCameraViewController.modulemap

@@ -0,0 +1,6 @@
+framework module ALCameraViewController {
+  umbrella header "ALCameraViewController-umbrella.h"
+
+  export *
+  module * { export * }
+}

+ 10 - 0
Pods/Target Support Files/ALCameraViewController/ALCameraViewController.xcconfig

@@ -0,0 +1,10 @@
+CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ALCameraViewController
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PODS_TARGET_SRCROOT = ${PODS_ROOT}/ALCameraViewController
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
+SWIFT_VERSION = 4.2

+ 26 - 0
Pods/Target Support Files/ALCameraViewController/Info.plist

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>3.0.3</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>

+ 26 - 0
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.markdown

@@ -1,6 +1,32 @@
 # Acknowledgements
 This application makes use of the following third party libraries:
 
+## ALCameraViewController
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Alex Littlejohn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+
 ## DBDebugToolkit
 
 Copyright (c) 2016 Dariusz Bukowski <dariusz.m.bukowski@gmail.com>

+ 32 - 0
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.plist

@@ -12,6 +12,38 @@
 			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>The MIT License (MIT)
+
+Copyright (c) 2015 Alex Littlejohn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>ALCameraViewController</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
 		<dict>
 			<key>FooterText</key>
 			<string>Copyright (c) 2016 Dariusz Bukowski &lt;dariusz.m.bukowski@gmail.com&gt;

+ 2 - 0
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh

@@ -143,6 +143,7 @@ strip_invalid_archs() {
 
 
 if [[ "$CONFIGURATION" == "Debug" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/ALCameraViewController/ALCameraViewController.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/DBDebugToolkit/DBDebugToolkit.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/JGProgressHUD/JGProgressHUD.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework"
@@ -152,6 +153,7 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
   install_framework "${BUILT_PRODUCTS_DIR}/SwiftyBeaver/SwiftyBeaver.framework"
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/ALCameraViewController/ALCameraViewController.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/DBDebugToolkit/DBDebugToolkit.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/JGProgressHUD/JGProgressHUD.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework"

+ 3 - 3
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.debug.xcconfig

@@ -1,11 +1,11 @@
 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit" "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar" "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit" "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController" "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver"
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ALCameraViewController" "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit" "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar" "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit" "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController" "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
 LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/openssl-ios-bitcode/lib"
-OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit/DBDebugToolkit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD/JGProgressHUD.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar/MessageInputBar.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController/QuickTableViewController.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver/SwiftyBeaver.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
-OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "DBDebugToolkit" -framework "JGProgressHUD" -framework "MessageInputBar" -framework "MessageKit" -framework "QuickTableViewController" -framework "Reachability" -framework "SwiftyBeaver"
+OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/ALCameraViewController/ALCameraViewController.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit/DBDebugToolkit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD/JGProgressHUD.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar/MessageInputBar.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController/QuickTableViewController.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver/SwiftyBeaver.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
+OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "ALCameraViewController" -framework "DBDebugToolkit" -framework "JGProgressHUD" -framework "MessageInputBar" -framework "MessageKit" -framework "QuickTableViewController" -framework "Reachability" -framework "SwiftyBeaver"
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

+ 3 - 3
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.release.xcconfig

@@ -1,11 +1,11 @@
 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit" "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar" "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit" "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController" "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver"
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ALCameraViewController" "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit" "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar" "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit" "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController" "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
 LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/openssl-ios-bitcode/lib"
-OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit/DBDebugToolkit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD/JGProgressHUD.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar/MessageInputBar.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController/QuickTableViewController.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver/SwiftyBeaver.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
-OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "DBDebugToolkit" -framework "JGProgressHUD" -framework "MessageInputBar" -framework "MessageKit" -framework "QuickTableViewController" -framework "Reachability" -framework "SwiftyBeaver"
+OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/ALCameraViewController/ALCameraViewController.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/DBDebugToolkit/DBDebugToolkit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/JGProgressHUD/JGProgressHUD.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar/MessageInputBar.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/QuickTableViewController/QuickTableViewController.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyBeaver/SwiftyBeaver.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
+OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "ALCameraViewController" -framework "DBDebugToolkit" -framework "JGProgressHUD" -framework "MessageInputBar" -framework "MessageKit" -framework "QuickTableViewController" -framework "Reachability" -framework "SwiftyBeaver"
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

+ 2 - 0
deltachat-ios.xcodeproj/project.pbxproj

@@ -644,6 +644,7 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh",
+				"${BUILT_PRODUCTS_DIR}/ALCameraViewController/ALCameraViewController.framework",
 				"${BUILT_PRODUCTS_DIR}/DBDebugToolkit/DBDebugToolkit.framework",
 				"${BUILT_PRODUCTS_DIR}/JGProgressHUD/JGProgressHUD.framework",
 				"${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework",
@@ -654,6 +655,7 @@
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ALCameraViewController.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DBDebugToolkit.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JGProgressHUD.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MessageInputBar.framework",

+ 1 - 6
deltachat-ios/AppDelegate.swift

@@ -69,11 +69,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         start()
         open()
 
-        let ud = UserDefaults.standard
-        if ud.bool(forKey: Constants.Keys.deltachatUserProvidedCredentialsKey) {
-            initCore(withCredentials: false)
-        }
-
         // registerForPushNotifications()
 
         return true
@@ -125,7 +120,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         close()
     }
 
-    private func open() {
+    func open() {
         let paths = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
         let documentsPath = paths[0]
         let dbfile = documentsPath + "/messenger.db"

+ 29 - 29
deltachat-ios/ChatViewController.swift

@@ -10,6 +10,7 @@ import MapKit
 import MessageInputBar
 import MessageKit
 import UIKit
+import ALCameraViewController
 
 class ChatViewController: MessagesViewController {
     let outgoingAvatarOverlap: CGFloat = 17.5
@@ -23,6 +24,8 @@ class ChatViewController: MessagesViewController {
     var incomingMsgObserver: Any?
 
     var disableWriting = false
+    
+    var previewView: UIView?
 
     init(chatId: Int) {
         self.chatId = chatId
@@ -534,18 +537,36 @@ extension ChatViewController: MessagesLayoutDelegate {
 
     @objc func didPressPhotoButton() {
         if UIImagePickerController.isSourceTypeAvailable(.camera) {
-            let imagePicker = UIImagePickerController()
-            imagePicker.sourceType = .camera
-            imagePicker.cameraDevice = .rear
-            imagePicker.delegate = self
-            imagePicker.allowsEditing = true
-            present(imagePicker, animated: true, completion: nil)
+            let cameraViewController = CameraViewController { [weak self] image, asset in
+                self?.dismiss(animated: true, completion: nil)
+                
+                DispatchQueue.global().async {
+                    if let pickedImage = image {
+                        let width = Int32(exactly: pickedImage.size.width)!
+                        let height = Int32(exactly: pickedImage.size.height)!
+                        let path = self?.saveImage(image: pickedImage)
+                        let msg = dc_msg_new(mailboxPointer, DC_MSG_IMAGE)
+                        dc_msg_set_file(msg, path, "image/jpeg")
+                        dc_msg_set_dimension(msg, width, height)
+                        dc_send_msg(mailboxPointer, UInt32(self!.chatId), msg)
+                        
+                        // cleanup
+                        dc_msg_unref(msg)
+                    }
+                }
+            }
+            
+            present(cameraViewController, animated: true, completion: nil)
         } else {
-            logger.info("no camera available")
+            let alert = UIAlertController(title: "Camera is not available", message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: {_ in
+                self.dismiss(animated: true, completion: nil)
+            }))
+            present(alert, animated: true, completion: nil)
         }
     }
 
-    fileprivate func saveImage(image: UIImage) -> String? {
+    func saveImage(image: UIImage) -> String? {
         guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) as NSURL else {
             return nil
         }
@@ -580,27 +601,6 @@ extension ChatViewController: MessagesLayoutDelegate {
     }
 }
 
-extension ChatViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
-    func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
-        DispatchQueue.global().async {
-            if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage,
-                let width = Int32(exactly: pickedImage.size.width),
-                let height = Int32(exactly: pickedImage.size.height),
-                let path = self.saveImage(image: pickedImage) {
-                let msg = dc_msg_new(mailboxPointer, DC_MSG_IMAGE)
-                dc_msg_set_file(msg, path, "image/jpeg")
-                dc_msg_set_dimension(msg, width, height)
-                dc_send_msg(mailboxPointer, UInt32(self.chatId), msg)
-
-                // cleanup
-                dc_msg_unref(msg)
-            }
-        }
-
-        dismiss(animated: true, completion: nil)
-    }
-}
-
 // MARK: - MessageCellDelegate
 
 extension ChatViewController: MessageCellDelegate {

+ 1 - 0
deltachat-ios/ContactProfileViewController.swift

@@ -114,6 +114,7 @@ class ContactProfileViewController: UITableViewController {
             } else {
                 contactCell.setBackupImage(name: contact.name, color: contact.color)
             }
+
             contactCell.setVerified(isVerified: contact.isVerified)
 
             return contactCell

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно