Skip to content
This repository has been archived by the owner on Dec 11, 2020. It is now read-only.

[WIP] Support URL items #36

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
410 changes: 205 additions & 205 deletions WeTransfer Sample Project/MainViewController.swift

Large diffs are not rendered by default.

194 changes: 97 additions & 97 deletions WeTransfer Sample Project/MediaPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,104 +11,104 @@ import Photos

/// Basic wrapper for UIImagePickerController to handle authorization and configuring and presenting the controller
final class MediaPicker: NSObject {
struct Media {
let url: URL
let previewImage: UIImage
}
typealias PickedMediaHandler = (_ media: Media?) -> Void
private var mediaHandler: PickedMediaHandler?
private var presentedImagePickerControler: UIImagePickerController?
func show(from viewController: UIViewController, mediaHandler: @escaping PickedMediaHandler) {
guard self.mediaHandler == nil else {
return
}
self.mediaHandler = mediaHandler
authorize { [weak self] (succeeded) in
guard succeeded, UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
self?.finish(with: nil)
return
}
self?.presentImagePicker(from: viewController)
}
}
private func presentImagePicker(from viewController: UIViewController) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = .photoLibrary
if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary) {
imagePickerController.mediaTypes = mediaTypes
}
viewController.present(imagePickerController, animated: true, completion: nil)
presentedImagePickerControler = imagePickerController
}
private func authorize(with completion: @escaping (Bool) -> Void) {
switch PHPhotoLibrary.authorizationStatus() {
case .authorized:
completion(true)
case .denied, .restricted:
completion(false)
case .notDetermined:
PHPhotoLibrary.requestAuthorization { (status) in
guard status == .authorized else {
completion(false)
return
}
completion(true)
}
}
}
private func finish(with item: URL?) {
guard let url = item else {
mediaHandler?(nil)
dismissPickerController()
return
}
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
var pickedMedia: Media?
let asset = AVAsset(url: url)
if asset.duration.seconds > 0 {
// Get first frame if video
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
if let image = try? imageGenerator.copyCGImage(at: CMTime.zero, actualTime: nil) {
pickedMedia = Media(url: url, previewImage: UIImage(cgImage: image))
}
} else {
if let image = UIImage(contentsOfFile: url.path) {
pickedMedia = Media(url: url, previewImage: image)
}
}
DispatchQueue.main.async {
self?.mediaHandler?(pickedMedia)
self?.dismissPickerController()
}
}
}
private func dismissPickerController() {
mediaHandler = nil
presentedImagePickerControler?.presentingViewController?.dismiss(animated: true, completion: nil)
presentedImagePickerControler = nil
}
struct Media {
let url: URL
let previewImage: UIImage
}
typealias PickedMediaHandler = (_ media: Media?) -> Void
private var mediaHandler: PickedMediaHandler?
private var presentedImagePickerControler: UIImagePickerController?
func show(from viewController: UIViewController, mediaHandler: @escaping PickedMediaHandler) {
guard self.mediaHandler == nil else {
return
}
self.mediaHandler = mediaHandler
authorize { [weak self] (succeeded) in
guard succeeded, UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
self?.finish(with: nil)
return
}
self?.presentImagePicker(from: viewController)
}
}
private func presentImagePicker(from viewController: UIViewController) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = .photoLibrary
if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary) {
imagePickerController.mediaTypes = mediaTypes
}
viewController.present(imagePickerController, animated: true, completion: nil)
presentedImagePickerControler = imagePickerController
}
private func authorize(with completion: @escaping (Bool) -> Void) {
switch PHPhotoLibrary.authorizationStatus() {
case .authorized:
completion(true)
case .denied, .restricted:
completion(false)
case .notDetermined:
PHPhotoLibrary.requestAuthorization { (status) in
guard status == .authorized else {
completion(false)
return
}
completion(true)
}
}
}
private func finish(with item: URL?) {
guard let url = item else {
mediaHandler?(nil)
dismissPickerController()
return
}
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
var pickedMedia: Media?
let asset = AVAsset(url: url)
if asset.duration.seconds > 0 {
// Get first frame if video
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
if let image = try? imageGenerator.copyCGImage(at: CMTime.zero, actualTime: nil) {
pickedMedia = Media(url: url, previewImage: UIImage(cgImage: image))
}
} else {
if let image = UIImage(contentsOfFile: url.path) {
pickedMedia = Media(url: url, previewImage: image)
}
}
DispatchQueue.main.async {
self?.mediaHandler?(pickedMedia)
self?.dismissPickerController()
}
}
}
private func dismissPickerController() {
mediaHandler = nil
presentedImagePickerControler?.presentingViewController?.dismiss(animated: true, completion: nil)
presentedImagePickerControler = nil
}
}

extension MediaPicker: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
finish(with: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
guard let url = info[UIImagePickerController.InfoKey.imageURL] as? URL ?? info[UIImagePickerController.InfoKey.mediaURL] as? URL else {
finish(with: nil)
return
}
finish(with: url)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
finish(with: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
guard let url = info[UIImagePickerController.InfoKey.imageURL] as? URL ?? info[UIImagePickerController.InfoKey.mediaURL] as? URL else {
finish(with: nil)
return
}
finish(with: url)
}
}
102 changes: 51 additions & 51 deletions WeTransfer Sample Project/RoundedButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,55 @@ import UIKit

/// Button with colored background and rounded corners
final class RoundedButton: UIButton {
enum Style {
case regular
case alternative
}
private let horizontalPadding: CGFloat = 22
private let minimumHeight: CGFloat = 44
var style: Style = .regular {
didSet {
updateBackgroundColor()
updateTitleColor()
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
layer.cornerRadius = 8
updateBackgroundColor()
updateTitleColor()
titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
heightAnchor.constraint(greaterThanOrEqualToConstant: minimumHeight).isActive = true
contentEdgeInsets = UIEdgeInsets(top: 0, left: horizontalPadding, bottom: 0, right: horizontalPadding)
}
override var isEnabled: Bool {
didSet {
updateBackgroundColor()
updateTitleColor()
}
}
private func updateBackgroundColor() {
if isEnabled {
let enabledColor = UIColor(red: 64 / 255, green: 159 / 255, blue: 255 / 255, alpha: 1)
let alternativeColor = UIColor(white: 235 / 255, alpha: 1)
backgroundColor = style == .alternative ? alternativeColor : enabledColor
} else {
backgroundColor = UIColor(red: 165 / 255, green: 168 / 255, blue: 172 / 255, alpha: 1)
}
}
private func updateTitleColor() {
let titleColor = UIColor.white
let alternativeTitleColor = UIColor(white: 75 / 255, alpha: 1)
setTitleColor(style == .alternative ? alternativeTitleColor : titleColor, for: .normal)
}
enum Style {
case regular
case alternative
}
private let horizontalPadding: CGFloat = 22
private let minimumHeight: CGFloat = 44
var style: Style = .regular {
didSet {
updateBackgroundColor()
updateTitleColor()
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
layer.cornerRadius = 8
updateBackgroundColor()
updateTitleColor()
titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
heightAnchor.constraint(greaterThanOrEqualToConstant: minimumHeight).isActive = true
contentEdgeInsets = UIEdgeInsets(top: 0, left: horizontalPadding, bottom: 0, right: horizontalPadding)
}
override var isEnabled: Bool {
didSet {
updateBackgroundColor()
updateTitleColor()
}
}
private func updateBackgroundColor() {
if isEnabled {
let enabledColor = UIColor(red: 64 / 255, green: 159 / 255, blue: 255 / 255, alpha: 1)
let alternativeColor = UIColor(white: 235 / 255, alpha: 1)
backgroundColor = style == .alternative ? alternativeColor : enabledColor
} else {
backgroundColor = UIColor(red: 165 / 255, green: 168 / 255, blue: 172 / 255, alpha: 1)
}
}
private func updateTitleColor() {
let titleColor = UIColor.white
let alternativeTitleColor = UIColor(white: 75 / 255, alpha: 1)
setTitleColor(style == .alternative ? alternativeTitleColor : titleColor, for: .normal)
}
}
12 changes: 6 additions & 6 deletions WeTransfer Sample Project/Supporting Files/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import UIKit

@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
}
Loading