|
@@ -0,0 +1,992 @@
|
|
|
+//
|
|
|
+// PQUploadViewController.swift
|
|
|
+// PQSpeed
|
|
|
+//
|
|
|
+// Created by SanW on 2020/8/1.
|
|
|
+// Copyright © 2020 BytesFlow. All rights reserved.
|
|
|
+//
|
|
|
+
|
|
|
+import MobileCoreServices
|
|
|
+import Photos
|
|
|
+import UIKit
|
|
|
+import BFCommonKit
|
|
|
+
|
|
|
+let playerHeaderH: CGFloat = cScreenWidth * (250 / 375)
|
|
|
+
|
|
|
+open class PQUploadController: BFBaseViewController {
|
|
|
+ // 最大的宽度
|
|
|
+ public var maxWidth: CGFloat = cScreenWidth
|
|
|
+ // 最大的高度
|
|
|
+ public var maxHeight: CGFloat = adapterWidth(width: 300)
|
|
|
+ public var jumptoPublicHandle:((_ selectData:PQUploadModel?) -> Void)?
|
|
|
+ // 画面比例
|
|
|
+ public var aspectRatio: aspectRatio?
|
|
|
+ public var preViewSize: CGSize {
|
|
|
+ if aspectRatio == nil, (isMember(of: PQUploadController.self) && selectedData == nil) || (!isMember(of: PQUploadController.self) && uploadData == nil) {
|
|
|
+ return CGSize(width: maxHeight, height: maxHeight)
|
|
|
+ }
|
|
|
+ if selectedData != nil {
|
|
|
+ aspectRatio = .origin(width: CGFloat(videoData[lastSeletedIndex?.item ?? 0].videoWidth), height: CGFloat(videoData[lastSeletedIndex?.item ?? 0].videoHeight))
|
|
|
+ } else if aspectRatio == nil {
|
|
|
+ aspectRatio = .origin(width: CGFloat(uploadData?.videoWidth ?? maxHeight), height: CGFloat(uploadData?.videoHeight ?? maxHeight))
|
|
|
+ }
|
|
|
+ switch aspectRatio {
|
|
|
+ case let .origin(width, height):
|
|
|
+ var tempHeight: CGFloat = 0
|
|
|
+ var tempWidth: CGFloat = 0
|
|
|
+ if width > height {
|
|
|
+ tempHeight = (maxWidth * height / width)
|
|
|
+ tempWidth = maxWidth
|
|
|
+ } else {
|
|
|
+ tempHeight = maxHeight
|
|
|
+ tempWidth = (maxHeight * width / height)
|
|
|
+ }
|
|
|
+ if tempHeight.isNaN || tempWidth.isNaN {
|
|
|
+ return CGSize.zero
|
|
|
+ } else {
|
|
|
+ return CGSize(width: tempWidth, height: tempHeight)
|
|
|
+ }
|
|
|
+ case .oneToOne:
|
|
|
+ if maxWidth > maxHeight {
|
|
|
+ return CGSize(width: maxHeight, height: maxHeight)
|
|
|
+ } else {
|
|
|
+ return CGSize(width: maxWidth, height: maxWidth)
|
|
|
+ }
|
|
|
+ case .sixteenToNine:
|
|
|
+ return CGSize(width: maxWidth, height: maxWidth * 9.0 / 16.0)
|
|
|
+ case .nineToSixteen:
|
|
|
+ return CGSize(width: maxHeight * 9.0 / 16.0, height: maxHeight)
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ return CGSize(width: maxHeight, height: maxHeight)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上传入口类型
|
|
|
+ public var sourceType: videoUploadSourceType = .videoUpload
|
|
|
+ // 制作视频项目Id
|
|
|
+ public var makeVideoProjectId: String?
|
|
|
+ // 再创作数据
|
|
|
+ public var reCreateData: PQReCreateModel?
|
|
|
+ // 视频创作埋点数据
|
|
|
+ public var eventTrackData: PQVideoMakeEventTrackModel?
|
|
|
+ // 制作视频草稿Id
|
|
|
+ public var makeVideoDraftboxId: String?
|
|
|
+ // 制作视频草稿结构化数据
|
|
|
+ public var makeVideoSdata: String?
|
|
|
+ public var isAssetImage: Bool = false // 是否请求的是图片
|
|
|
+ public var videoWidth: CGFloat = 0 // 视频宽
|
|
|
+ public var videoHeight: CGFloat = 0 // 视频高
|
|
|
+ public var isLoop: Bool = true // 是否循环播放
|
|
|
+ public var playerItem: AVPlayerItem? // 当前播放item
|
|
|
+ public var videoOutput: AVPlayerItemVideoOutput?
|
|
|
+ let itemSize = CGSize(width: ((cScreenWidth - cDefaultMargin) / 3) * UIScreen.main.scale, height: ((cScreenWidth - cDefaultMargin) / 3) * UIScreen.main.scale)
|
|
|
+ public var categoryH: CGFloat = cDefaultMargin * 40 // 相簿高度
|
|
|
+
|
|
|
+ public var videoData: [PQUploadModel] = Array<PQUploadModel>.init()
|
|
|
+
|
|
|
+ public var categoryData: [PQUploadModel] = Array<PQUploadModel>.init()
|
|
|
+
|
|
|
+ // 当前选中的数据
|
|
|
+ public var selectedData: PQUploadModel?
|
|
|
+ // 确定上传的数据
|
|
|
+ public var uploadData: PQUploadModel?
|
|
|
+ public var catagerySelectedIndex: IndexPath = IndexPath(item: 0, section: 0) // 更多图库选择
|
|
|
+
|
|
|
+ public var isJumpToAuthorization: Bool = false // 是否跳到授权
|
|
|
+ public var lastSeletedIndex: IndexPath? // 上次选中的index
|
|
|
+ public lazy var imageManager: PHCachingImageManager = {
|
|
|
+ (PHCachingImageManager.default() as? PHCachingImageManager) ?? PHCachingImageManager()
|
|
|
+ }()
|
|
|
+
|
|
|
+ public var allPhotos: PHFetchResult<PHAsset>!
|
|
|
+ public var previousPreheatRect = CGRect.zero
|
|
|
+
|
|
|
+ public var smartAlbums: PHFetchResult<PHAssetCollection>!
|
|
|
+ public var userCollections: PHFetchResult<PHCollection>!
|
|
|
+ public let sectionLocalizedTitles = ["", NSLocalizedString("Smart Albums", comment: ""), NSLocalizedString("Albums", comment: "")]
|
|
|
+ public lazy var fetchOptions: PHFetchOptions = {
|
|
|
+ let fetchOptions = PHFetchOptions()
|
|
|
+ fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
|
|
|
+ fetchOptions.predicate = NSPredicate(format: "mediaType = %d", !isAssetImage ? PHAssetMediaType.video.rawValue : PHAssetMediaType.image.rawValue)
|
|
|
+ return fetchOptions
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var imagesOptions: PHImageRequestOptions = {
|
|
|
+ let imagesOptions = PHImageRequestOptions()
|
|
|
+ imagesOptions.isSynchronous = true
|
|
|
+ imagesOptions.isNetworkAccessAllowed = false
|
|
|
+ imagesOptions.deliveryMode = .opportunistic
|
|
|
+ imagesOptions.resizeMode = .fast
|
|
|
+ imagesOptions.progressHandler = { _, _, _, info in
|
|
|
+ BFLog(message: "progressHandler = \(info)")
|
|
|
+ }
|
|
|
+ return imagesOptions
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var singleImageOptions: PHImageRequestOptions = {
|
|
|
+ let singleImageOptions = PHImageRequestOptions()
|
|
|
+ singleImageOptions.isSynchronous = true
|
|
|
+ singleImageOptions.isNetworkAccessAllowed = false
|
|
|
+ singleImageOptions.deliveryMode = .highQualityFormat
|
|
|
+ return singleImageOptions
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var backBtn: UIButton = {
|
|
|
+ let backBtn = UIButton(type: .custom)
|
|
|
+ backBtn.frame = CGRect(x: 0, y: cDevice_iPhoneStatusBarHei, width: cDefaultMargin * 4, height: cDefaultMargin * 4)
|
|
|
+ backBtn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: -5, right: 0)
|
|
|
+ backBtn.setImage(UIImage(named: "ic_close_black"), for: .normal)
|
|
|
+ backBtn.addTarget(self, action: #selector(backBtnClick), for: .touchUpInside)
|
|
|
+ return backBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+ public var anthorEmptyData: BFEmptyModel? = {
|
|
|
+ let anthorEmptyData = BFEmptyModel()
|
|
|
+ anthorEmptyData.title = "开始上传"
|
|
|
+ anthorEmptyData.summary = "要开始上传视频,请先授予相册使用权限"
|
|
|
+ anthorEmptyData.emptyImageName = "icon_authorError"
|
|
|
+ return anthorEmptyData
|
|
|
+ }()
|
|
|
+
|
|
|
+ public var emptyData: BFEmptyModel? = {
|
|
|
+ let emptyData = BFEmptyModel()
|
|
|
+ emptyData.title = "哦呜~ 你没有可上传的视频~"
|
|
|
+ emptyData.emptyImageName = "video_empty"
|
|
|
+ return emptyData
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var emptyRemindView: BFEmptyRemindView = {
|
|
|
+ let emptyRemindView = BFEmptyRemindView(frame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei))
|
|
|
+ emptyRemindView.isHidden = true
|
|
|
+ emptyRemindView.emptyData = anthorEmptyData
|
|
|
+ view.addSubview(emptyRemindView)
|
|
|
+ emptyRemindView.fullRefreshBloc = { [weak self, weak emptyRemindView] _, _ in
|
|
|
+ self?.isJumpToAuthorization = true
|
|
|
+ if emptyRemindView?.refreshBtn.currentTitle == "授予权限" {
|
|
|
+ openAppSetting()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return emptyRemindView
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var collectionView: UICollectionView = {
|
|
|
+ let layout = UICollectionViewFlowLayout()
|
|
|
+ layout.sectionInset = UIEdgeInsets.zero
|
|
|
+ let collectionView = UICollectionView(frame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei), collectionViewLayout: layout)
|
|
|
+ collectionView.showsVerticalScrollIndicator = false
|
|
|
+ collectionView.register(PQSelecteVideoItemCell.self, forCellWithReuseIdentifier: "PQSelecteVideoItemCell")
|
|
|
+ collectionView.delegate = self
|
|
|
+ collectionView.dataSource = self
|
|
|
+ if #available(iOS 11.0, *) {
|
|
|
+ collectionView.contentInsetAdjustmentBehavior = .never
|
|
|
+ } else {
|
|
|
+ automaticallyAdjustsScrollViewInsets = false
|
|
|
+ }
|
|
|
+ collectionView.backgroundColor = UIColor.hexColor(hexadecimal: "#191919")
|
|
|
+ return collectionView
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var categoryCollectionView: UICollectionView = {
|
|
|
+ let layout = UICollectionViewFlowLayout()
|
|
|
+ layout.sectionInset = UIEdgeInsets.zero
|
|
|
+ let categoryCollectionView = UICollectionView(frame: CGRect(x: 0, y: -categoryH, width: cScreenWidth, height: categoryH), collectionViewLayout: layout)
|
|
|
+ categoryCollectionView.showsVerticalScrollIndicator = false
|
|
|
+ categoryCollectionView.register(PQAssetCategoryCell.self, forCellWithReuseIdentifier: "PQAssetCategoryCell")
|
|
|
+ categoryCollectionView.delegate = self
|
|
|
+ categoryCollectionView.dataSource = self
|
|
|
+ if #available(iOS 11.0, *) {
|
|
|
+ categoryCollectionView.contentInsetAdjustmentBehavior = .never
|
|
|
+ } else {
|
|
|
+ automaticallyAdjustsScrollViewInsets = false
|
|
|
+ }
|
|
|
+ categoryCollectionView.backgroundColor = BFConfig.shared.editCoverimageSelectedbackgroundColor
|
|
|
+ return categoryCollectionView
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var categoryView: UIView = {
|
|
|
+ let categoryView = UIView(frame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei))
|
|
|
+ categoryView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
|
|
|
+ let bgView = UIView(frame: CGRect(x: 0, y: categoryH, width: categoryView.frame.width, height: categoryView.frame.height - categoryH))
|
|
|
+ let ges = UITapGestureRecognizer(target: self, action: #selector(cancelClick))
|
|
|
+ bgView.addGestureRecognizer(ges)
|
|
|
+ categoryView.addSubview(bgView)
|
|
|
+ categoryView.isHidden = true
|
|
|
+ return categoryView
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var avPlayer: AVPlayer = {
|
|
|
+ let avPlayer = AVPlayer()
|
|
|
+ NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: avPlayer.currentItem, queue: .main) { [weak self] notify in
|
|
|
+ BFLog(message: "AVPlayerItemDidPlayToEndTime = \(notify)")
|
|
|
+ avPlayer.seek(to: CMTime.zero)
|
|
|
+ if self?.isLoop ?? false, bf_getCurrentViewController()?.isMember(of: PQUploadController.self) ?? false {
|
|
|
+ if self?.playerLayer.superlayer == nil {
|
|
|
+ self?.playerHeaderView.layer.insertSublayer(self!.playerLayer, at: 0)
|
|
|
+ }
|
|
|
+ avPlayer.play()
|
|
|
+ } else {
|
|
|
+ self?.sliderView.setValue(1.0, animated: false)
|
|
|
+ self?.playBtn.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ NotificationCenter.default.addObserver(forName: .AVPlayerItemNewErrorLogEntry, object: avPlayer.currentItem, queue: .main) { notify in
|
|
|
+ BFLog(message: "AVPlayerItemNewErrorLogEntry = \(notify)")
|
|
|
+ }
|
|
|
+ NotificationCenter.default.addObserver(forName: .AVPlayerItemFailedToPlayToEndTime, object: avPlayer.currentItem, queue: .main) { notify in
|
|
|
+ BFLog(message: "AVPlayerItemFailedToPlayToEndTime = \(notify)")
|
|
|
+ }
|
|
|
+ NotificationCenter.default.addObserver(forName: .AVPlayerItemPlaybackStalled, object: avPlayer.currentItem, queue: .main) { notify in
|
|
|
+ BFLog(message: "AVPlayerItemPlaybackStalled = \(notify)")
|
|
|
+ }
|
|
|
+ avPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 1000), queue: .main) { [weak self] _ in
|
|
|
+ let progress = CMTimeGetSeconds(avPlayer.currentItem?.currentTime() ?? CMTime.zero) / CMTimeGetSeconds(avPlayer.currentItem?.duration ?? CMTime.zero)
|
|
|
+ self?.sliderView.setValue(Float(progress), animated: false)
|
|
|
+ if progress >= 1, !(self?.isLoop ?? false) {
|
|
|
+ self?.sliderView.setValue(Float(progress), animated: false)
|
|
|
+ self?.playBtn.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return avPlayer
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var playerLayer: AVPlayerLayer = {
|
|
|
+ let playerLayer = AVPlayerLayer(player: avPlayer)
|
|
|
+ playerLayer.frame = CGRect(origin: CGPoint.zero, size: preViewSize)
|
|
|
+ return playerLayer
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var sliderView: BFPlayerSlider = {
|
|
|
+ let sliderView = BFPlayerSlider(frame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei + maxHeight, width: view.frame.width, height: cDefaultMargin))
|
|
|
+ let thbImage = UIImage(named: "icon_point")
|
|
|
+ sliderView.setMinimumTrackImage(thbImage, for: .normal)
|
|
|
+ sliderView.setMaximumTrackImage(thbImage, for: .normal)
|
|
|
+ sliderView.setThumbImage(thbImage, for: .highlighted)
|
|
|
+ sliderView.setThumbImage(thbImage, for: .normal)
|
|
|
+ sliderView.maximumTrackTintColor = UIColor.clear
|
|
|
+ sliderView.addTarget(self, action: #selector(sliderValueDidChanged(sender:)), for: .valueChanged)
|
|
|
+ sliderView.minimumTrackTintColor = UIColor.white
|
|
|
+ sliderView.isHidden = true
|
|
|
+ sliderView.backgroundColor = UIColor.black
|
|
|
+ return sliderView
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var playBtn: UIButton = {
|
|
|
+ let playBtn = UIButton(type: .custom)
|
|
|
+ playBtn.frame = CGRect(x: (preViewSize.width - cDefaultMargin * 5) / 2, y: (preViewSize.height - cDefaultMargin * 5) / 2, width: cDefaultMargin * 5, height: cDefaultMargin * 5)
|
|
|
+ playBtn.setImage(UIImage(named: "icon_video_play_big"), for: .normal)
|
|
|
+ playBtn.tag = 4
|
|
|
+ playBtn.isHidden = true
|
|
|
+ playBtn.isUserInteractionEnabled = false
|
|
|
+ // playBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
|
|
|
+ return playBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+ public var playerHeaderView: UIImageView = {
|
|
|
+ let playerHeaderView = UIImageView(frame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: 0))
|
|
|
+ playerHeaderView.isUserInteractionEnabled = true
|
|
|
+ playerHeaderView.contentMode = .scaleAspectFit
|
|
|
+ playerHeaderView.clipsToBounds = true
|
|
|
+ playerHeaderView.backgroundColor = UIColor.black
|
|
|
+ return playerHeaderView
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var selecteBtn: UIButton = {
|
|
|
+ let selecteBtn = UIButton(frame: CGRect(x: deleteBtn.frame.maxX + cDefaultMargin, y: 0, width: cScreenWidth - nextBtn.frame.width - deleteBtn.frame.maxX - cDefaultMargin * 5, height: cDevice_iPhoneTabBarHei))
|
|
|
+ selecteBtn.titleLabel?.lineBreakMode = .byTruncatingTail
|
|
|
+ selecteBtn.setTitle("全部", for: .normal)
|
|
|
+ selecteBtn.setImage(UIImage(named: "icon_uploadVideo_more"), for: .normal)
|
|
|
+ selecteBtn.setTitleColor(UIColor.white, for: .normal)
|
|
|
+ selecteBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium)
|
|
|
+ selecteBtn.tag = 2
|
|
|
+ selecteBtn.imagePosition(at: .right, space: cDefaultMargin / 2)
|
|
|
+ selecteBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
|
|
|
+ return selecteBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var deleteBtn: UIButton = {
|
|
|
+ let deleteBtn = UIButton(frame: CGRect(x: cDefaultMargin, y: 0, width: cDefaultMargin * 4, height: cDevice_iPhoneTabBarHei))
|
|
|
+ deleteBtn.setImage(UIImage(named: "upload_delete"), for: .normal)
|
|
|
+ deleteBtn.tag = 1
|
|
|
+ deleteBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
|
|
|
+ return deleteBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var nextBtn: UIButton = {
|
|
|
+ let nextBtn = UIButton(frame: CGRect(x: 0, y: (cDevice_iPhoneTabBarHei - cDefaultMargin * 3) / 2, width: cDefaultMargin * 6, height: cDefaultMargin * 3))
|
|
|
+ nextBtn.addCorner(corner: 3)
|
|
|
+ nextBtn.setTitle("下一步", for: .normal)
|
|
|
+ nextBtn.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .medium)
|
|
|
+ nextBtn.tag = 3
|
|
|
+ nextBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
|
|
|
+ nextBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#333333")
|
|
|
+ nextBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#999999"), for: .normal)
|
|
|
+ return nextBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+ public lazy var bottomView: UIView = {
|
|
|
+ let bottomView = UIView(frame: CGRect(x: 0, y: cDefaultMargin * 2, width: cScreenWidth, height: cDevice_iPhoneNavBarHei))
|
|
|
+ bottomView.addSubview(selecteBtn)
|
|
|
+ bottomView.backgroundColor = UIColor.hexColor(hexadecimal: "#191919")
|
|
|
+ selecteBtn.center.y = nextBtn.center.y
|
|
|
+ bottomView.addSubview(deleteBtn)
|
|
|
+ bottomView.addSubview(nextBtn)
|
|
|
+ nextBtn.frame.origin.x = bottomView.frame.width - nextBtn.frame.width - cDefaultMargin * 2
|
|
|
+ return bottomView
|
|
|
+ }()
|
|
|
+
|
|
|
+ open override func viewDidLoad() {
|
|
|
+ super.viewDidLoad()
|
|
|
+
|
|
|
+ view.backgroundColor = BFConfig.shared.editCoverimageSelectedbackgroundColor
|
|
|
+ navHeadImageView?.backgroundColor = BFConfig.shared.editCoverimageSelectedbackgroundColor
|
|
|
+ lineView?.backgroundColor = BFConfig.shared.editCoverimageSelectedbackgroundColor
|
|
|
+ addSubViews()
|
|
|
+ bottomView.backgroundColor = BFConfig.shared.editCoverimageSelectedbackgroundColor
|
|
|
+ loadLocalData()
|
|
|
+ }
|
|
|
+
|
|
|
+ deinit {
|
|
|
+ // PHPhotoLibrary.shared().unregisterChangeObserver(self)
|
|
|
+ }
|
|
|
+
|
|
|
+ open override func viewDidDisappear(_ animated: Bool) {
|
|
|
+ super.viewDidDisappear(animated)
|
|
|
+ if !isAssetImage {
|
|
|
+ avPlayer.pause()
|
|
|
+ playBtn.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ open override func viewWillAppear(_ animated: Bool) {
|
|
|
+ super.viewDidAppear(animated)
|
|
|
+ if !isAssetImage {
|
|
|
+ if selectedData != nil {
|
|
|
+ playBtn.isHidden = true
|
|
|
+ if playerLayer.superlayer == nil {
|
|
|
+ playerHeaderView.layer.insertSublayer(playerLayer, at: 0)
|
|
|
+ }
|
|
|
+ avPlayer.play()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ addPlayerItemObserver()
|
|
|
+ }
|
|
|
+
|
|
|
+ open override func viewWillDisappear(_ animated: Bool) {
|
|
|
+ super.viewWillDisappear(animated)
|
|
|
+ removePlayerItemObserver()
|
|
|
+ }
|
|
|
+
|
|
|
+ open func addSubViews() {
|
|
|
+ view.addSubview(collectionView)
|
|
|
+ navHeadImageView?.addSubview(bottomView)
|
|
|
+ if !isAssetImage {
|
|
|
+ view.addSubview(playerHeaderView)
|
|
|
+ view.addSubview(sliderView)
|
|
|
+ let ges = UITapGestureRecognizer(target: self, action: #selector(playPreVideo))
|
|
|
+ playerHeaderView.addGestureRecognizer(ges)
|
|
|
+ playerHeaderView.addSubview(playBtn)
|
|
|
+ playerHeaderView.layer.insertSublayer(playerLayer, at: 0)
|
|
|
+ }
|
|
|
+ PQNotification.addObserver(self, selector: #selector(didBecomeActiveNotification), name: UIApplication.didBecomeActiveNotification, object: nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ open func loadLocalData() {
|
|
|
+ let authStatus = PHPhotoLibrary.authorizationStatus()
|
|
|
+ if authStatus == .notDetermined {
|
|
|
+ // 第一次触发授权 alert
|
|
|
+ PHPhotoLibrary.requestAuthorization { [weak self] (status: PHAuthorizationStatus) -> Void in
|
|
|
+ if status == .authorized {
|
|
|
+ if (self?.allPhotos == nil) || (self?.allPhotos.count ?? 0) <= 0 {
|
|
|
+ self?.loadPhotoData()
|
|
|
+ }
|
|
|
+ if self?.backBtn != nil {
|
|
|
+ self?.backBtn.removeFromSuperview()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.emptyRemindView.isHidden = false
|
|
|
+ self?.emptyRemindView.refreshBtn.isHidden = false
|
|
|
+ self?.emptyRemindView.refreshBtn.setTitle("授予权限", for: .normal)
|
|
|
+ if self?.backBtn.superview == nil {
|
|
|
+ self?.view.addSubview((self?.backBtn)!)
|
|
|
+ } else {
|
|
|
+ self?.backBtn.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if authStatus == .authorized {
|
|
|
+ if allPhotos == nil || allPhotos.count <= 0 {
|
|
|
+ loadPhotoData()
|
|
|
+ }
|
|
|
+ if backBtn.superview != nil {
|
|
|
+ backBtn.removeFromSuperview()
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ emptyRemindView.isHidden = false
|
|
|
+ emptyRemindView.refreshBtn.isHidden = false
|
|
|
+ emptyRemindView.refreshBtn.setTitle("授予权限", for: .normal)
|
|
|
+ if backBtn.superview == nil {
|
|
|
+ view.addSubview(backBtn)
|
|
|
+ } else {
|
|
|
+ backBtn.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ open func loadPhotoData() {
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ BFLoadingHUB.shared.showHUB(superView: self!.view, isVerticality: false)
|
|
|
+ }
|
|
|
+ DispatchQueue.global().async { [weak self] in
|
|
|
+ self?.allPhotos = PHAsset.fetchAssets(with: self?.fetchOptions)
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ if self?.view != nil {
|
|
|
+ BFLoadingHUB.shared.dismissHUB(superView: self!.view)
|
|
|
+ }
|
|
|
+ self?.collectionView.reloadData()
|
|
|
+ if (self?.allPhotos.count ?? 0) <= 0 {
|
|
|
+ self?.emptyRemindView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei - cDevice_iPhoneTabBarHei)
|
|
|
+ self?.emptyRemindView.emptyData = self?.emptyData
|
|
|
+ self?.emptyRemindView.isHidden = false
|
|
|
+ } else {
|
|
|
+ self?.emptyRemindView.isHidden = true
|
|
|
+ }
|
|
|
+ if (self?.allPhotos.count ?? 0) > 0 {
|
|
|
+ let tempData = PQUploadModel()
|
|
|
+ tempData.title = "全部"
|
|
|
+ tempData.categoryList = self!.allPhotos
|
|
|
+ self?.categoryData.insert(tempData, at: 0)
|
|
|
+ }
|
|
|
+ self?.updateCachedAssets()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ PHPhotoLibrary.shared().register(self)
|
|
|
+
|
|
|
+ DispatchQueue.global().async { [weak self] in
|
|
|
+ self?.smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)
|
|
|
+ self?.smartAlbums?.enumerateObjects { [weak self] assCollection, _, _ in
|
|
|
+ if assCollection.localizedTitle != "最近删除" {
|
|
|
+ self?.convertCollection(collection: assCollection)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ self?.userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
|
|
|
+ self?.userCollections.enumerateObjects { assCollection, index, point in
|
|
|
+ BFLog(message: "userCollections == \(assCollection),index = \(index),point = \(point)")
|
|
|
+ if assCollection is PHAssetCollection {
|
|
|
+ if assCollection.localizedTitle != "最近删除" {
|
|
|
+ self?.convertCollection(collection: assCollection as? PHAssetCollection)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !isAssetImage {
|
|
|
+ // 视频上传相关上报
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_pageView, objectType: .ot_pageView, pageSource: .sp_upload_videoSelect, extParams: ["source": videoUploadSourceType.videoUpload.rawValue, "projectId": "", "draftboxId": ""], remindmsg: "上传相关")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转化处理获取到的相簿
|
|
|
+ open func convertCollection(collection: PHAssetCollection?) {
|
|
|
+ if collection == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ DispatchQueue.global().async { [weak self] in
|
|
|
+ let assetsFetchResult = PHAsset.fetchAssets(in: collection!, options: self?.fetchOptions)
|
|
|
+ if assetsFetchResult.count > 0 {
|
|
|
+ let tempData = PQUploadModel()
|
|
|
+ tempData.title = collection?.localizedTitle
|
|
|
+ tempData.categoryList = assetsFetchResult
|
|
|
+ if tempData.categoryList.count > 0 {
|
|
|
+ self?.categoryData.append(tempData)
|
|
|
+ }
|
|
|
+ BFLog(message: "assetsFetchResult = \(assetsFetchResult)")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc open func btnClick(sender: UIButton) {
|
|
|
+ switch sender.tag {
|
|
|
+ case 1: // 返回
|
|
|
+ navigationController?.popViewController(animated: true)
|
|
|
+ if !isAssetImage {
|
|
|
+ // 视频上传相关上报
|
|
|
+ // MARK: SanW--待修改-2021.11.08
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_up_backBtn, pageSource: .sp_upload_videoSelect, extParams: ["source": videoUploadSourceType.videoUpload.rawValue, "projectId": "", "draftboxId":""], remindmsg: "上传相关")
|
|
|
+ }
|
|
|
+ case 2: // 筛选
|
|
|
+ showCollects()
|
|
|
+ case 3: // 下一步
|
|
|
+ if selectedData == nil {
|
|
|
+ cShowHUB(superView: nil, msg: isAssetImage ? "请选择图片" : "请选择视频")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if !isAssetImage {
|
|
|
+ avPlayer.pause()
|
|
|
+ playBtn.isHidden = false
|
|
|
+ if jumptoPublicHandle != nil {
|
|
|
+ uploadData?.videoFromScene = .UploadNormal
|
|
|
+ jumptoPublicHandle!(selectedData)
|
|
|
+ }
|
|
|
+ // 视频上传相关上报
|
|
|
+ PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_up_nextBtn, pageSource: .sp_upload_videoSelect, extParams: ["source": videoUploadSourceType.videoUpload.rawValue, "projectId": "", "draftboxId": ""], remindmsg: "上传相关")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ imageManager.requestImage(for: (selectedData?.asset)!, targetSize: itemSize, contentMode: .aspectFill, options: nil) { [weak self] image, _ in
|
|
|
+ self?.selectedData?.image = image
|
|
|
+ let vc = PQImageCropVC(image: (self?.selectedData?.image)!, aspectWidth: self?.videoWidth ?? 0.0, aspectHeight: self?.videoHeight ?? 0.0)
|
|
|
+ vc.uploadData = self?.selectedData
|
|
|
+ self?.navigationController?.pushViewController(vc, animated: true)
|
|
|
+ }
|
|
|
+ case 4: // 播放
|
|
|
+ playBtn.isHidden = true
|
|
|
+ if playerLayer.superlayer == nil {
|
|
|
+ playerHeaderView.layer.insertSublayer(playerLayer, at: 0)
|
|
|
+ }
|
|
|
+ avPlayer.play()
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc public func showCollects() {
|
|
|
+ if categoryData.count <= 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ categoryCollectionView.reloadData()
|
|
|
+ if categoryView.superview == nil {
|
|
|
+ view.insertSubview(categoryView, belowSubview: navHeadImageView!)
|
|
|
+ categoryView.addSubview(categoryCollectionView)
|
|
|
+ showCategoryView()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if categoryView.isHidden {
|
|
|
+ showCategoryView()
|
|
|
+ } else {
|
|
|
+ cancelClick()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc public func showCategoryView() {
|
|
|
+ categoryView.isHidden = false
|
|
|
+ categoryView.alpha = 0
|
|
|
+ view.bringSubviewToFront(categoryView)
|
|
|
+ view.bringSubviewToFront(bottomView)
|
|
|
+ UIView.animate(withDuration: 0.3, animations: {
|
|
|
+ self.categoryCollectionView.frame = CGRect(x: 0, y: 0, width: cScreenWidth, height: self.categoryH)
|
|
|
+ self.categoryView.alpha = 1
|
|
|
+ }) { _ in
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc func cancelClick() {
|
|
|
+ UIView.animate(withDuration: 0.3, animations: {
|
|
|
+ self.categoryCollectionView.frame = CGRect(x: 0, y: -self.categoryH, width: cScreenWidth, height: self.categoryH)
|
|
|
+ self.categoryView.alpha = 0
|
|
|
+ }) { _ in
|
|
|
+ self.categoryView.isHidden = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc open func playPreVideo() {
|
|
|
+ playBtn.isHidden = !playBtn.isHidden
|
|
|
+ if playBtn.isHidden {
|
|
|
+ if playerLayer.superlayer == nil {
|
|
|
+ playerHeaderView.layer.insertSublayer(playerLayer, at: 0)
|
|
|
+ }
|
|
|
+ avPlayer.play()
|
|
|
+ } else {
|
|
|
+ avPlayer.pause()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc func sliderValueDidChanged(sender: UISlider) {
|
|
|
+ avPlayer.seek(to: CMTime(value: CMTimeValue(sender.value * Float(CMTimeGetSeconds(avPlayer.currentItem?.duration ?? CMTime.zero))), timescale: 1))
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc open func didBecomeActiveNotification() {
|
|
|
+ if isJumpToAuthorization {
|
|
|
+ loadLocalData()
|
|
|
+ isJumpToAuthorization = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ open func isPublishEnabled() {
|
|
|
+ if selectedData != nil {
|
|
|
+ nextBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#EE0051")
|
|
|
+ nextBtn.setTitleColor(UIColor.white, for: .normal)
|
|
|
+ } else {
|
|
|
+ nextBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#333333")
|
|
|
+ nextBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#999999"), for: .normal)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension PQUploadController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIScrollViewDelegate {
|
|
|
+ open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection _: Int) -> Int {
|
|
|
+ if collectionView == self.collectionView {
|
|
|
+ return allPhotos == nil ? videoData.count : allPhotos.count
|
|
|
+ }
|
|
|
+ return categoryData.count
|
|
|
+ }
|
|
|
+
|
|
|
+ open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
|
+ if collectionView == self.collectionView {
|
|
|
+ let cell = PQSelecteVideoItemCell.selecteVideoItemCell(collectionView: collectionView, indexPath: indexPath)
|
|
|
+ if videoData.count <= indexPath.item, allPhotos != nil {
|
|
|
+ let itemData = PQUploadModel()
|
|
|
+ // itemData.image = UIImage.init(named: "cut_place")
|
|
|
+ let asset = allPhotos.object(at: indexPath.item)
|
|
|
+ itemData.asset = asset
|
|
|
+ itemData.duration = asset.duration
|
|
|
+ videoData.append(itemData)
|
|
|
+ }
|
|
|
+ if videoData.count > indexPath.item {
|
|
|
+ let itemData = videoData[indexPath.item]
|
|
|
+ cell.uploadData = itemData
|
|
|
+ if itemData.image == nil, itemData.asset != nil {
|
|
|
+ cell.representedAssetIdentifier = itemData.asset?.localIdentifier
|
|
|
+ imageManager.requestImage(for: itemData.asset!, targetSize: itemSize, contentMode: .aspectFill, options: nil) {[weak self, weak cell] image, info in
|
|
|
+ if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell?.representedAssetIdentifier == itemData.asset?.localIdentifier {
|
|
|
+ if image != nil {
|
|
|
+ itemData.image = image
|
|
|
+ cell?.videoImageView.image = image
|
|
|
+ } else if image == nil, info?.keys.contains("PHImageResultIsInCloudKey") ?? false {
|
|
|
+ let option = PHImageRequestOptions()
|
|
|
+ option.isNetworkAccessAllowed = true
|
|
|
+ option.resizeMode = .fast
|
|
|
+ self?.imageManager.requestImageData(for: itemData.asset!, options: option) {[weak cell] data, _, _, _ in
|
|
|
+ if data != nil {
|
|
|
+ let image = UIImage(data: data!)
|
|
|
+ itemData.image = image
|
|
|
+ cell?.videoImageView.image = image
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ cell.uploadData = PQUploadModel()
|
|
|
+ }
|
|
|
+ return cell
|
|
|
+ } else {
|
|
|
+ let cell = PQAssetCategoryCell.assetCategoryCell(collectionView: collectionView, indexPath: indexPath)
|
|
|
+ let itemData = categoryData[indexPath.item]
|
|
|
+ let asset = itemData.categoryList.object(at: 0)
|
|
|
+ if itemData.image == nil {
|
|
|
+ cell.representedAssetIdentifier = asset.localIdentifier
|
|
|
+ imageManager.requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: nil) {[weak cell] image, info in
|
|
|
+ if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell?.representedAssetIdentifier == asset.localIdentifier {
|
|
|
+ itemData.image = image
|
|
|
+ cell?.uploadData = itemData
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ cell.uploadData = itemData
|
|
|
+ }
|
|
|
+ cell.isSelected = indexPath == catagerySelectedIndex
|
|
|
+ return cell
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
|
+ if collectionView == self.collectionView {
|
|
|
+ if videoData.count <= indexPath.item {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let itemData = videoData[indexPath.item]
|
|
|
+ if !isAssetImage, (itemData.asset?.duration ?? 0) < 5.0 {
|
|
|
+ cShowHUB(superView: nil, msg: "请选择大于5s的视频")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let ratio = Float(itemData.asset?.pixelWidth ?? 0) / Float(itemData.asset?.pixelHeight ?? 1)
|
|
|
+ if ratio < 0.4 || ratio > 4.2 {
|
|
|
+ cShowHUB(superView: nil, msg: "暂不支持该比例的素材")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if lastSeletedIndex != nil, lastSeletedIndex != indexPath {
|
|
|
+ let lastData = videoData[lastSeletedIndex!.item]
|
|
|
+ lastData.isSelected = false
|
|
|
+ collectionView.reloadItems(at: [lastSeletedIndex!])
|
|
|
+ }
|
|
|
+ lastSeletedIndex = indexPath
|
|
|
+ if itemData.isSelected {
|
|
|
+ itemData.isSelected = false
|
|
|
+ selectedData = nil
|
|
|
+ if !isAssetImage {
|
|
|
+ avPlayer.pause()
|
|
|
+ playBtn.isHidden = false
|
|
|
+ sliderView.isHidden = true
|
|
|
+ UIView.animate(withDuration: 0.5, animations: { [weak self] in
|
|
|
+ self?.playerHeaderView.frame = CGRect(x: 0, y: -(self?.preViewSize.height ?? 0) - cDevice_iPhoneNavBarAndStatusBarHei, width: self?.preViewSize.width ?? 0, height: self?.preViewSize.height ?? 0)
|
|
|
+ self?.sliderView.frame.origin.y = self?.playerHeaderView.frame.maxY ?? 0
|
|
|
+ self?.playerHeaderView.center.x = self?.view.center.x ?? 0
|
|
|
+ self?.collectionView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei)
|
|
|
+ }) { _ in
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ itemData.isSelected = true
|
|
|
+ let itemData = videoData[indexPath.item]
|
|
|
+ if !isAssetImage {
|
|
|
+ selectedData = nil
|
|
|
+ sliderView.setValue(0, animated: false)
|
|
|
+ // 加载中...
|
|
|
+ BFLoadingHUB.shared.showHUB(superView: playerHeaderView)
|
|
|
+ avPlayer.pause()
|
|
|
+ avPlayer.replaceCurrentItem(with: nil)
|
|
|
+ playerLayer.removeFromSuperlayer()
|
|
|
+ PQPHAssetVideoParaseUtil.parasToAVPlayerItem(phAsset: itemData.asset!, isHighQuality: true) { [weak self] playerItem, fileSize, info in
|
|
|
+ if playerItem == nil || fileSize > maxUploadSize {
|
|
|
+ if fileSize > maxUploadSize {
|
|
|
+ cShowHUB(superView: nil, msg: "请选择小于10G的视频")
|
|
|
+ } else {
|
|
|
+ cShowHUB(superView: nil, msg: (info != nil && (info?.keys.contains("PHImageResultIsInCloudKey") ?? false) && "\(info?["PHImageResultIsInCloudKey"] ?? "1")" == "1") ? "暂不支持iCloud中的视频" : "此视频已损坏或已删除无法播放")
|
|
|
+ }
|
|
|
+ self?.videoData[(self?.lastSeletedIndex?.item)!].isSelected = false
|
|
|
+ self?.collectionView.reloadItems(at: [(self?.lastSeletedIndex)!])
|
|
|
+ self?.lastSeletedIndex = nil
|
|
|
+ self?.selectedData = nil
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.sliderView.isHidden = true
|
|
|
+ if (self?.playerHeaderView.frame.minY ?? 0.0) >= 0.0 {
|
|
|
+ UIView.animate(withDuration: 0.5, animations: { [weak self] in
|
|
|
+ self?.playerHeaderView.frame = CGRect(x: 0, y: -(self?.preViewSize.height ?? 0) - cDevice_iPhoneNavBarAndStatusBarHei, width: self?.preViewSize.width ?? 0, height: self?.preViewSize.height ?? 0)
|
|
|
+ self?.sliderView.frame.origin.y = self?.playerHeaderView.frame.maxY ?? 0
|
|
|
+ self?.playerHeaderView.center.x = self?.view.center.x ?? 0
|
|
|
+ self?.collectionView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei)
|
|
|
+ }) { _ in
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 加载中...
|
|
|
+ if self?.playerHeaderView != nil {
|
|
|
+ BFLoadingHUB.shared.dismissHUB(superView: (self?.playerHeaderView)!)
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ DispatchQueue.main.async { [weak self] in
|
|
|
+ self?.selectedData = itemData
|
|
|
+ self?.selectedData?.localPath = (playerItem?.asset as! AVURLAsset).url.absoluteString
|
|
|
+ self?.selectedData?.duration = (playerItem?.asset as! AVURLAsset).duration.seconds
|
|
|
+ // 移除监听
|
|
|
+ self?.removePlayerItemObserver()
|
|
|
+ self?.playerItem = playerItem
|
|
|
+ // 添加监听
|
|
|
+ self?.addPlayerItemObserver()
|
|
|
+ self?.playBtn.isHidden = true
|
|
|
+ self?.avPlayer.replaceCurrentItem(with: playerItem)
|
|
|
+ if self?.playerLayer.superlayer == nil {
|
|
|
+ self?.playerHeaderView.layer.insertSublayer(self!.playerLayer, at: 0)
|
|
|
+ }
|
|
|
+ self?.avPlayer.play()
|
|
|
+// self?.playerHeaderView.image = itemData.image
|
|
|
+
|
|
|
+ let tracks = (playerItem?.asset as? AVURLAsset)?.tracks(withMediaType: .video)
|
|
|
+ if tracks != nil, (tracks?.count ?? 0) > 0 {
|
|
|
+ let videoTrack = tracks?.first
|
|
|
+ let transform = videoTrack?.preferredTransform
|
|
|
+ let width: CGFloat = CGFloat(transform?.a ?? 0.0) * CGFloat(videoTrack?.naturalSize.width ?? 0.0) + CGFloat(transform?.c ?? 0.0) * CGFloat(videoTrack?.naturalSize.height ?? 0.0)
|
|
|
+ let height: CGFloat = CGFloat(transform?.b ?? 0.0) * CGFloat(videoTrack?.naturalSize.width ?? 0.0) + CGFloat(transform?.d ?? 0.0) * CGFloat(videoTrack?.naturalSize.height ?? 0.0)
|
|
|
+ self?.selectedData?.videoWidth = abs(width)
|
|
|
+ self?.selectedData?.videoHeight = abs(height)
|
|
|
+ } else {
|
|
|
+ self?.selectedData?.videoWidth = CGFloat(self?.selectedData?.asset?.pixelWidth ?? 0)
|
|
|
+ self?.selectedData?.videoHeight = CGFloat(self?.selectedData?.asset?.pixelHeight ?? 0)
|
|
|
+ }
|
|
|
+ self?.isPublishEnabled()
|
|
|
+ self?.playerHeaderView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: self?.preViewSize.width ?? 0, height: self?.preViewSize.height ?? 0)
|
|
|
+ if self?.playerHeaderView != nil {
|
|
|
+ BFLoadingHUB.shared.showHUB(superView: (self?.playerHeaderView)!)
|
|
|
+ }
|
|
|
+ self?.playerHeaderView.center.x = self?.view.center.x ?? 0
|
|
|
+ self?.sliderView.frame.origin.y = self?.playerHeaderView.frame.maxY ?? 0
|
|
|
+ self?.collectionView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei + CGFloat(self?.preViewSize.height ?? 0) + cDefaultMargin * 1.5, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei - CGFloat(self?.preViewSize.height ?? 0) - cDefaultMargin * 1.5)
|
|
|
+ self?.collectionView.scrollToItem(at: indexPath, at: .top, animated: true)
|
|
|
+ self?.sliderView.isHidden = false
|
|
|
+ self?.playBtn.frame.origin = CGPoint(x: (CGFloat(self?.preViewSize.width ?? 0) - CGFloat(cDefaultMargin * 5)) / 2, y: (CGFloat(self?.preViewSize.height ?? 0) - CGFloat(cDefaultMargin * 5)) / 2)
|
|
|
+ self?.playerLayer.frame = self?.playerHeaderView.bounds ?? CGRect.zero
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ selectedData = itemData
|
|
|
+ }
|
|
|
+ }
|
|
|
+ isPublishEnabled()
|
|
|
+ collectionView.reloadItems(at: [indexPath])
|
|
|
+ } else {
|
|
|
+ videoData.removeAll()
|
|
|
+ self.collectionView.setContentOffset(CGPoint.zero, animated: true)
|
|
|
+ self.collectionView.reloadData()
|
|
|
+ allPhotos = categoryData[indexPath.item].categoryList
|
|
|
+ catagerySelectedIndex = indexPath
|
|
|
+ selecteBtn.setTitle(categoryData[indexPath.item].title, for: .normal)
|
|
|
+ selecteBtn.imagePosition(at: .right, space: cDefaultMargin / 2)
|
|
|
+ if !isAssetImage {
|
|
|
+ playBtn.isHidden = false
|
|
|
+ sliderView.isHidden = true
|
|
|
+ avPlayer.pause()
|
|
|
+ if selectedData != nil {
|
|
|
+ selectedData = nil
|
|
|
+ UIView.animate(withDuration: 0.5, animations: { [weak self] in
|
|
|
+ self?.playerHeaderView.frame = CGRect(x: 0, y: -(self?.preViewSize.height ?? 0) - cDevice_iPhoneNavBarAndStatusBarHei, width: self?.preViewSize.width ?? 0, height: self?.preViewSize.height ?? 0)
|
|
|
+ self?.playerHeaderView.center.x = self?.view.center.x ?? 0
|
|
|
+ self?.sliderView.frame.origin.y = self?.playerHeaderView.frame.maxY ?? 0
|
|
|
+ self?.collectionView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei)
|
|
|
+ }) { _ in
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ lastSeletedIndex = nil
|
|
|
+ isPublishEnabled()
|
|
|
+ if allPhotos.count <= 0 {
|
|
|
+ emptyRemindView.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei - cDevice_iPhoneTabBarHei)
|
|
|
+ emptyRemindView.emptyData = emptyData
|
|
|
+ emptyRemindView.isHidden = false
|
|
|
+ } else {
|
|
|
+ emptyRemindView.isHidden = true
|
|
|
+ }
|
|
|
+ self.collectionView.reloadData()
|
|
|
+ cancelClick()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ open func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt _: IndexPath) -> CGSize {
|
|
|
+ if collectionView == self.collectionView {
|
|
|
+ return CGSize(width: (cScreenWidth - cDefaultMargin) / 3, height: (cScreenWidth - cDefaultMargin) / 3)
|
|
|
+ }
|
|
|
+ return CGSize(width: collectionView.frame.width, height: cDefaultMargin * 8)
|
|
|
+ }
|
|
|
+
|
|
|
+ open func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, minimumLineSpacingForSectionAt _: Int) -> CGFloat {
|
|
|
+ if collectionView == self.collectionView {
|
|
|
+ return cDefaultMargin / 2
|
|
|
+ }
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+
|
|
|
+ open func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, minimumInteritemSpacingForSectionAt _: Int) -> CGFloat {
|
|
|
+ if collectionView == self.collectionView {
|
|
|
+ return cDefaultMargin / 2
|
|
|
+ }
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+
|
|
|
+ open func scrollViewDidScroll(_: UIScrollView) {
|
|
|
+ // 这里是不是有用的?
|
|
|
+// if bf_getCurrentViewController() is PQUploadController || bf_getCurrentViewController() is PQImageSelectedController {
|
|
|
+// if scrollView == collectionView {
|
|
|
+// updateCachedAssets()
|
|
|
+// } else {
|
|
|
+// BFLog(message: "contentOffset = \(scrollView.contentOffset),contentSize = \(scrollView.contentSize)")
|
|
|
+// if scrollView.contentOffset.y > ((scrollView.contentSize.height - scrollView.frame.height) + cDefaultMargin * 10) {
|
|
|
+// cancelClick()
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension PQUploadController {
|
|
|
+ /// 添加监听
|
|
|
+ /// - Parameter playerItem: <#playerItem description#>
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ func addPlayerItemObserver() {
|
|
|
+ playerItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 移除监听
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ func removePlayerItemObserver() {
|
|
|
+ playerItem?.removeObserver(self, forKeyPath: "status")
|
|
|
+ }
|
|
|
+
|
|
|
+ open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
|
|
|
+ if object is AVPlayerItem, keyPath == "status" {
|
|
|
+ BFLog(message: "(object as! AVPlayerItem).status = \((object as! AVPlayerItem).status.rawValue)")
|
|
|
+ BFLoadingHUB.shared.dismissHUB(superView: playerHeaderView)
|
|
|
+ switch (object as! AVPlayerItem).status {
|
|
|
+ case .unknown:
|
|
|
+ break
|
|
|
+ case .readyToPlay:
|
|
|
+ break
|
|
|
+ case .failed:
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func resetCachedAssets() {
|
|
|
+ imageManager.stopCachingImagesForAllAssets()
|
|
|
+ previousPreheatRect = .zero
|
|
|
+ }
|
|
|
+
|
|
|
+ private func updateCachedAssets() {
|
|
|
+ if allPhotos != nil, allPhotos.count <= 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ guard isViewLoaded, view.window != nil else { return }
|
|
|
+ let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
|
|
|
+ let preheatRect = visibleRect.insetBy(dx: 0, dy: -0.5 * visibleRect.height)
|
|
|
+ let delta = abs(preheatRect.midY - previousPreheatRect.midY)
|
|
|
+ guard delta > view.bounds.height / 3 else { return }
|
|
|
+ let (addedRects, removedRects) = differencesBetweenRects(previousPreheatRect, preheatRect)
|
|
|
+ let addedAssets = addedRects
|
|
|
+ .flatMap { rect in collectionView.indexPathsForElements(in: rect) }
|
|
|
+ .map { indexPath in allPhotos.object(at: indexPath.item) }
|
|
|
+ let removedAssets = removedRects
|
|
|
+ .flatMap { rect in collectionView.indexPathsForElements(in: rect) }
|
|
|
+ .map { indexPath in allPhotos.object(at: indexPath.item) }
|
|
|
+ imageManager.startCachingImages(for: addedAssets,
|
|
|
+ targetSize: itemSize, contentMode: .aspectFill, options: nil)
|
|
|
+ imageManager.stopCachingImages(for: removedAssets,
|
|
|
+ targetSize: itemSize, contentMode: .aspectFill, options: nil)
|
|
|
+
|
|
|
+ previousPreheatRect = preheatRect
|
|
|
+ }
|
|
|
+
|
|
|
+ private func differencesBetweenRects(_ old: CGRect, _ new: CGRect) -> (added: [CGRect], removed: [CGRect]) {
|
|
|
+ if old.intersects(new) {
|
|
|
+ var added = [CGRect]()
|
|
|
+ if new.maxY > old.maxY {
|
|
|
+ added += [CGRect(x: new.origin.x, y: old.maxY,
|
|
|
+ width: new.width, height: new.maxY - old.maxY)]
|
|
|
+ }
|
|
|
+ if old.minY > new.minY {
|
|
|
+ added += [CGRect(x: new.origin.x, y: new.minY,
|
|
|
+ width: new.width, height: old.minY - new.minY)]
|
|
|
+ }
|
|
|
+ var removed = [CGRect]()
|
|
|
+ if new.maxY < old.maxY {
|
|
|
+ removed += [CGRect(x: new.origin.x, y: new.maxY,
|
|
|
+ width: new.width, height: old.maxY - new.maxY)]
|
|
|
+ }
|
|
|
+ if old.minY < new.minY {
|
|
|
+ removed += [CGRect(x: new.origin.x, y: old.minY,
|
|
|
+ width: new.width, height: new.minY - old.minY)]
|
|
|
+ }
|
|
|
+ return (added, removed)
|
|
|
+ } else {
|
|
|
+ return ([new], [old])
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension PQUploadController: PHPhotoLibraryChangeObserver {
|
|
|
+ public func photoLibraryDidChange(_ changeInstance: PHChange) {
|
|
|
+ // Change notifications may be made on a background queue. Re-dispatch to the
|
|
|
+ // main queue before acting on the change as we'll be updating the UI.
|
|
|
+ DispatchQueue.main.sync { [weak self] in
|
|
|
+ // Check each of the three top-level fetches for changes.
|
|
|
+ if allPhotos != nil, changeInstance.changeDetails(for: allPhotos) != nil {
|
|
|
+ self?.categoryData.removeAll()
|
|
|
+ self?.loadPhotoData()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|