浏览代码

1.接入公共库

wenweiwei 3 年之前
父节点
当前提交
925417db60
共有 46 个文件被更改,包括 65 次插入8159 次删除
  1. 0 22
      BFFramework/Classes/BFModules/BFCategorys/BFBundle+Ext.swift
  2. 0 46
      BFFramework/Classes/BFModules/BFCategorys/BFColor+Ext.swift
  3. 0 109
      BFFramework/Classes/BFModules/BFCategorys/BFInt+Ext.swift
  4. 0 203
      BFFramework/Classes/BFModules/BFCategorys/BFString+Ext.swift
  5. 0 63
      BFFramework/Classes/BFModules/BFCategorys/BFUIButton+ext.swift
  6. 0 234
      BFFramework/Classes/BFModules/BFCategorys/BFUIImage+Ext.swift
  7. 0 490
      BFFramework/Classes/BFModules/BFCategorys/BFUIView+Ext.swift
  8. 0 176
      BFFramework/Classes/BFModules/BFCategorys/NXFundation+Ext.swift
  9. 0 392
      BFFramework/Classes/BFModules/BFCategorys/NXUI+Ext.swift
  10. 0 77
      BFFramework/Classes/BFModules/BFCategorys/NXUIColor+Ext.swift
  11. 0 32
      BFFramework/Classes/BFModules/BFCategorys/UIControl+NXCategory.h
  12. 0 68
      BFFramework/Classes/BFModules/BFCategorys/UIControl+NXCategory.m
  13. 0 174
      BFFramework/Classes/BFModules/BFDebug/NXLogger.swift
  14. 0 68
      BFFramework/Classes/BFModules/BFDebug/NXLoggerManager.swift
  15. 0 188
      BFFramework/Classes/BFModules/BFDebug/NXLoggerVC.swift
  16. 0 13
      BFFramework/Classes/BFModules/BFMacro/NXConfig.swift
  17. 0 159
      BFFramework/Classes/BFModules/BFUtility/NXAudioRecorder.swift
  18. 0 113
      BFFramework/Classes/BFModules/BFUtility/NXDeviceManager.swift
  19. 0 43
      BFFramework/Classes/BFModules/BFUtility/NXFileManager.swift
  20. 0 22
      BFFramework/Classes/BFModules/BFUtility/PQBridgeObject.h
  21. 0 56
      BFFramework/Classes/BFModules/BFUtility/PQBridgeObject.m
  22. 0 180
      BFFramework/Classes/BFModules/BFUtility/PQCreateEmptyWAV.swift
  23. 0 526
      BFFramework/Classes/BFModules/BFUtility/PQLZStringUtil.swift
  24. 0 778
      BFFramework/Classes/BFModules/BFUtility/PQPHAssetVideoParaseUtil.swift
  25. 0 95
      BFFramework/Classes/BFModules/BFUtility/PQVideoSnapshotUtil.swift
  26. 0 48
      BFFramework/Classes/BFModules/BFUtility/PQWeakTimer.swift
  27. 0 156
      BFFramework/Classes/BFModules/BFUtility/SWNetRequest.swift
  28. 0 203
      BFFramework/Classes/Base/Controller/PQBaseViewController.swift
  29. 0 184
      BFFramework/Classes/Base/Controller/PQBaseWebViewController.swift
  30. 0 46
      BFFramework/Classes/Base/Controller/PQNavigatinController.swift
  31. 0 189
      BFFramework/Classes/Base/Model/PQBaseModel.swift
  32. 0 121
      BFFramework/Classes/Base/View/PQFollowButton.swift
  33. 0 41
      BFFramework/Classes/Base/View/PQGIFImageView.swift
  34. 0 53
      BFFramework/Classes/Base/View/PQHeartAnimation.swift
  35. 0 141
      BFFramework/Classes/Base/View/PQLoadingHUB.swift
  36. 0 515
      BFFramework/Classes/Base/View/PQRemindView.swift
  37. 0 27
      BFFramework/Classes/Base/View/PQTabBar.swift
  38. 0 106
      BFFramework/Classes/Base/View/PQTextView.swift
  39. 0 813
      BFFramework/Classes/Enums/Enums.swift
  40. 0 85
      BFFramework/Classes/Utils/PQBFConfig.swift
  41. 0 804
      BFFramework/Classes/Utils/PQCommonMethodUtil.swift
  42. 0 273
      BFFramework/Classes/Utils/PQConstant.swift
  43. 4 0
      Example/BFFramework.xcodeproj/project.pbxproj
  44. 1 0
      Example/BFFramework/ViewController.swift
  45. 3 0
      Example/Podfile
  46. 57 27
      Example/Podfile.lock

+ 0 - 22
BFFramework/Classes/BFModules/BFCategorys/BFBundle+Ext.swift

@@ -1,22 +0,0 @@
-//
-//  Bundle+Ext.swift
-//  BFFramework
-//
-//  Created by ak on 2021/6/2.
-//  取 BFFramework 资源目录
-
-import Foundation
-
-extension Bundle {
-    
-    // bf main bundle url
-   public func BF_mainbundle_URL() -> URL {
-        let bundle:Bundle = Bundle.init(for: PQBaseViewController.self)
-        return bundle.url(forResource: "BFFramework", withExtension: "bundle")!
-    }
-    // bf main bundle
-    public func BF_mainbundle() -> Bundle {
-        return  Bundle.init(url: BF_mainbundle_URL())!
-    }
- 
-}

+ 0 - 46
BFFramework/Classes/BFModules/BFCategorys/BFColor+Ext.swift

@@ -1,46 +0,0 @@
-//
-//  UIColor+Ext.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/25.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-import UIKit
-
-extension UIColor {
-    public  class func hexColor(hexadecimal: String) -> UIColor {
-        var cstr = hexadecimal.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased() as NSString
-        if cstr.length < 6 {
-            return UIColor.clear
-        }
-        if cstr.hasPrefix("0X") {
-            cstr = cstr.substring(from: 2) as NSString
-        }
-        if cstr.hasPrefix("#") {
-            cstr = cstr.substring(from: 1) as NSString
-        }
-        if cstr.length != 6 {
-            return UIColor.clear
-        }
-        var range = NSRange()
-        range.location = 0
-        range.length = 2
-        // r
-        let rStr = cstr.substring(with: range)
-        // g
-        range.location = 2
-        let gStr = cstr.substring(with: range)
-        // b
-        range.location = 4
-        let bStr = cstr.substring(with: range)
-        var r: UInt32 = 0x0
-        var g: UInt32 = 0x0
-        var b: UInt32 = 0x0
-        Scanner(string: rStr).scanHexInt32(&r)
-        Scanner(string: gStr).scanHexInt32(&g)
-        Scanner(string: bStr).scanHexInt32(&b)
-        return UIColor(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: 1)
-    }
-}

+ 0 - 109
BFFramework/Classes/BFModules/BFCategorys/BFInt+Ext.swift

@@ -1,109 +0,0 @@
-//
-//  Int+Ext.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/7/20.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-
-extension Int {
-    /// 分数字格式化如413200->4,132.09
-
-    /// 是否保留2位小数
-    /// - Parameter isDecimal: <#isDecimal description#>
-    /// - Returns: <#description#>
-   public func paraseDecimalFormatterValue(isDecimal: Bool = false) -> String? {
-        let decimal = self % 100
-        let nonDecimal = self / 100
-        let formatter = NumberFormatter()
-        formatter.numberStyle = .decimal
-        if let title = formatter.string(from: NSNumber(value: nonDecimal)) {
-            if isDecimal {
-                return title + String(format: ".%02d", decimal)
-            } else {
-                return title
-            }
-        }
-        return nil
-    }
-
-    /// 改变单位为万
-    /// @param originUnit <#originUnit description#>
-    public func changeUnit() -> String {
-        var unitStr: String = ""
-        if self < 10000 {
-            unitStr = "\(self)"
-        } else if self <= 1_000_000 {
-            let divisor = pow(10.0, Double(1))
-            let decimal = ((Double(self) / 10000) * divisor).rounded() / divisor
-            unitStr = "\(decimal)万"
-        } else {
-            unitStr = "\(self / 10000)万"
-        }
-        BFLog(message: "转化单位:\(self) = \(unitStr)")
-        return unitStr
-    }
-}
-
-// MARK: - Float64 double类型扩展
-
-/// Float64 double类型扩展
-
-extension Float64 {
-    /// 时长转化为分秒 62'52"
-    /// - Returns: <#description#>
-    public func formatDurationToMS() -> String {
-        let duration = lround(self)
-        var text = ""
-        let min = duration / 60
-        let second = duration % 60
-        if min > 0, second > 0 {
-            text = "\(min)" + "\'" + "\(second)" + "\""
-        } else if min > 0 {
-            text = "\(min)" + "\'" + "0\""
-        } else {
-            text = "\(second)" + "\""
-        }
-        return text
-    }
-
-    /// 时长转化成时分秒 01:02:52
-    /// - Parameter value: <#value description#>
-    /// - Returns: <#description#>
-    public  func formatDurationToHMS() -> String {
-        var theTime = lround(self)
-        var theTime1 = 0 // 分
-        var theTime2 = 0 // 小时
-        if theTime < 60 {
-            if theTime < 10 {
-                return "00:0\(theTime)"
-            }
-            return "00:\(theTime)"
-        }
-        theTime1 = theTime / 60
-        theTime = theTime % 60
-        if theTime1 > 60 {
-            theTime2 = theTime1 / 60
-            theTime1 = theTime1 % 60
-        }
-        var result = "\(theTime)"
-        if theTime < 10 {
-            result = "0" + result
-        }
-        if theTime1 > 0 {
-            result = "\(theTime1):" + result
-            if theTime1 < 10 {
-                result = "0" + result
-            }
-        }
-        if theTime2 > 0 {
-            result = "\(theTime2):" + result
-            if theTime2 < 10 {
-                result = "0" + result
-            }
-        }
-        return result
-    }
-}

+ 0 - 203
BFFramework/Classes/BFModules/BFCategorys/BFString+Ext.swift

@@ -1,203 +0,0 @@
-//
-//  String+Ext.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/7/22.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-import MobileCoreServices
-
-extension String {
-    /// md5加密
-   public var md5: String {
-        let str = cString(using: String.Encoding.utf8)
-        let strLen = CUnsignedInt(lengthOfBytes(using: String.Encoding.utf8))
-        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
-        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
-        CC_MD5(str!, strLen, result)
-        let hash = NSMutableString()
-        for i in 0..<digestLen {
-            hash.appendFormat("%02x", result[i])
-        }
-        result.deallocate()
-        return hash as String
-    }
-    
-    // 文件后缀名
-    public  var pathExtension: String {
-        return (self as NSString).pathExtension
-    }
-
-    public func ga_widthForComment(font: UIFont, height: CGFloat = 15) -> CGFloat {
-
-        let rect = NSString(string: self).boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
-        return ceil(rect.width)
-    }
-//
-//    public  func ga_heightForComment(fontSize: CGFloat, width: CGFloat) -> CGFloat {
-//        let font = UIFont.systemFont(ofSize: fontSize)
-//        let rect = NSString(string: self).boundingRect(with: CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
-//        return ceil(rect.height)
-//    }
-//
-//    public  func ga_heightForComment(fontSize: CGFloat, width: CGFloat, maxHeight: CGFloat) -> CGFloat {
-//        let font = UIFont.systemFont(ofSize: fontSize)
-//        let rect = NSString(string: self).boundingRect(with: CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
-//        return ceil(rect.height)>maxHeight ? maxHeight : ceil(rect.height)
-//    }
- 
-
-    public  func enumerateSearchText(searchText: String?, complate: (_ idx: Int, _ range: NSRange) -> Void) {
-        if searchText == nil || (searchText?.count ?? 0) <= 0 || !contains(searchText!) {
-            return
-        }
-        let len: Int = searchText!.count
-        var loc: Int = 0
-        let subStrings: [String] = NSString(string: self).components(separatedBy: searchText!)
-        for (idx, subText) in subStrings.enumerated() {
-            loc = loc + subText.count
-            let range = NSRange(location: loc, length: len)
-            complate(idx, range)
-            loc = loc + len
-            if idx == subStrings.count - 2 {
-                break
-            }
-        }
-    }
-
-    public  func attributedTextWithSearchText(searchText: String?, textColor: UIColor, textFont: UIFont, searchTextColor: UIColor, searchTextFont: UIFont) -> NSMutableAttributedString {
-        let attbText = NSMutableAttributedString(string: self, attributes: [NSAttributedString.Key.font: textFont, NSAttributedString.Key.foregroundColor: textColor])
-        if count <= 0 || searchText == nil || (searchText?.count ?? 0) <= 0 {
-            return attbText
-        }
-        for tempStr in searchText! {
-            BFLog(message: "self = \(self),searchText = \(searchText ?? ""),tempStr = \(tempStr)")
-            enumerateSearchText(searchText: "\(tempStr)") { _, range in
-                attbText.setAttributes([NSAttributedString.Key.font: searchTextFont, NSAttributedString.Key.foregroundColor: searchTextColor], range: range)
-            }
-        }
-        return attbText
-    }
-
-    // 判断是否为空
-    public  var isSpace: Bool {
-        return allSatisfy { $0.isWhitespace }
-    }
-
-    /// 通过 文件路径/文件名/文件后缀 获取mimeType(文件媒体类型)
-    /// - Parameter pathExtension: <#pathExtension description#>
-    /// - Returns: <#description#>
-    public func mimeType() -> String {
-        if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (self as NSString).pathExtension as CFString, nil)?.takeRetainedValue() {
-            if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?
-                .takeRetainedValue()
-            {
-                return mimetype as String
-            }
-        }
-        return "application/octet-stream"
-    }
-
-    // 将原始的url编码为合法的url
-    public  func urlEncoded() -> String {
-        let encodeUrlString = addingPercentEncoding(withAllowedCharacters:
-            .urlQueryAllowed)
-        return encodeUrlString ?? ""
-    }
-
-    // 将编码后的url转换回原始的url
-    public func urlDecoded() -> String {
-        return removingPercentEncoding ?? ""
-    }
-
-    // 判断是否包含Emoji表情
-    public func isEmoji() -> Bool {
-        let numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
-        guard !numbers.contains(self) else {
-            return false
-        }
-        let tempEmoji: [Unicode.Scalar] = ["\u{26F8}", "\u{26F7}", "\u{263A}", "\u{2639}", "\u{2620}", "\u{270C}", "\u{261D}", "\u{0001F441}", "\u{0001F5E3}", "\u{0001F575}", "\u{0001F574}", "\u{26D1}", "\u{0001F576}", "\u{0001F577}", "\u{0001F54A}", "\u{0001F43F}", "\u{2618}", "\u{0001F32A}", "\u{2600}", "\u{0001F324}", "\u{0001F325}", "\u{2601}", "\u{0001F326}", "\u{0001F327}", "\u{26C8}", "\u{0001F329}", "\u{0001F328}", "\u{2744}", "\u{2603}", "\u{0001F32C}", "\u{2602}", "\u{0001F32B}", "\u{0001F336}", "\u{0001F37D}"]
-        let scalars = unicodeScalars.map { $0.value }
-        for element in scalars {
-            if let scalar = Unicode.Scalar(element) {
-                if #available(iOS 10.2, *) {
-                    if (scalar.properties.isEmoji && scalar.properties.isEmojiPresentation) || tempEmoji.contains(scalar) {
-                        return true
-                    } else {
-                        BFLog(message: "是表情==\(element),\(scalar)")
-                    }
-                }
-            }
-        }
-        return false
-    }
-
-    var isContainsEmoji: Bool {
-        for scalar in unicodeScalars {
-            switch scalar.value {
-            case 0x1F600...0x1F64F, // Emoticons
-                 0x1F300...0x1F5FF, // Misc Symbols and Pictographs
-                 0x1F680...0x1F6FF, // Transport and Map
-                 0x2600...0x26FF, // Misc symbols
-                 0x2700...0x27BF, // Dingbats
-                 0xFE00...0xFE0F: // Variation Selectors
-                return true
-            default:
-                continue
-            }
-        }
-        return false
-    }
-
-    // 是否包含表情
-    var containsEmoji: Bool {
-        for scalar in unicodeScalars {
-            switch scalar.value {
-            case
-                0x00A0...0x00AF,
-                0x2030...0x204F,
-                0x2120...0x213F,
-                0x2190...0x21AF,
-                0x2310...0x329F,
-                0x1F000...0x1F9CF:
-                return true
-            default:
-                continue
-            }
-        }
-        return false
-    }
-
-    /**
-     * 字母、数字、中文正则判断(不包括空格)
-     *注意: 因为考虑到输入习惯,许多人习惯使用九宫格,这里在正常选择全键盘输入错误的时候,进行九宫格判断,九宫格对应的是下面➋➌➍➎➏➐➑➒的字符
-     */
-    static func isInputRuleNotBlank(str: String) -> Bool {
-        let pattern = "^[a-zA-Z\\u4E00-\\u9FA5\\d]*$"
-        let pred = NSPredicate(format: "SELF MATCHES %@", pattern)
-        let isMatch = pred.evaluate(with: str)
-        if !isMatch {
-            let other = "➋➌➍➎➏➐➑➒"
-            let len = str.count
-            for i in 0..<len {
-                let tmpStr = str as NSString
-                let tmpOther = other as NSString
-                let c = tmpStr.character(at: i)
-
-                if !(isalpha(Int32(c)) > 0 || isalnum(Int32(c)) > 0 || (Int(c) == "_".hashValue) || (Int(c) == "-".hashValue) || (c >= 0x4E00 && c <= 0x9FA6) || (tmpOther.range(of: str).location != NSNotFound)) {
-                    return false
-                }
-                return true
-            }
-        }
-        return isMatch
-    }
-}
-
-extension Optional where Wrapped == String {
-    public var isSpace: Bool {
-        return self?.isSpace ?? true
-    }
-}

+ 0 - 63
BFFramework/Classes/BFModules/BFCategorys/BFUIButton+ext.swift

@@ -1,63 +0,0 @@
-//
-//  UIButton+ext.swift
-//  PQSpeed
-//
-//  Created by ak on 2020/8/14.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-/**
- UIButton图像文字同时存在时---图像相对于文字的位置
-
- - top:    图像在上
- - left:   图像在左
- - right:  图像在右
- - bottom: 图像在下
- */
-public enum PQButtonImageEdgeInsetsStyle {
-    case top, left, right, bottom
-}
-
-import Foundation
-extension UIButton {
-    public func imagePosition(at style: PQButtonImageEdgeInsetsStyle, space: CGFloat) {
-        guard let imageV = imageView else { return }
-        guard let titleL = titleLabel else { return }
-        // 获取图像的宽和高
-        let imageWidth = imageV.frame.size.width
-        let imageHeight = imageV.frame.size.height
-        // 获取文字的宽和高
-        let labelWidth = titleL.frame.size.width
-        let labelHeight = titleL.frame.size.height
-
-        var imageEdgeInsets = UIEdgeInsets.zero
-        var labelEdgeInsets = UIEdgeInsets.zero
-        // UIButton同时有图像和文字的正常状态---左图像右文字,间距为0
-        switch style {
-        case .left:
-            // 正常状态--只不过加了个间距
-            imageEdgeInsets = UIEdgeInsets(top: 0, left: -space * 0.5, bottom: 0, right: space * 0.5)
-            labelEdgeInsets = UIEdgeInsets(top: 0, left: space * 0.5, bottom: 0, right: -space * 0.5)
-        case .right:
-            // 切换位置--左文字右图像
-            // 图像:UIEdgeInsets的left是相对于UIButton的左边移动了labelWidth + space * 0.5,right相对于label的左边移动了-labelWidth - space * 0.5
-            imageEdgeInsets = UIEdgeInsets(top: 0, left: labelWidth + space * 0.5, bottom: 0, right: -labelWidth - space * 0.5)
-            labelEdgeInsets = UIEdgeInsets(top: 0, left: -imageWidth - space * 0.5, bottom: 0, right: imageWidth + space * 0.5)
-        case .top:
-            // 切换位置--上图像下文字
-            /** 图像的中心位置向右移动了labelWidth * 0.5,向上移动了-imageHeight * 0.5 - space * 0.5
-              *文字的中心位置向左移动了imageWidth * 0.5,向下移动了labelHeight*0.5+space*0.5
-             */
-            imageEdgeInsets = UIEdgeInsets(top: -(imageHeight * 0.5 - space), left: labelWidth * 0.5, bottom: imageHeight * 0.5 - space, right: -labelWidth * 0.5)
-            labelEdgeInsets = UIEdgeInsets(top: labelHeight * 0.5 + space * 2, left: -imageWidth * 0.5, bottom: -(labelHeight * 0.5 + space * 2), right: imageWidth * 0.5)
-        case .bottom:
-            // 切换位置--下图像上文字
-            /** 图像的中心位置向右移动了labelWidth * 0.5,向下移动了imageHeight * 0.5 + space * 0.5
-             *文字的中心位置向左移动了imageWidth * 0.5,向上移动了labelHeight*0.5+space*0.5
-             */
-            imageEdgeInsets = UIEdgeInsets(top: imageHeight * 0.5 + space * 0.5, left: labelWidth * 0.5, bottom: -imageHeight * 0.5 - space * 0.5, right: -labelWidth * 0.5)
-            labelEdgeInsets = UIEdgeInsets(top: -labelHeight * 0.5 - space * 0.5, left: -imageWidth * 0.5, bottom: labelHeight * 0.5 + space * 0.5, right: imageWidth * 0.5)
-        }
-        titleEdgeInsets = labelEdgeInsets
-        self.imageEdgeInsets = imageEdgeInsets
-    }
-}

+ 0 - 234
BFFramework/Classes/BFModules/BFCategorys/BFUIImage+Ext.swift

@@ -1,234 +0,0 @@
-//
-//  UIImage+Ext.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/6/19.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-
-public extension UIImage {
-    // 从BFframwork bundle 中取图片
-    func BF_Image(named: String) -> UIImage {
-        let image: UIImage = UIImage(named: named, in: Bundle().BF_mainbundle(), compatibleWith: nil) ?? UIImage()
-        return image
-    }
-
-    func cropImage(ratio: CGFloat) -> UIImage {
-        // 计算最终尺寸
-        let newSize: CGSize = CGSize(width: size.width, height: size.width * ratio)
-        // 图片绘制区域
-        var rect = CGRect.zero
-        rect.size.width = size.width
-        rect.size.height = size.height
-        rect.origin.x = (newSize.width - size.width) / 2.0
-        rect.origin.y = (newSize.height - size.height) / 2.0
-
-        UIGraphicsBeginImageContext(newSize)
-        draw(in: rect)
-        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
-        UIGraphicsEndImageContext()
-
-        return scaledImage!
-    }
-
-    func cropImage(newSize: CGSize) -> UIImage {
-        //// 图片绘制区域
-        var rect = CGRect.zero
-        rect.size.width = newSize.width
-        rect.size.height = newSize.width * (size.height / size.width)
-        // 绘制并获取最终图片
-        UIGraphicsBeginImageContext(newSize)
-        draw(in: rect)
-        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
-        UIGraphicsEndImageContext()
-
-        return scaledImage!
-    }
-
-    func imageWithImage(scaledToSize newSize: CGSize) -> UIImage {
-        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
-        draw(in: CGRect(origin: CGPoint.zero, size: newSize))
-        let newImage = UIGraphicsGetImageFromCurrentImageContext() ?? self
-        UIGraphicsEndImageContext()
-        return newImage
-    }
-
-    /// 旋转角度
-    /// - Parameter image: <#image description#>
-    /// - Returns: <#description#>
-    func rotateImage(rotate: Int, originWidth: CGFloat, originHeight: CGFloat) -> UIImage {
-        let rotate: CGFloat = CGFloat(3 * Double.pi / 2)
-        let rect = CGRect(x: 0, y: 0, width: originWidth, height: originHeight)
-        let translateX: CGFloat = -rect.size.height
-        let translateY: CGFloat = 0
-        let scaleY = rect.size.width / rect.size.height
-        let scaleX = rect.size.height / rect.size.width
-        UIGraphicsBeginImageContext(rect.size)
-        let context = UIGraphicsGetCurrentContext()
-        //        context!.translateBy(x: 0.0, y: rect.size.height)
-        //        context!.scaleBy(x: 1.0, y: -1.0)
-        context!.rotate(by: rotate)
-        context!.translateBy(x: translateX, y: translateY)
-        context!.scaleBy(x: scaleX, y: scaleY)
-        draw(in: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height))
-        return UIGraphicsGetImageFromCurrentImageContext()!
-    }
-
-    /// 生成三角图
-    /// - Parameters:
-    ///   - size: <#size description#>
-    ///   - tintColor: <#tintColor description#>
-    ///   - convert:是否倒置
-    /// - Returns: <#description#>
-    class func triangleImage(size: CGSize, tintColor: UIColor, direction: moveDirection = .moveDirectionDown) -> UIImage {
-        var startPoint: CGPoint = CGPoint.zero
-        var middlePoint: CGPoint = CGPoint.zero
-        var endPoint: CGPoint = CGPoint.zero
-        switch direction {
-        case .moveDirectionLeft:
-            startPoint = CGPoint(x: size.width, y: 0)
-            middlePoint = CGPoint(x: 0, y: size.height / 2.0)
-            endPoint = CGPoint(x: size.width, y: size.height)
-        case .moveDirectionRight:
-            startPoint = CGPoint(x: 0, y: 0)
-            middlePoint = CGPoint(x: size.width, y: size.height / 2.0)
-            endPoint = CGPoint(x: 0, y: size.height)
-        case .moveDirectionUp:
-            startPoint = CGPoint(x: 0, y: size.height)
-            middlePoint = CGPoint(x: size.width / 2.0, y: 0)
-            endPoint = CGPoint(x: size.width, y: size.height)
-        default:
-            startPoint = CGPoint(x: 0, y: 0)
-            middlePoint = CGPoint(x: size.width / 2.0, y: size.height)
-            endPoint = CGPoint(x: size.width, y: 0)
-        }
-        UIGraphicsBeginImageContextWithOptions(size, false, 0)
-        let ctx = UIGraphicsGetCurrentContext()
-        let path = UIBezierPath()
-        path.move(to: startPoint)
-        path.addLine(to: middlePoint)
-        path.addLine(to: endPoint)
-        path.close()
-        ctx?.setFillColor(tintColor.cgColor)
-        path.fill()
-        let image = UIGraphicsGetImageFromCurrentImageContext()!
-        UIGraphicsEndImageContext()
-        return image
-    }
-
-    /// 按照最短边缩放  add by ak
-    /// - Parameter maxLength: 边长最大值
-    func nx_scaleWithMaxLength(maxLength: CGFloat) -> UIImage {
-        if size.width > maxLength || size.height > maxLength {
-            var maxWidth: CGFloat = maxLength
-            var maxHeight: CGFloat = maxLength
-
-            if size.width != size.height {
-                if size.width > size.height {
-                    // 按照宽 来缩放
-                    let imageScale: CGFloat = maxLength / size.width
-
-                    maxHeight = size.height * imageScale
-                } else if size.width < size.height {
-                    let imageScale: CGFloat = maxLength / size.height
-
-                    maxWidth = size.width * imageScale
-                }
-            }
-            // 返回新的改变大小后的图片
-            return nx_scaleToSize(size: CGSize(width: maxWidth, height: maxHeight))
-        }
-
-        return self
-    }
-
-    /// 缩放到指定大小 add by ak
-    /// - Parameter size: 新的大小
-    func nx_scaleToSize(size: CGSize) -> UIImage {
-        var width: CGFloat = CGFloat(cgImage!.width)
-        var height: CGFloat = CGFloat(cgImage!.height)
-
-        let verticalRadio: CGFloat = size.height * 1.0 / height
-        let horizontalRadio: CGFloat = size.width * 1.0 / width
-
-        var radio: CGFloat = 1
-        if verticalRadio > 1, horizontalRadio > 1 {
-            radio = verticalRadio > horizontalRadio ? horizontalRadio : verticalRadio
-        } else {
-            radio = verticalRadio < horizontalRadio ? verticalRadio : horizontalRadio
-        }
-
-        width = width * radio
-        height = height * radio
-
-        let xPos: CGFloat = (size.width - width) / 2
-        let yPos: CGFloat = (size.height - height) / 2
-
-        // 创建一个bitmap的context
-        // 并把它设置成为当前正在使用的context
-        UIGraphicsBeginImageContext(size)
-
-        // 绘制改变大小的图片
-        var rect = CGRect.zero
-        rect.size.width = width
-        rect.size.height = height
-        rect.origin.x = xPos
-        rect.origin.y = yPos
-
-        draw(in: rect)
-
-        // 从当前context中创建一个改变大小后的图片
-        let scaledImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
-
-        // 使当前的context出堆栈
-        UIGraphicsEndImageContext()
-
-        // 返回新的改变大小后的图片
-        return scaledImage
-    }
-
-    // 将图片裁剪成指定比例(多余部分自动删除)let image3 = image.crop(ratio: 1) /将图片转成 1:1 比例(正方形)
-    func nxcrop(ratio: CGFloat) -> UIImage {
-        // 计算最终尺寸
-        var newSize: CGSize!
-        if size.width / size.height > ratio {
-            newSize = CGSize(width: size.height * ratio, height: size.height)
-        } else {
-            newSize = CGSize(width: size.width, height: size.width / ratio)
-        }
-
-        ////图片绘制区域
-        var rect = CGRect.zero
-        rect.size.width = size.width
-        rect.size.height = size.height
-        rect.origin.x = (newSize.width - size.width) / 2.0
-        rect.origin.y = (newSize.height - size.height) / 2.0
-
-        // 绘制并获取最终图片
-        UIGraphicsBeginImageContext(newSize)
-        draw(in: rect)
-        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
-        UIGraphicsEndImageContext()
-
-        return scaledImage!
-    }
-    
-    /// 改变图片主题颜色
-    /// - Parameters:
-    ///   - color: <#color description#>
-    ///   - blendMode: <#blendMode description#>
-    /// - Returns: <#description#>
-    func tintImage(color: UIColor, blendMode: CGBlendMode) -> UIImage? {
-        let rect = CGRect(origin: CGPoint.zero, size: size)
-        UIGraphicsBeginImageContextWithOptions(size, false, scale)
-        color.setFill()
-        UIRectFill(rect)
-        draw(in: rect, blendMode: blendMode, alpha: 1.0)
-        let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
-        UIGraphicsEndImageContext()
-        return tintedImage
-    }
-}
-

+ 0 - 490
BFFramework/Classes/BFModules/BFCategorys/BFUIView+Ext.swift

@@ -1,490 +0,0 @@
-//
-//  UICollectionView+Ext.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/6/6.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import KingfisherWebP
-import UIKit
-
-// MARK: - UIView的分类扩展
-
-/// UIView的分类扩展
-extension UIView {
-      public func addCorner(roundingCorners: UIRectCorner = .allCorners, corner: CGFloat = cDefaultMargin) {
-        if roundingCorners == .allCorners {
-            layer.cornerRadius = corner
-            layer.masksToBounds = true
-        } else {
-            let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: roundingCorners, cornerRadii: CGSize(width: corner, height: corner))
-            let cornerLayer = CAShapeLayer()
-            cornerLayer.frame = bounds
-            cornerLayer.path = path.cgPath
-            layer.mask = cornerLayer
-        }
-    }
-
-    /// 添加阴影
-    /// - Parameters:
-    ///   - color: <#color description#>
-    ///   - offset: <#offset description#>
-    /// - Returns: <#description#>
-     public func addShadowLayer(isAll: Bool = false, color: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5), offset: CGSize = CGSize(width: 1, height: 1)) {
-        layer.shadowColor = color.cgColor
-        layer.shadowOffset = offset
-        layer.shadowRadius = 0.5
-        layer.shadowOpacity = 1.0
-        if isAll {
-            layer.shadowColor = color.cgColor
-            layer.shadowOffset = CGSize.zero
-            // 设置偏移量为0,四周都有阴影
-            layer.shadowRadius = 0.5 // 阴影半径
-            layer.shadowOpacity = 0.3 // 阴影透明度
-            layer.masksToBounds = false
-            layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius).cgPath
-        }
-    }
-
-    /// 添加虚线条
-     public func addBorderToLayer(frame: CGRect? = nil) {
-        // 线条颜色
-        let borderLayer: CAShapeLayer = CAShapeLayer()
-        borderLayer.strokeColor = UIColor.hexColor(hexadecimal: "#FFFFFF").cgColor
-        borderLayer.fillColor = nil
-        borderLayer.path = UIBezierPath(rect: frame == nil ? bounds : frame!).cgPath
-        borderLayer.frame = bounds
-        borderLayer.lineWidth = 2.0
-        borderLayer.lineCap = .round
-        // 第一位是 线条长度   第二位是间距 nil时为实线
-        borderLayer.lineDashPattern = [5, 5]
-        layer.addSublayer(borderLayer)
-    }
-
-     public func animateZoom() {
-        transform = CGAffineTransform(scaleX: 0.4, y: 0.4)
-        UIView.animate(withDuration: 0.5, animations: {
-            self.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
-        }) { _ in
-            UIView.animate(withDuration: 0.5, animations: {
-                self.transform = .identity
-            }) { _ in
-            }
-        }
-    }
-
-    /// 添加抖动功能
-    /// - Parameters:
-    ///   - fromValue: <#fromValue description#>
-    ///   - toValue: <#toValue description#>
-    ///   - duration: <#duration description#>
-    ///   - repeatCount: <#repeatCount description#>
-    /// - Returns: <#description#>
-     public func shakeAnimation(_ fromValue: Float, _ toValue: Float, _ duration: Float, _: Float) {
-        layer.removeAllAnimations()
-        let shake = CABasicAnimation(keyPath: "transform.rotation.z")
-        shake.fromValue = fromValue
-        shake.toValue = toValue
-        shake.duration = CFTimeInterval(duration)
-        shake.autoreverses = true
-        shake.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
-        shake.isRemovedOnCompletion = false
-        layer.add(shake, forKey: "imageView")
-        // 增加锚点
-        layer.anchorPoint = CGPoint(x: 0.5, y: 1)
-    }
-
-    /// 添加心跳动画
-    /// - Parameters:
-    ///   - duration: <#duration description#>
-    ///   - isRepeat: <#isRepeat description#>
-    ///   - multiple: <#multiple description#>
-    /// - Returns: <#description#>
-     public func heartbeatAnimate(duration: TimeInterval, isRepeat: Bool, multiple: CGFloat) {
-        UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
-            self.transform = CGAffineTransform(scaleX: 1.0 + multiple, y: 1.0 + multiple)
-        }) { _ in
-            UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
-                self.transform = .identity
-            }) { _ in
-                UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
-                    self.transform = CGAffineTransform(scaleX: 1.0 + multiple * 2, y: 1.0 + multiple * 2)
-                }) { _ in
-                    UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
-                        self.transform = .identity
-                    }) { _ in
-                        if isRepeat {
-                            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.3) {
-                                self.heartbeatAnimate(duration: duration, isRepeat: isRepeat, multiple: multiple)
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /// 活动心跳动画
-    /// - Returns: <#description#>
-     public func activityHeartbeatAnimate() {
-        layer.removeAllAnimations()
-        UIView.animateKeyframes(withDuration: 0.45, delay: 0, options: .allowUserInteraction, animations: {
-            self.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
-        }) { _ in
-            UIView.animateKeyframes(withDuration: 0.45, delay: 0, options: .allowUserInteraction, animations: {
-                self.transform = .identity
-            }) { _ in
-                self.activityHeartbeatAnimate()
-            }
-        }
-    }
-
-    /// 活动心跳动画
-    /// - Returns: <#description#>
-     public func heartbeatAnimate() {
-        layer.removeAllAnimations()
-        UIView.animateKeyframes(withDuration: 1, delay: 0, options: .allowUserInteraction, animations: {
-            self.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
-        }) { isFinished in
-            UIView.animateKeyframes(withDuration: 1, delay: 0, options: .allowUserInteraction, animations: {
-                self.transform = .identity
-            }) { isFinished in
-                if isFinished {
-                    self.heartbeatAnimate()
-                }
-            }
-        }
-    }
-
-     public func addScaleBasicAnimation() {
-        let animation = CABasicAnimation(keyPath: "transform.scale")
-        animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
-        animation.duration = 0.5
-        animation.repeatCount = 1000
-        animation.autoreverses = true
-        animation.fromValue = 0.8
-        animation.toValue = 1.1
-        layer.add(animation, forKey: nil)
-    }
-
-     public func addScaleYBasicAnimation() {
-        let animation = CAKeyframeAnimation(keyPath: "transform.translation.y")
-        animation.duration = 0.5
-        animation.repeatCount = 100
-        animation.isRemovedOnCompletion = true
-        //        animation.
-        animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
-        layer.add(animation, forKey: nil)
-        //            CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"];
-        //            CGFloat duration = 1.f;
-        //            CGFloat height = 7.f;
-        //            CGFloat currentY = self.animationView.transform.ty;
-        //            animation.duration = duration;
-        //            animation.values = @[@(currentY),@(currentY - height/4),@(currentY - height/4*2),@(currentY - height/4*3),@(currentY - height),@(currentY - height/ 4*3),@(currentY - height/4*2),@(currentY - height/4),@(currentY)];
-        //            animation.keyTimes = @[ @(0), @(0.025), @(0.085), @(0.2), @(0.5), @(0.8), @(0.915), @(0.975), @(1) ];
-        //            animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
-        //            animation.repeatCount = HUGE_VALF;
-        //            [self.animationView.layer addAnimation:animation forKey:@"kViewShakerAnimationKey"];
-        //        }
-    }
-
-    /// 将view生成一张图片
-    /// - Returns: <#description#>
-     public func graphicsGetImage() -> UIImage? {
-        UIGraphicsBeginImageContextWithOptions(frame.size, true, 0.0)
-        layer.render(in: UIGraphicsGetCurrentContext()!)
-        let newImage = UIGraphicsGetImageFromCurrentImageContext()
-        UIGraphicsEndImageContext()
-        return newImage
-    }
-
-    /// 动画显示View
-    /// - Returns: <#description#>
-     public func showViewAnimate(duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
-        UIView.animate(withDuration: duration, animations: { [weak self] in
-            self?.frame = CGRect(x: 0, y: cScreenHeigth - self!.frame.height, width: self!.frame.width, height: self!.frame.height)
-        }) { isFinished in
-            if completion != nil {
-                completion!(isFinished)
-            }
-        }
-    }
-
-    /// 动画隐藏view
-    /// - Returns: <#description#>
-     public func dismissViewAnimate(duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
-        UIView.animate(withDuration: duration, animations: { [weak self] in
-            self?.frame = CGRect(x: 0, y: cScreenHeigth, width: self!.frame.width, height: self!.frame.height)
-        }) { isFinished in
-            if completion != nil {
-                completion!(isFinished)
-            }
-        }
-    }
-
-    /// add  by ak 添加虚线框
-    /// - Parameter color: 框色
-    /// - Parameter lineWidth: 框宽
-     public func addBorderToLayer(color: CGColor, lineWidth: CGFloat) {
-        let border = CAShapeLayer()
-
-        //  线条颜色
-        border.strokeColor = color
-        border.fillColor = nil
-
-        border.path = UIBezierPath(rect: bounds).cgPath
-
-        border.frame = bounds
-        border.lineWidth = lineWidth
-        border.lineCap = .square
-
-        //  第一位是 线条长度   第二位是间距 nil时为实线
-        border.lineDashPattern = [9, 4]
-        layer.addSublayer(border)
-    }
-}
-
-// MARK: - UICollectionView的分类扩展
-
-/// UICollectionView的分类扩展
-extension UICollectionView {
-    /// 获取当前cell
-    /// - Returns: <#description#>
-     public func visibleCell() -> UICollectionViewCell? {
-        let visibleRect = CGRect(origin: contentOffset, size: bounds.size)
-        let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
-        guard let visibleIndexPath = indexPathForItem(at: visiblePoint) else { return nil }
-        return cellForItem(at: visibleIndexPath)
-    }
-
-    /// 添加刷新组件
-    /// - Parameters:
-    ///   - scroller: <#scroller description#>
-    ///   - type: 1-头部跟尾部 2-头部 3-尾部
-     public func addRefreshView(type: REFRESH_TYPE = .REFRESH_TYPE_ALL, refreshHandle: ((_ isHeader: Bool) -> Void)?) {
-        if type == .REFRESH_TYPE_ALL || type == .REFRESH_TYPE_HEADER {
-            let header = MJRefreshNormalHeader.init {
-                if refreshHandle != nil {
-                    refreshHandle!(true)
-                }
-            }
-            header.setTitle("下拉刷新", for: .willRefresh)
-            header.setTitle("正在刷新...", for: .refreshing)
-            header.setTitle("松开刷新", for: .pulling)
-            header.setTitle("下拉刷新", for: .idle)
-            header.lastUpdatedTimeLabel?.isHidden = true
-            mj_header = header
-        }
-        if type == .REFRESH_TYPE_ALL || type == .REFRESH_TYPE_FOOTER {
-            // MJRefreshBackNormalFooter 不会附在上面
-            // MJRefreshAutoFooter 不会便宜
-            let footer = MJRefreshBackNormalFooter.init {
-                if refreshHandle != nil {
-                    refreshHandle!(false)
-                }
-            }
-            footer.setTitle("暂时没有更多了", for: .noMoreData)
-            footer.setTitle("精彩内容正在加载中...", for: .refreshing)
-            mj_footer = footer
-        }
-    }
-
-     public func indexPathsForElements(in rect: CGRect) -> [IndexPath] {
-        let allLayoutAttributes = collectionViewLayout.layoutAttributesForElements(in: rect)!
-        return allLayoutAttributes.map { $0.indexPath }
-    }
-}
-
-// MARK: - UITabBar的分类扩展
-
-/// UITabBar的分类扩展
-extension UITabBar {
-    /// 展示小红点
-    /// - Parameter index: <#index description#>
-    /// - Returns: <#description#>
-     public func showPoint(index: Int) {
-        let pointW: CGFloat = 8
-        let pointView = UIView()
-        pointView.tag = 11111 + index
-        pointView.layer.cornerRadius = pointW / 2
-        pointView.backgroundColor = UIColor.hexColor(hexadecimal: "#EE0051")
-        let percentX: CGFloat = CGFloat(Double(index) + 0.7) / CGFloat(items?.count ?? 1)
-        let pointX = ceil(percentX * frame.width)
-        let pointY = ceil(0.1 * frame.height)
-        pointView.frame = CGRect(x: pointX, y: pointY, width: pointW, height: pointW)
-        addSubview(pointView)
-    }
-
-    /// 移除小红点
-    /// - Parameter index: <#index description#>
-    /// - Returns: <#description#>
-     public func removePoint(index: Int) {
-        for item in subviews {
-            if item.tag == 11111 + index {
-                item.removeFromSuperview()
-            }
-        }
-    }
-
-    /// 展示创作视频引导
-    /// - Parameter index: <#index description#>
-    /// - Returns: <#description#>
-     public func showVideoMakeRemindView() {
-        let isOldUploadClick: String? = getUserDefaults(key: cIsUploadClick) as? String
-        let isUploadClick: String? = getUserDefaultsForJson(key: cIsUploadClick) as? String
-        let isVerticalSlip: String? = getUserDefaults(key: cIsVerticalSlip) as? String
-        if isOldUploadClick == nil && isVerticalSlip != nil && isVerticalSlip == "1", isUploadClick == nil || isUploadClick?.count ?? 0 <= 0 || isUploadClick != "2" {
-            let width: CGFloat = 275 // 275
-            let height: CGFloat = 107 // 107
-            let videoMakeRemindBtn = UIButton(frame: CGRect(x: 0, y: -height + 5, width: width, height: height))
-            videoMakeRemindBtn.tag = cVideoMakeRemindTag
-            videoMakeRemindBtn.setBackgroundImage(UIImage(named: "videomk_guide"), for: .normal)
-            addSubview(videoMakeRemindBtn)
-            videoMakeRemindBtn.center.x = center.x
-            videoMakeRemindBtn.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
-            videoMakeRemindBtn.addScaleBasicAnimation()
-            if isUploadClick == "1" {
-                saveUserDefaultsToJson(key: cIsUploadClick, value: "2")
-            } else {
-                saveUserDefaultsToJson(key: cIsUploadClick, value: "1")
-            }
-            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) { [weak self] in
-                self?.removeVideoMakeRemindView()
-            }
-        }
-    }
-
-    @objc  public func dismiss() {
-  
-    }
-
-    /// 移除创作视频引导
-    /// - Returns: <#description#>
-     public func removeVideoMakeRemindView() {
-        viewWithTag(cVideoMakeRemindTag)?.removeFromSuperview()
-    }
-}
-
-// MARK: - UILabel的分类扩展
-
-/// UILabel的分类扩展
-extension UILabel {
-    var isTruncated: Bool {
-        guard let labelText = text else {
-            return false
-        }
-
-        // 计算理论上显示所有文字需要的尺寸
-        let rect = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
-        let labelTextSize = (labelText as NSString)
-            .boundingRect(with: rect, options: .usesLineFragmentOrigin,
-                          attributes: [NSAttributedString.Key.font: font as Any], context: nil)
-
-        // 计算理论上需要的行数
-        let labelTextLines = Int(ceil(CGFloat(labelTextSize.height) / font.lineHeight))
-
-        // 实际可显示的行数
-        var labelShowLines = Int(floor(CGFloat(bounds.size.height) / font.lineHeight))
-        if numberOfLines != 0 {
-            labelShowLines = min(labelShowLines, numberOfLines)
-        }
-
-        // 比较两个行数来判断是否需要截断
-        return labelTextLines > labelShowLines
-    }
-
-    /// 添加阴影
-    /// - Parameters:
-    ///   - color: <#color description#>
-    ///   - offset: <#offset description#>
-    /// - Returns: <#description#>
-     public func addShadow(color: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5), offset: CGSize = CGSize(width: 1, height: 1)) {
-        shadowColor = color
-        shadowOffset = offset
-    }
-}
-
-extension UIImageView {
-    /// imageView加载网络图片
-    /// - Parameters:
-    ///   - url: 网络url
-     public func setNetImage(url: String?, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
-        if url == nil || (url?.count ?? 0) <= 0 {
-            BFLog(message: "设置按钮网络图片地址为空")
-            return
-        }
-        kf.setImage(with: URL(string: url!), placeholder: placeholder, options: url?.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
-
-        }) {  _ in
-        }
-    }
-
-    /// 展示加载中动画
-    /// - Returns: <#description#>
-     public func showLoadingAnimation(duration: Double = 1) {
-        let rotationAnim = CABasicAnimation(keyPath: "transform.rotation.z")
-        rotationAnim.fromValue = 0
-        rotationAnim.toValue = Double.pi * 2
-        rotationAnim.repeatCount = MAXFLOAT
-        rotationAnim.duration = duration
-        rotationAnim.isRemovedOnCompletion = false
-        layer.add(rotationAnim, forKey: nil)
-    }
-
-    /// 播放GIF
-    /// - Parameters:
-    ///   - data : 图片二进制数据
-    ///   - images: 图片
-    ///   - repeatCount: 循环次数
-    ///   - duration: 时长
-    /// - Returns: <#description#>
-     public func displayGIF(data: Data? = nil, images: [UIImage]? = nil, repeatCount: Int = Int.max, duration: Double = 1) {
-        if images != nil, (images?.count ?? 0) > 0, !isAnimating {
-            layer.removeAllAnimations()
-            stopAnimating()
-            animationImages = images
-            animationDuration = duration
-            animationRepeatCount = repeatCount
-            startAnimating()
-        } else if images == nil && data != nil {
-            PQPHAssetVideoParaseUtil.parasGIFImage(data: data!) { [weak self] _, images, duration in
-                if images != nil, (images?.count ?? 0) > 0 {
-                    self?.displayGIF(images: images!, repeatCount: repeatCount, duration: duration ?? 1)
-                }
-            }
-        }
-    }
-    
-    /// 移除
-    public func removePlayGIF() {
-        layer.removeAllAnimations()
-        stopAnimating()
-    }
-}
-
-extension UIButton {
-    /// UIButton加载网络图片
-    /// - Parameters:
-    ///   - url: 网络url
-     public func setNetImage(url: String?, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
-        if url == nil || (url?.count ?? 0) <= 0 {
-            BFLog(message: "设置按钮网络图片地址为空")
-            return
-        }
-        kf.setImage(with: URL(string: url!), for: .normal, placeholder: placeholder, options: url?.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
-
-        }) { _ in
-        }
-    }
-
-    /// UIButton加载网络背景图片
-    /// - Parameters:
-    ///   - url: 网络url
-     public func setNetBackgroundImage(url: String, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
-        kf.setBackgroundImage(with: URL(string: url), for: .normal, placeholder: placeholder, options: url.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
-
-        }) { _ in
-        }
-    }
-}

+ 0 - 176
BFFramework/Classes/BFModules/BFCategorys/NXFundation+Ext.swift

@@ -1,176 +0,0 @@
-//
-//  NXFundation+Ext.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import Foundation
-import UIKit
-
-
-public extension Date {
-    var millisecondsSince1970:Int {
-        return Int((self.timeIntervalSince1970 * 1000.0).rounded())
-    }
-    
-    var secondsSince1970:Int {
-        return Int((self.timeIntervalSince1970).rounded())
-    }
-    
-    init(milliseconds:Int) {
-        self = Date(timeIntervalSince1970: TimeInterval(milliseconds / 1000))
-    }
-    
-    func getCurrentTimeString(_ format: String = "yyyy-MM-dd HH:mm:ss") -> String {
-        let nowDate = Date()
-        let formatter = DateFormatter()
-        formatter.dateFormat = format
-        formatter.locale = Locale(identifier: "en_US_POSIX")
-        formatter.timeZone = Foundation.TimeZone(identifier: "UTC")
-        //formatter.dateStyle = .MediumStyle
-        //formatter.timeStyle = .MediumStyle
-        return formatter.string(from: nowDate)
-    }
-    
-    var iso8601: String {
-        return Formatter.iso8601.string(from: self)
-    }
-}
-
-
-public extension Formatter {
-    static let iso8601: DateFormatter = {
-        let formatter = DateFormatter()
-        formatter.calendar = Calendar(identifier: .chinese)
-        formatter.locale = Locale(identifier: "Asia/Shanghai")
-        formatter.timeZone = TimeZone(secondsFromGMT: 0)
-        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
-        return formatter
-    }()
-}
-
-public extension String {
-    var dateFromISO8601: Date? {
-        return Formatter.iso8601.date(from: self)
-    }
-    
-    func appendLineToURL(fileURL: URL) throws {
-        try (self + "\n").appendToURL(fileURL: fileURL)
-    }
-    
-    func appendToURL(fileURL: URL) throws {
-        let data = self.data(using: String.Encoding.utf8)!
-        try data.append2File(fileURL: fileURL)
-    }
-
-    ///
-    func substring(to index: Int) -> String {
-        guard let end_Index = validEndIndex(original: index) else {
-            return self
-        }
-        return String(self[startIndex..<end_Index])
-    }
-    ///
-    func substring(from index: Int) -> String {
-        guard let start_index = validStartIndex(original: index)  else {
-            return self
-        }
-        return String(self[start_index..<endIndex])
-    }
-    ///
-    func sliceString(_ range: CountableRange<Int>) -> String {
-        guard
-            let startIndex = validStartIndex(original: range.lowerBound),
-            let endIndex   = validEndIndex(original: range.upperBound),
-            startIndex <= endIndex
-            else {
-                return ""
-        }
-        return String(self[startIndex..<endIndex])
-    }
-    ///
-    func sliceString(_ range: CountableClosedRange<Int>) -> String {
-        guard
-            let start_Index = validStartIndex(original: range.lowerBound),
-            let end_Index   = validEndIndex(original: range.upperBound),
-            startIndex <= endIndex
-            else {
-                return ""
-        }
-        if endIndex.encodedOffset <= end_Index.encodedOffset {
-            return String(self[start_Index..<endIndex])
-        }
-        return String(self[start_Index...end_Index])
-    }
-    
-    private func validIndex(original: Int) -> String.Index {
-        switch original {
-        case ...startIndex.encodedOffset : return startIndex
-        case endIndex.encodedOffset...   : return endIndex
-        default                          : return index(startIndex, offsetBy: original)
-        }
-    }
-    
-    private func validStartIndex(original: Int) -> String.Index? {
-        guard original <= endIndex.encodedOffset else { return nil }
-        return validIndex(original: original)
-    }
-    
-    private func validEndIndex(original: Int) -> String.Index? {
-        guard original >= startIndex.encodedOffset else { return nil }
-        return validIndex(original: original)
-    }
-    
-    ///
-    func toDate(formatter: String) -> Date {
-        let dateFormatter = DateFormatter()
-        dateFormatter.locale = Locale.current
-        dateFormatter.dateFormat = formatter
-        let date = dateFormatter.date(from: self)
-        return date!
-    }
-    
-}
-
-extension Data {
-    func append2File(fileURL: URL) throws {
-        if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
-            defer {
-                fileHandle.closeFile()
-            }
-            fileHandle.seekToEndOfFile()
-            fileHandle.write(self)
-        }
-        else {
-            try write(to: fileURL, options: .atomic)
-        }
-    }
-}
-
-public extension UInt32 {
-    
-    var double: Double {
-        return Double(self)
-    }
-    
-}
-
-public extension UIApplication {
-    class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
-        if let navigationController = controller as? UINavigationController {
-            return topViewController(controller: navigationController.visibleViewController)
-        }
-        if let tabController = controller as? UITabBarController {
-            if let selected = tabController.selectedViewController {
-                return topViewController(controller: selected)
-            }
-        }
-        if let presented = controller?.presentedViewController {
-            return topViewController(controller: presented)
-        }
-        return controller
-    }
-}
-

+ 0 - 392
BFFramework/Classes/BFModules/BFCategorys/NXUI+Ext.swift

@@ -1,392 +0,0 @@
-//
-//  NXUI+Ext.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-public extension UIViewController {
-    func showAlert(withTitle title: String?, message: String?) {
-        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
-        let action = UIAlertAction(title: "OK", style: .cancel, handler: nil)
-        alert.addAction(action)
-        
-        present(alert, animated: true, completion: nil)
-    }
-    
-    var contentViewController: UIViewController {
-        if let navcon = self as? UINavigationController {
-            return navcon.visibleViewController ?? self
-        } else {
-            return self
-        }
-    }
-}
-
-// Shake oritention
-public enum ShakeDirection: Int {
-    case horizontal
-    case vertical
-}
-
-public extension UIView {
-    func shake(direction: ShakeDirection = .horizontal, times: Int = 5,
-                      interval: TimeInterval = 0.1, delta: CGFloat = 2,
-                      completion: (() -> Void)? = nil) {
-        UIView.animate(withDuration: interval, animations: { () -> Void in
-            switch direction {
-            case .horizontal:
-                self.layer.setAffineTransform( CGAffineTransform(translationX: delta, y: 0))
-                break
-            case .vertical:
-                self.layer.setAffineTransform( CGAffineTransform(translationX: 0, y: delta))
-                break
-            }
-        }) { (complete) -> Void in
-            if (times == 0) {
-                // last shaking finish, reset location, callback
-                UIView.animate(withDuration: interval, animations: { () -> Void in
-                    self.layer.setAffineTransform(CGAffineTransform.identity)
-                }, completion: { (complete) -> Void in
-                    completion?()
-                })
-            }
-            else {
-                // not last shaking, continue
-                self.shake(direction: direction, times: times - 1,  interval: interval,
-                           delta: delta * -1, completion:completion)
-            }
-        }
-    }
-}
-
-
-extension UIView {
-    var x: CGFloat {
-        set {
-            var frame = self.frame
-            frame.origin.x = newValue
-            self.frame = frame
-        }
-        get {
-            return self.frame.origin.x
-        }
-    }
-    
-    var y: CGFloat {
-        set {
-            var frame = self.frame
-            frame.origin.y = newValue
-            self.frame = frame
-        }
-        get {
-            return self.frame.origin.y
-        }
-    }
-    
-    var centerX: CGFloat {
-        set {
-            var center = self.center
-            center.x = newValue
-            self.center = center
-        }
-        get {
-            return self.center.x
-        }
-    }
-    
-    var centerY: CGFloat {
-        set {
-            var center = self.center
-            center.y = newValue
-            self.center = center
-        }
-        get {
-            return self.center.y
-        }
-    }
-    
-    var width: CGFloat {
-        set {
-            var frame = self.frame
-            frame.size.width = newValue
-            self.frame = frame
-        }
-        get {
-            return self.frame.size.width
-        }
-    }
-    
-    var height: CGFloat {
-        set {
-            var frame = self.frame
-            frame.size.height = newValue
-            self.frame = frame
-        }
-        get {
-            return self.frame.size.height
-        }
-    }
-    
-    var size: CGSize {
-        set {
-            var frame = self.frame
-            frame.size = newValue
-            self.frame = frame
-        }
-        get {
-            return self.frame.size
-        }
-    }
-    
-    var origin: CGPoint {
-        set {
-            var frame = self.frame
-            frame.origin = newValue
-            self.frame = frame
-        }
-        get {
-            return self.frame.origin
-        }
-    }
-    
-    var bottomY: CGFloat {
-        set {
-            var frame = self.frame
-            frame.origin.y = newValue - frame.size.height
-            self.frame = frame
-        }
-        get {
-            return self.height + self.y
-        }
-    }
-    
-    var rightX: CGFloat {
-        set {
-            var frame = self.frame
-            frame.origin.x = newValue - frame.size.width
-            self.frame = frame
-        }
-        get {
-            return self.width + self.x
-        }
-    }
-    
-    // MARK: - UIView round corner
-    ///
-    /// - Parameter cornerRadius: radius
-    func roundedCorners(cornerRadius: CGFloat) {
-        roundedCorners(cornerRadius: cornerRadius, borderWidth: 0, borderColor: nil)
-    }
-    
-    ///
-    /// - Parameters:
-    ///   - cornerRadius:
-    ///   - borderWidth:
-    ///   - borderColor:
-    func roundedCorners(cornerRadius: CGFloat?, borderWidth: CGFloat?, borderColor: UIColor?) {
-        self.layer.cornerRadius = cornerRadius!
-        self.layer.borderWidth = borderWidth!
-        self.layer.borderColor = borderColor?.cgColor
-        self.layer.masksToBounds = true
-    }
-    
-    ///
-    /// - Parameters:
-    ///   - cornerRadius:
-    ///   - rectCorner:
-    func roundedCorners(cornerRadius: CGFloat?, rectCorner: UIRectCorner?) {
-        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: rectCorner!, cornerRadii: CGSize(width: cornerRadius!, height: cornerRadius!))
-        let layer = CAShapeLayer()
-        layer.frame = self.bounds
-        layer.path = path.cgPath
-        self.layer.mask = layer
-    }
-    
-    ///
-    /// - Parameters:
-    ///   - colors:
-    ///   - locations:
-    ///   - startPoint: [0...1]
-    ///   - endPoint: [0...1]
-    func gradientColor(colors: [CGColor], locations: [NSNumber], startPoint: CGPoint, endPoint: CGPoint) {
-        let gradientLayer = CAGradientLayer()
-        gradientLayer.colors = colors
-        gradientLayer.locations = locations
-        /*
-         // vertical
-         gradientLayer.startPoint = CGPoint(x: 0, y: 0)
-         gradientLayer.endPoint = CGPoint(x: 0, y: 1)
-         */
-        gradientLayer.startPoint = startPoint
-        gradientLayer.endPoint = endPoint
-        gradientLayer.frame = self.frame
-        self.layer.insertSublayer(gradientLayer, at: 0)
-    }
-    
-    // MARK: - UIView blur
-    ///
-    /// - Parameter style: UIBlurEffectStyle
-    func addBlurEffect(style: UIBlurEffect.Style) {
-        let effect = UIBlurEffect(style: UIBlurEffect.Style.light)
-        let effectView = UIVisualEffectView(effect: effect)
-        effectView.frame = self.bounds
-        self.backgroundColor = .clear
-        self.addSubview(effectView)
-        self.sendSubviewToBack(effectView)
-    }
-}
-public extension UIView {
-    
-    /// 往当前视图添加一个子视图
-    /// - Parameters:
-    ///   - rect: 子视图大小
-    ///   - bgColor: 子视图背景色
-    /// - Returns: 子视图
-    func nx_addView(rect:CGRect = .zero,bgColor:UIColor = .white) ->UIView{
-        let view = UIView(frame: rect)
-        view.backgroundColor = bgColor
-        self.addSubview(view)
-        return view
-    }
-    
-    /// 往当前视图添加UIImageView
-    /// - Parameters:
-    ///   - image: 图片对象
-    ///   - rect: UIImageView
-    ///   - contentMode: 图片填充模式
-    /// - Returns: 图片
-     func nx_addImageView(image:UIImage?,rect:CGRect = .zero, contentMode:ContentMode = .scaleAspectFit)->UIImageView{
-        let imageView = UIImageView(frame: rect);
-        imageView.image = image
-        imageView.contentMode = contentMode
-        self.addSubview(imageView)
-        return imageView
-    }
-    
-    /// 添加文本控件
-    /// - Parameters:
-    ///   - fontSize: 文本大小
-    ///   - text: 文本
-    ///   - textColor: 文本颜色
-    ///   - bgColor: 背景颜色
-    /// - Returns: 文本控件
-    func nx_addLabel(fontSize: CGFloat, text: String, textColor: UIColor, bgColor: UIColor) -> UILabel {
-        return nx_addLabel(font: UIFont.systemFont(ofSize: fontSize),
-                        text: text,
-                        textColor: textColor,
-                        bgColor: bgColor)
-    }
-    
-    /// 添加文本控件
-    /// - Parameters:
-    ///   - font: 文本大小
-    ///   - text: 文本
-    ///   - textColor: 文本颜色
-    ///   - bgColor: 背景颜色
-    /// - Returns: 文本控件
-    func nx_addLabel(font: UIFont, text: String, textColor: UIColor, bgColor: UIColor) -> UILabel {
-        let label = UILabel(frame: .zero)
-        label.font = font
-        label.text = text
-        label.textColor = textColor
-        label.backgroundColor = bgColor
-        self.addSubview(label)
-        return label
-    }
-    
-    /// 添加按钮控件
-    /// - Parameters:
-    ///   - rect: 控件大小
-    ///   - title: 标题
-    ///   - titleColor: 标题颜色
-    ///   - font: 字体
-    ///   - image: 图片
-    ///   - bgImg: 背景图片
-    ///   - target: 事件响应者
-    ///   - action: 事件响应方法
-    ///   - event: 响应事件
-    /// - Returns: 按钮
-    func nx_addButton(rect: CGRect, title: String, titleColor: UIColor, font: UIFont, image: UIImage?, bgImg: UIImage?, target: Any?, action: Selector?, event: UIControl.Event?) -> UIButton {
-            let btn = UIButton(type: .custom)
-            btn.frame = rect
-            btn.setTitle(title, for: .normal)
-            btn.setTitle(title, for: .highlighted)
-            btn.setTitleColor(titleColor, for: .normal)
-            btn.setTitleColor(titleColor, for: .highlighted)
-            btn.setImage(image, for: .normal)
-            btn.setImage(image, for: .highlighted)
-            btn.setBackgroundImage(bgImg, for: .normal)
-            btn.setBackgroundImage(bgImg, for: .highlighted)
-            btn.titleLabel?.font = font
-            if let sel = action, let e = event {
-                btn.addTarget(target, action: sel, for: e)
-            }
-            addSubview(btn)
-            return btn
-        }
-    
-    /// 添加一个文本类型的按钮控件
-    /// - Parameters:
-    ///   - rect: 按钮大小
-    ///   - title: 文本
-    ///   - titleColor: 文本颜色
-    ///   - target: 事件响应者
-    ///   - action: 事件响应方法
-    ///   - event:响应事件
-    /// - Returns: 按钮控件
-        func nx_addButton(rect: CGRect, title: String, titleColor: UIColor, target: Any?, action: Selector?, event: UIControl.Event?) -> UIButton {
-            return nx_addButton(rect: rect,
-                             title: title,
-                             titleColor: titleColor,
-                             font: UIFont.systemFont(ofSize: 14),
-                             image: nil,
-                             bgImg: nil,
-                             target: target,
-                             action: action,
-                             event: event)
-        }
-    
-    /// 添加图片类型按钮
-    /// - Parameters:
-    ///   - rect: 按钮大小
-    ///   - image: 图片
-    ///   - target: 事件响应者
-    ///   - action: 事件响应方法
-    ///   - event: 响应事件
-    /// - Returns: 按钮控件
-        func nx_addButton(rect: CGRect, image: UIImage, target: Any?, action: Selector?, event: UIControl.Event?) -> UIButton {
-            return nx_addButton(rect: rect,
-                             title: "",
-                             titleColor: .white,
-                             font: UIFont.systemFont(ofSize: 14),
-                             image: image,
-                             bgImg: nil,
-                             target: target,
-                             action: action,
-                             event: event)
-        }
-    
-    /// 添加tableView
-    /// - Parameters:
-    ///   - rect: 大小
-    ///   - delegate: delegate对象
-    ///   - dataSource: dataSource 对象
-    /// - Returns: 表视图
-    func nx_addTableView(rect: CGRect, delegate: UITableViewDelegate?,dataSource:UITableViewDataSource?) -> UITableView {
-          let tableView = UITableView(frame: rect)
-          tableView.delegate = delegate
-          tableView.dataSource = dataSource
-          backgroundColor = .white
-          tableView.tableFooterView = UIView()
-          if #available(iOS 11.0, *) {
-              tableView.contentInsetAdjustmentBehavior = .never
-          }
-          return tableView
-      }
-
-}
- 

+ 0 - 77
BFFramework/Classes/BFModules/BFCategorys/NXUIColor+Ext.swift

@@ -1,77 +0,0 @@
-//
-//  NXUIColor+Ext.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-extension UIColor {
-    
-    // MARK: - hex (0x000000) -> UIColor
-    ///
-    /// - Parameter hex (0x000000)
-    /// - Returns: UIColor
-    class func hex(hex: Int) -> UIColor {
-        return UIColor.hex(hex: hex, alpha: 1.0)
-    }
-    ///
-    /// - Parameters:
-    /// - Returns: UIColor
-    class func hex(hex: Int, alpha: CGFloat) -> UIColor {
-        return UIColor(red: CGFloat((hex >> 16) & 0xFF)/255.0, green: CGFloat((hex >> 8) & 0xFF)/255.0, blue: CGFloat(hex & 0xFF)/255.0, alpha: alpha)
-    }
- 
-    private class func colorComponent(hex: String, start: Int, length: Int) -> CGFloat {
-        let subString = hex.sliceString(start..<(start + length))
-        let fullHex = length == 2 ? subString : (subString + subString)
-        var val: CUnsignedInt = 0
-        Scanner(string: fullHex).scanHexInt32(&val)
-        return CGFloat(val) / 255.0
-    }
-    
-    var hex: String {
-        var color = self
-        if color.cgColor.numberOfComponents < 4 {
-            let components = color.cgColor.components
-            
-            color = UIColor(red: components![0], green: components![0], blue: components![0], alpha: components![1])
-        }
-        if color.cgColor.colorSpace?.model != CGColorSpaceModel.rgb {
-            return "#FFFFFF"
-        }
-        return String(format: "#%02X%02X%02X", Int(color.cgColor.components![0]*255.0), Int(color.cgColor.components![1]*255.0), Int(color.cgColor.components![2]*255.0))
-    }
-    
-    // MARK: - RGB -> UIColor
-    class func rgba(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> UIColor {
-        return UIColor(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: alpha)
-    }
-    // MARK: - RGBA -> UIColor
-    class func rgb(red: CGFloat, green: CGFloat, blue: CGFloat) -> UIColor {
-        return rgba(red: red, green: green, blue: blue, alpha: 1.0)
-    }
-    
-    var rgba: [Int] {
-        var red: CGFloat = 0
-        var green: CGFloat = 0
-        var blue: CGFloat = 0
-        var alpha: CGFloat = 0
-        self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
-        return [Int(red*255.0), Int(green*255.0), Int(blue*255.0), Int(alpha)]
-    }
-    
-    class func randomColor() -> UIColor {
-        let red = CGFloat(arc4random()%255)
-        let green = CGFloat(arc4random()%255)
-        let blue = CGFloat(arc4random()%255)
-        let color = UIColor(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: 1.0)
-        return color
-    }
-    
-    
-    
-}
-

+ 0 - 32
BFFramework/Classes/BFModules/BFCategorys/UIControl+NXCategory.h

@@ -1,32 +0,0 @@
-//
-//  UIControl+acceptEventInterval.h
-//  NXlib
-//
-//  Created by AK on 15/9/15.
-//  Copyright (c) 2015年 AK. All rights reserved.
-//
-
-// 本类的作用
-// 防止多次连续点击事件,加一个两次点击的时间间隔,专治各种测试人员-_-!
-// 使用 addTarget:action:forControlEvents 给对象添加事件的都可以加时间间隔 如
-// UIButton、UISwitch、UITextField
-
-/*
- *	UIButton * testBtn;
- *  testBtn.uxy_acceptEventInterval = 2.5;
- */
-#import <UIKit/UIKit.h>
-
-@interface UIControl (NXCategory)
-
-/**
- *  设置重复点击加间隔。
- */
-@property(nonatomic, assign) NSTimeInterval uxy_acceptEventInterval;
-
-/**
- *  忽略本次点击。
- */
-@property(nonatomic) BOOL ignoreEvent;
-
-@end

+ 0 - 68
BFFramework/Classes/BFModules/BFCategorys/UIControl+NXCategory.m

@@ -1,68 +0,0 @@
-//
-//  UIControl+acceptEventInterval.m
-//  NXlib
-//
-//  Created by AK on 15/9/15.
-//  Copyright (c) 2015年 AK. All rights reserved.
-//
-
-#import "UIControl+NXCategory.h"
-
-#if TARGET_OS_IPHONE
-#import <objc/message.h>
-#import <objc/runtime.h>
-#else
-#import <objc/objc-class.h>
-#endif
-
-@implementation UIControl (NXCategory)
-
-static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
-static const char *UIControl_ignoreEvent = "UIControl_ignoreEvent";
-
-//改变两个方法的实现。在类第一次使用的时候回调用这个方法
-+ (void)load
-{
-    Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
-    Method b = class_getInstanceMethod(self, @selector(__uxy_sendAction:to:forEvent:));
-    //改变两个方法的实现
-    method_exchangeImplementations(a, b);  // isnt
-}
-//通过关联对象重写get和set方法
-- (NSTimeInterval)uxy_acceptEventInterval
-{
-    return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
-}
-
-- (void)setUxy_acceptEventInterval:(NSTimeInterval)uxy_acceptEventInterval
-{
-    objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(uxy_acceptEventInterval),
-                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-}
-#pragma mark 现在是否可点的get和set。通过关联对象。
-- (void)setIgnoreEvent:(BOOL)ignoreEvent
-{
-    objc_setAssociatedObject(self, UIControl_ignoreEvent, @(ignoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-}
-- (BOOL)ignoreEvent { return [objc_getAssociatedObject(self, UIControl_ignoreEvent) boolValue]; }
-- (void)__uxy_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
-{
-    if (self.ignoreEvent)
-    {
-        NSLog(@"无效点击!!!!!!!!!!");
-        return;
-    }
-    if (self.uxy_acceptEventInterval > 0)
-    {
-        self.ignoreEvent = YES;
-        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.uxy_acceptEventInterval * NSEC_PER_SEC)),
-                       dispatch_get_main_queue(), ^{
-                           self.ignoreEvent = NO;
-                       });
-    }
-
-    //调用系统实现
-    [self __uxy_sendAction:action to:target forEvent:event];
-}
-
-@end

+ 0 - 174
BFFramework/Classes/BFModules/BFDebug/NXLogger.swift

@@ -1,174 +0,0 @@
-//
-//  NXLogger.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-
-public enum NXLoggerLevel: Int {
-    case info = 1
-    case debug = 2
-    case warning = 3
-    case error = 4
-    case none = 5
-    
-    var name: String {
-        switch self {
-            case .info: return "i"
-            case .debug: return "d"
-            case .warning: return "w"
-            case .error: return "e"
-            case .none: return "N"
-        }
-    }
-}
-
-public enum LoggerOutput: String {
-    case debuggerConsole
-    case deviceConsole
-    case fileOnly
-    case debugerConsoleAndFile
-    case deviceConsoleAndFile
-}
-
-
-private let fileExtension = "txt"
-private let LOG_BUFFER_SIZE = 10
-
-public class NXLogger: NSObject {
-
-    // MARK: - Output
-    public var tag: String?
-    public var level: NXLoggerLevel = .none
-    public var ouput: LoggerOutput = .debuggerConsole
-    public var showThread: Bool = false
-    
-    // MARK: - Init
-    private let isolationQueue = DispatchQueue(label: "com.nxframework.isolation", qos: .background, attributes: .concurrent)
-    private let serialQueue = DispatchQueue(label: "com.nxframework.swiftylog")
-    private let logSubdiretory = NXFileManager.documentDirectoryURL.appendingPathComponent(fileExtension)
-
-    public static let shared = NXLogger()
-    
-    private var _data: [String] = []
-    private var data: [String] {
-        get { return isolationQueue.sync { return _data } }
-        set { isolationQueue.async(flags: .barrier) { self._data = newValue } }
-    }
-    
-    private var logUrl: URL? {
-        let fileName = "NSFrameworkSwiftyLog"
-        try? FileManager.default.createDirectory(at: logSubdiretory, withIntermediateDirectories: false)
-        let url = logSubdiretory.appendingPathComponent(fileName).appendingPathExtension(fileExtension)
-        return url
-    }
-    
-    private override init() {
-        super.init()
-     
-        NotificationCenter.default.addObserver(self, selector: #selector(appMovedToBackground), name:   UIApplication.willResignActiveNotification, object: nil)
-   
-    }
-    
-    // MARK: - Methods
-    @objc private func appMovedToBackground() {
-         self.saveAsync()
-    }
-    
-    func saveAsync() {
-        guard let url = logUrl else { return }
-        serialQueue.async { [weak self] in
-            guard let count = self?.data.count, count > 0 else { return }
-
-            var stringsData = Data()
-            
-            self?.data.forEach { (string) in
-                if let stringData = (string + "\n").data(using: String.Encoding.utf8) {
-                    stringsData.append(stringData)
-                } else {
-                    print("MutalbeData failed")
-                }
-            }
-
-            do {
-                try stringsData.append2File(fileURL: url)
-                self?.data.removeAll()
-            } catch let error as NSError {
-                print("wrote failed: \(url.absoluteString), \(error.localizedDescription)")
-            }
-        }
-    }
-    
-    func removeAllAsync() {
-        guard let url = logUrl else { return }
-        DispatchQueue.global(qos: .userInitiated).async {
-            try? FileManager.default.removeItem(at: url)
-        }
-    }
-    
-    func load() -> [String]? {
-        guard let url = logUrl else { return nil }
-        guard let strings = try? String(contentsOf: url, encoding: String.Encoding.utf8) else { return nil }
-
-        return strings.components(separatedBy: "\n")
-    }
-
-    private func log(_ level: NXLoggerLevel, message: String, currentTime: Date, fileName: String , functionName: String, lineNumber: Int, thread: Thread) {
-        
-        guard level.rawValue >= self.level.rawValue else { return }
-        
-        
-        let _fileName = fileName.split(separator: "/")
-        let text = "\(level.name)-\(showThread ? thread.description : "")[\(_fileName.last ?? "?")#\(functionName)#\(lineNumber)]\(tag ?? ""): \(message)"
-        
-        switch self.ouput {
-            case .fileOnly:
-                addToBuffer(text: "\(currentTime.iso8601) \(text)")
-            case .debuggerConsole:
-                print("\(currentTime.iso8601) \(text)")
-            case .deviceConsole:
-                NSLog(text)
-            case .debugerConsoleAndFile:
-                print("\(currentTime.iso8601) \(text)")
-                addToBuffer(text: "\(currentTime.iso8601) \(text)")
-            case .deviceConsoleAndFile:
-                NSLog(text)
-                addToBuffer(text: "\(currentTime.iso8601) \(text)")
-        }
-    }
-    
-    private func addToBuffer(text: String) {
-        isolationQueue.async(flags: .barrier) { self._data.append(text) }
-        if data.count > LOG_BUFFER_SIZE {
-            saveAsync()
-        }
-    }
-    
-}
-
-// MARK: - Output
-extension NXLogger {
-    public func i(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.info, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    public func d(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.debug, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    public func w(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.warning, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    public func e(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.error, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    
-    public func synchronize() {
-        saveAsync()
-    }
-}
-
-
-

+ 0 - 68
BFFramework/Classes/BFModules/BFDebug/NXLoggerManager.swift

@@ -1,68 +0,0 @@
-//
-//  NXLoggerManager.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-extension UIWindow {
-    open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
-        guard NXLogger.shared.level != .none else { return }
-        guard NXLogger.shared.ouput == .debugerConsoleAndFile
-            || NXLogger.shared.ouput == .deviceConsoleAndFile
-            || NXLogger.shared.ouput == .fileOnly else { return }
-        
-        NXLogger.shared.saveAsync()
-        let manager = LoggerManager()
-        manager.show()
-    }
-}
-
-protocol LoggerAction {
-    func removeAll()
-}
-
-class LoggerManager: NSObject {
-    let controller = NXLoggerVC()
-    public func show() {
-        guard let topViewController = UIApplication.topViewController() else { return }
-        guard topViewController .isKind(of: NXLoggerVC.self) == false else { return }
-        
-        controller.data = " \(loadLog())\(deviceInfo())"
-        controller.delegate = self
-        
-        topViewController.present(controller, animated: true, completion: nil)
-    }
-    
-    private func loadLog() -> String {
-        var texts: [String] = []
-        
-        guard let data = NXLogger.shared.load() else { return "" }
-        
-        data.forEach { (string) in
-            texts.append("<pre style=\"line-height:8px;\">\(string)</pre>")
-        }
-        
-        return texts.joined()
-    }
-    
-    private func deviceInfo() -> String {
-        var texts:[String] = []
-        
-        texts.append("<pre style=\"line-height:8px;\">==============================================</pre>")
-        NXDeviceManager.info().forEach { (string) in
-            texts.append("<pre style=\"line-height:8px;\">\(string)</pre>")
-        }
-        return texts.joined()
-    }
-}
-
-extension LoggerManager: LoggerAction {
-    func removeAll() {
-        NXLogger.shared.removeAllAsync()
-        controller.data = deviceInfo()
-    }
-}

+ 0 - 188
BFFramework/Classes/BFModules/BFDebug/NXLoggerVC.swift

@@ -1,188 +0,0 @@
-//
-//  NXLoggerVC.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
- 
-import UIKit
-import MessageUI
-import WebKit
-
-
-private let screenWidth = UIScreen.main.bounds.width
-private let screenHeight = UIScreen.main.bounds.height
-private let keyWindow = UIApplication.shared.keyWindow
-
-let themeColor: UIColor = UIColor.hex(hex: 0x00B3C4)
-
-class NXLoggerVC: UIViewController {
-
-    var delegate: LoggerAction?
-    
-    var data: String = "" {
-        didSet {
-            loadWebView()
-        }
-    }
-
-    var webView: WKWebView = {
-        
-        let source: String = "var meta = document.createElement('meta');" +
-            "meta.name = 'viewport';" +
-            "meta.content = 'width=device-width, initial-scale=0.6, maximum-scale=0.8, user-scalable=yes';" +
-            "var head = document.getElementsByTagName('head')[0];" + "head.appendChild(meta);";
-        let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
-        let userContentController: WKUserContentController = WKUserContentController()
-        let conf = WKWebViewConfiguration()
-        conf.userContentController = userContentController
-        userContentController.addUserScript(script)
-        let view = WKWebView(frame: CGRect.zero, configuration: conf)
-        
-        /*
-        view.scrollView.isScrollEnabled = true               // Make sure our view is interactable
-        view.scrollView.bounces = true                    // Things like this should be handled in web code
-        view.allowsBackForwardNavigationGestures = false   // Disable swiping to navigate
-         */
-        return view
-    }()
-    
-    var textView: UITextView = {
-        let view = UITextView()
-        view.isEditable = false
-        view.backgroundColor = UIColor.lightGray
-        return view
-    }()
-    
-    var btnSend: UIButton = {
-        let button = UIButton(type: .system)
-        button.backgroundColor = themeColor
-        button.setTitleColor(.white, for: .normal)
-        button.roundedCorners(cornerRadius: 5)
-        button.setTitle("Send email", for: .normal)
-        button.addTarget(self, action: #selector(btnSendPressed(_:)), for: .touchUpInside)
-        
-        return button
-    }()
-    
-    var btnRemove: UIButton = {
-        let button = UIButton(type: .system)
-        button.backgroundColor = themeColor
-        button.setTitleColor(.white, for: .normal)
-        button.roundedCorners(cornerRadius: 5)
-        button.setTitle("Remove All", for: .normal)
-        button.addTarget(self, action: #selector(btnRemovePressed(_:)), for: .touchUpInside)
-        return button
-    }()
-    var btnCancel: UIButton = {
-        let button = UIButton(type: .system)
-        button.backgroundColor = themeColor
-        button.setTitleColor(.white, for: .normal)
-        button.roundedCorners(cornerRadius: 5)
-        button.setTitle("Cancel", for: .normal)
-        button.addTarget(self, action: #selector(btnCancelPressed(_:)), for: .touchUpInside)
-        return button
-    }()
-    
-    override func viewDidLoad() {
-        super.viewDidLoad()
-
-        addSubViews()
-        
-        loadWebView()
-
-    }
-    
-    private func addSubViews() {
-        self.view.backgroundColor = UIColor.white
-        
-        [webView, btnSend, btnRemove, btnCancel].forEach { (subView: UIView) in
-            subView.translatesAutoresizingMaskIntoConstraints = false
-            view.addSubview(subView)
-        }
-        
-        let views: [String:UIView] = ["webView": webView, "btnSend": btnSend, "btnRemove": btnRemove, "btnCancel": btnCancel]
-        
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[webView]|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(16)-[btnSend]-(16)-|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(16)-[btnRemove]-(16)-|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(16)-[btnCancel]-(16)-|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[webView]-[btnSend(==32)]-[btnRemove(==32)]-[btnCancel(==32)]-(8)-|", options: [], metrics: nil, views: views))
-    }
-    
-    @objc func btnCancelPressed(_ button: UIButton) {
-        self.dismiss(animated: true, completion: nil)
-    }
-    
-    @objc func btnSendPressed(_ button: UIButton) {
-        sendEmail()
-    }
-    
-    @objc func btnRemovePressed(_ button: UIButton) {
-        delegate?.removeAll()
-    }
-    
-    private func sendEmail() {
-        guard MFMailComposeViewController.canSendMail() == true else {
-            self.showAlert(withTitle: "No email client", message: "Please configure your email client first")
-            return
-        }
-
-        let mailComposer = MFMailComposeViewController()
-        mailComposer.mailComposeDelegate = self as! MFMailComposeViewControllerDelegate
-        
-        var body = "Host App: \(Bundle.main.bundleIdentifier ?? "")\n"
-        if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
-            let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
-            body += "Host App Version: \(version).\(buildNumber)\n"
-        }
-        if let venderId = UIDevice.current.identifierForVendor {
-            body += "identifierForVendor: \(venderId)\n"
-        }
-
-        mailComposer.setSubject("Log of \(Bundle.main.bundleIdentifier ?? "")")
-        mailComposer.setMessageBody(body, isHTML: false)
-
-
-        webView.evaluateJavaScript("document.documentElement.outerHTML.toString()") { (html, error) in
-            if let string = html as? String, let data = string.data(using: String.Encoding.utf16) {
-                
-                mailComposer.addAttachmentData(data, mimeType: "html", fileName: "\(Bundle.main.bundleIdentifier ?? "log").html" )
-            } else {
-                NXLogger.shared.e("get data from webview failed")
-            }
-        }
-        /*
-        if let data = try? Data(html) {
-            mailComposer.addAttachmentData(data, mimeType: "text/txt", fileName: "SwiftyLog.txt")
-        }
-        */
-        self.present(mailComposer, animated: true, completion: nil)
-    }
-    
-    private func loadWebView() {
-        webView.loadHTMLString(data, baseURL: nil)
-    }
-}
-    
-extension NXLoggerVC: MFMailComposeViewControllerDelegate {
-    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
-        controller.dismiss(animated: true, completion: nil)
-        switch result {
-            case .cancelled:
-                self.showAlert(withTitle: "Cancel", message: "Send email canceled")
-                break
-            case .sent:
-                break
-            case .failed:
-                self.showAlert(withTitle: "Failed", message: "Send email failed")
-                break
-            case .saved:
-                break
-        @unknown default:
-            fatalError("default ")
-        }
-        self.dismiss(animated: true, completion: nil)
-    }
-}

+ 0 - 13
BFFramework/Classes/BFModules/BFMacro/NXConfig.swift

@@ -1,13 +0,0 @@
-//
-//  NXConfig.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-class NXConfig: NSObject {
-
-}

+ 0 - 159
BFFramework/Classes/BFModules/BFUtility/NXAudioRecorder.swift

@@ -1,159 +0,0 @@
-//
-import AVFoundation
-import Foundation
-//  NXAudioRecorder.swift
-//  PQSpeed
-//
-//  Created by ak on 2021/1/23.
-//  Copyright © 2021 BytesFlow. All rights reserved.
-//  本类功能:录制声音,并转换成 MP3
-//  alse see https://www.jianshu.com/p/971fff236881
-import UIKit
-
-// 录制时长
-public typealias  RecorderProgross = (_ time: Float64) -> Void
-
-public class NXAudioRecorder {
-    public let recorder: AVAudioRecorder
-
-    public var finishClosure: ((_ isSuccess: Bool, _ url: String) -> Void)? {
-        return delegateHandler.finishClosure
-    }
-
-    /// 由于AVAudioRecorderDelegate继承NSObjectProtocol 所以引入这个类处理代理避免污染主类
-    public  var delegateHandler = EditAudioRecorderDelegateHandler()
-
-    public  var recorderProgross: RecorderProgross?
-    public  var session: AVAudioSession!
-    public  var recordFilePath: String!
-
-    public  var displayLink: CADisplayLink?
-
-    /// 初始化录音器
-    /// - Parameter path: 保存的文件全路径,注意文件后缀一定要是 caf
-    /// - Throws: description
-    public init(path: String) throws {
-        // 1,判断目录文件夹是否存在
-        recordFilePath = path
-        BFLog(message: "recorder file path is \(String(describing: recordFilePath))")
-
-        // 2,参数
-        let fileURL = URL(fileURLWithPath: recordFilePath)
-        // 注意设置参数 设置不对就无法录制
-        let settings: [String: Any] = [
-            AVFormatIDKey: kAudioFormatLinearPCM,
-            AVSampleRateKey: 16000.0,
-            AVNumberOfChannelsKey: 1,
-            AVEncoderBitDepthHintKey: 16,
-//            AVLinearPCMIsFloatKey:true, // 不要打开ios 13有杂音
-            AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue, // 录音质量
-        ]
-        recorder = try AVAudioRecorder(url: fileURL, settings: settings)
-        recorder.isMeteringEnabled = true
-        recorder.delegate = delegateHandler
-        recorder.prepareToRecord()
-    }
-
-    /// 开始录制
-    public func startRecord() {
-        if recorder.isRecording {
-            BFLog(message: "正在录制中。。")
-            return
-        }
-
-        startTimer()
-
-        if AVAudioSession.sharedInstance().category != .playAndRecord {
-            do {
-                try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .defaultToSpeaker)
-                try AVAudioSession.sharedInstance().setActive(true)
-            } catch {
-                BFLog(message: error)
-            }
-        }
-
-        session = AVAudioSession.sharedInstance()
-        session.requestRecordPermission { granted in
-            if granted {
-                DispatchQueue.global().async {
-                    DispatchQueue.main.async {}
-                }
-            } else {}
-        }
-
-        recorder.record()
-    }
-
-    // 暂停录制
-    public func pauseRecord() {
-        recorder.pause()
-    }
-
-    // 停止录制
-    public func stopRecord(_ closure: @escaping (_ isSuccess: Bool, _ url: String) -> Void) {
-        if !recorder.isRecording {
-            BFLog(message: "不是录制状态")
-        }
-
-        stopTimer()
-
-        delegateHandler.finishClosure = closure
-
-        recorder.stop()
-    }
-
-    @objc func displayLinkClick(_: CADisplayLink) {
-        recorder.updateMeters()
-
-        BFLog(message: "当前录制时间长 \(String(describing: recorder.currentTime)) 波值:\(String(describing: recorder.averagePower(forChannel: 0)))")
-        if recorderProgross != nil {
-            recorderProgross!(recorder.currentTime)
-        }
-    }
-
-    // 开始计时
-    public func startTimer() {
-        if displayLink == nil {
-            // 创建对象
-            displayLink = CADisplayLink(target: self, selector: #selector(displayLinkClick(_:)))
-            // 设置触发频率 这个周期可以通过frameInterval属性设置,CADisplayLink的selector每秒调用次数=60/frameInterval。比如当frameInterval设为2,每秒调用就变成30次
-//            if #available(iOS 10.0, *) {
-//                displayLink?.preferredFramesPerSecond = 1
-//            } else {
-            displayLink?.frameInterval = 1
-//            }
-            // 加入循环
-            displayLink?.add(to: RunLoop.main, forMode: RunLoop.Mode.default)
-        }
-    }
-
-    // 停止计时
-    public  func stopTimer() {
-        if displayLink != nil {
-            displayLink?.isPaused = true
-            // 将定时器移除主循环
-            displayLink?.remove(from: RunLoop.main, forMode: RunLoop.Mode.default)
-            // 停止定时器
-            displayLink?.invalidate()
-            displayLink = nil
-        }
-    }
-}
-
-public class EditAudioRecorderDelegateHandler: NSObject {
-    public var finishClosure: ((_ flag: Bool, _ url: String) -> Void)?
-}
-
-extension EditAudioRecorderDelegateHandler: AVAudioRecorderDelegate {
-    public  func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
-        BFLog(message: "完成录音结果 is \(flag) url is \(recorder.url)")
-        if flag {
-            finishClosure?(true, recorder.url.relativePath)
-        }
-    }
-
-    public  func audioRecorderEncodeErrorDidOccur(_: AVAudioRecorder, error: Error?) {
-        guard let error = error else { return }
-        BFLog(message: error)
-    }
-}

+ 0 - 113
BFFramework/Classes/BFModules/BFUtility/NXDeviceManager.swift

@@ -1,113 +0,0 @@
-//
-//  NXDeviceManager.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-class NXDeviceManager: NSObject {
-    
-    class func info() -> [String] {
-        var data: [String] = []
-        
-        data.append("Device Name: \(deviceNameAlias())")
-        if let bundleId = Bundle.main.bundleIdentifier {
-            data.append("Bundle Identifier: \(bundleId)")
-        }
-        
-        if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
-            let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
-            data.append( "Host App Version: \(version).\(buildNumber)" )
-        }
-        
-        if let venderId = UIDevice.current.identifierForVendor {
-            data.append( "Identifier For Vendor: \(venderId)" )
-        }
-        
-        data.append("System Version: \(getSystemVersion())")
-        data.append("Model: \(platformModelString())")
-        
-//        data.append("Total Disk Space(MB): \(UIDevice.totalDiskSpaceInMB)")
-//        data.append("Free Disk Space(MB): \(UIDevice.freeDiskSpaceInMB)")
-        
-        let lastRestarted = Date(timeIntervalSince1970: TimeInterval(Date().timeIntervalSince1970 - Double(uptime())))
-        data.append("Uptime: \(uptime())/\(lastRestarted)")
-        
-        return data
-    }
-    
-    class var isIpad:Bool {
-        if #available(iOS 8.0, *) {
-            return UIScreen.main.traitCollection.userInterfaceIdiom == .pad
-        } else {
-            return UIDevice.current.userInterfaceIdiom == .pad
-        }
-    }
-    class var isIphone:Bool {
-        if #available(iOS 8.0, *) {
-            return UIScreen.main.traitCollection.userInterfaceIdiom == .phone
-        } else {
-            return UIDevice.current.userInterfaceIdiom == .phone
-        }
-    }
-    
-    ///Name of the devices, like Baudins's Iphone
-    class func deviceNameAlias() -> String {
-        return  UIDevice.current.name
-    }
-    
-    class func processorCount() -> Int {
-        return ProcessInfo.processInfo.activeProcessorCount
-    }
-    
-    //Verion of the OS, like 9.0.1
-    class func osVersion()-> String {
-        return UIDevice.current.systemVersion;
-    }
-    
-    class func platformModelString() -> String {
-        if let key = "hw.machine".cString(using: String.Encoding.utf8) {
-            var size: Int = 0
-            sysctlbyname(key, nil, &size, nil, 0)
-            var machine = [CChar](repeating: 0, count: Int(size))
-            sysctlbyname(key, &machine, &size, nil, 0)
-            return String(cString: machine)
-        }
-        return "Unknown"
-    }
-    
-    /** uptime in seconds **/
-    class func uptime()  -> Int {
-        var currentTime = time_t()
-        var bootTime    = timeval()
-        var mib         = [CTL_KERN, KERN_BOOTTIME]
-        
-        var size = MemoryLayout<timeval>.stride
-        
-        if sysctl(&mib, u_int(mib.count), &bootTime, &size, nil, 0) != -1 && bootTime.tv_sec != 0 {
-            time(&currentTime)
-            
-            if (currentTime < bootTime.tv_sec) {
-                return 0
-            }
-            
-            return  currentTime - bootTime.tv_sec
-        }
-        return 0
-    }
-    
-    class func getScreenBrightness() -> CGFloat {
-        return UIScreen.main.brightness
-    }
-    
-    class func getPhysicalMemory() -> UInt64 {
-        return ProcessInfo.processInfo.physicalMemory
-    }
-    
-    class func getSystemVersion() -> String {
-        return UIDevice.current.systemVersion
-    }
-}

+ 0 - 43
BFFramework/Classes/BFModules/BFUtility/NXFileManager.swift

@@ -1,43 +0,0 @@
-//
-//  NXFileManager.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-/*
-
-本类功能, 文件操作.(ios, mac)
-
-一,iOS目录结构说明
-1,沙盒目录结构
-├── Documents - 存储用户数据或其它应该定期备份的
-├── Library
-│   ├── Caches -
-用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息
-│   │   └── Snapshots
-│   │       └── com.youyouxingyuan.re
-│   │           ├── A85B73F0-26A8-44E4-A761-446CAB8DAB38@2x.png
-│   │           └── BFAD5885-B767-4320-9A4B-555EC881C50D@2x.png
-│   └── Preferences - 偏好设置文件 NSUserDefaults 保存的数据
-└── tmp - 这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息
-
-2,在iOS8之后,应用每一次重启,沙盒路径都动态的发生了变化但不用担心数据问题,苹果会把你上一个路径中的数据转移到你新的路径中。你上一个路径也会被苹果毫无保留的删除,只保留最新的路径。
-
-@see  <Foundation/NSPathUtilities.h>
-
-*/
-import UIKit
-
-class NXFileManager: NSObject {
-    
-    static var documentDirectoryURL: URL {
-      return try! FileManager.default.url(
-        for: .documentDirectory,
-        in: .userDomainMask,
-        appropriateFor: nil,
-        create: false
-      )
-    }
-
-}

+ 0 - 22
BFFramework/Classes/BFModules/BFUtility/PQBridgeObject.h

@@ -1,22 +0,0 @@
-//
-//  PQBridgeObject.h
-//  PQSpeed
-//
-//  Created by SanW on 2020/8/20.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#include <ifaddrs.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface PQBridgeObject : NSObject
-+ (NSString *)getByteRate;
-+ (long long) getInterfaceBytes;
-+ (NSString *)formatNetWork:(long long int)rate;
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 56
BFFramework/Classes/BFModules/BFUtility/PQBridgeObject.m

@@ -1,56 +0,0 @@
-//
-//  PQBridgeObject.m
-//  PQSpeed
-//
-//  Created by SanW on 2020/8/20.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-#import "PQBridgeObject.h"
-
-@implementation PQBridgeObject
-+ (NSString *)getByteRate {
-    long long intcurrentBytes = [PQBridgeObject getInterfaceBytes];
-    NSString *rateStr = [PQBridgeObject formatNetWork:intcurrentBytes];
-    return rateStr;
-}
-
-+ (long long) getInterfaceBytes {
-    struct ifaddrs *ifa_list = 0, *ifa;
-    if (getifaddrs(&ifa_list) == -1) {
-        return 0;
-    }
-    uint32_t iBytes = 0;
-    uint32_t oBytes = 0;
-    for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
-        if (AF_LINK != ifa->ifa_addr->sa_family)
-            continue;
-        if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING))
-            continue;
-        if (ifa->ifa_data == 0)
-            continue;
-        /* Not a loopback device. */
-        if (strncmp(ifa->ifa_name, "lo", 2)){
-            struct if_data *if_data = (struct if_data *)ifa->ifa_data;
-            iBytes += if_data->ifi_ibytes;
-            
-            oBytes += if_data->ifi_obytes;
-        }
-    }
-    freeifaddrs(ifa_list);
-    NSLog(@"\n[getInterfaceBytes-Total]%d,%d",iBytes,oBytes);
-    return (iBytes + oBytes);
-}
-
-+ (NSString *)formatNetWork:(long long int)rate {
-    if (rate < 1024) {
-        return [NSString stringWithFormat:@"%lldB/s", rate];
-    } else if (rate >= 1024 && rate < 1024 * 1024) {
-        return [NSString stringWithFormat:@"%.1fK/s", (double)rate /1024];
-    } else if (rate >= 1024 * 1024 && rate < 1024 * 1024 * 1024) {
-        return [NSString stringWithFormat:@"%.1fM/s", (double)rate / (1024*1024)];
-    } else {
-        return @"0B/s";
-    };
-}
-@end

+ 0 - 180
BFFramework/Classes/BFModules/BFUtility/PQCreateEmptyWAV.swift

@@ -1,180 +0,0 @@
-//
-//  PQCreateEmptyWAV.swift
-//  PQSpeed
-//
-//  Created by ak on 2020/9/16.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//  功能: 生成指定长度的空 WAV 文件
-/*
-    e.g.
-    let tool = LYEmptyWAV(sampleRate: 44100,
-                                channel: 1,
-                                duration: 20,
-                                bit: 16);
-
-          var documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
-          documentPath.append("/test.wav")
-          tool.createEmptyWAVFile(url: URL(fileURLWithPath: documentPath))
-
-     600 s  622028807.468433  622028844.650877
- */
-
-import UIKit
-
-import AudioToolbox
-import Foundation
-public class PQCreateEmptyWAV {
-    // 采样率
-    private var mSampleRate: Double = 44100
-
-    // 声道
-    private var mChannel: Double = 1
-    // 时长
-    private var mduration: Double = 5.0
-    // 采样位数
-    private var mbit: Double = 16
-    public init(sampleRate: Double = 44100, channel: Double = 1, duration: Double, bit: Double = 16) {
-        mSampleRate = sampleRate
-        mChannel = channel
-        mduration = duration
-        mbit = bit
-        if mduration == 0 {
-            BFLog(message: "时长为0??")
-        }
-        BFLog(message: "mSampleRate is\(mSampleRate) mChannel is \(mChannel) mduration is:\(mduration) mbit is \(mbit)")
-    }
-
-    public  func createEmptyWAVFile(url: URL, completeHander: @escaping (_ fileURL: URL?) -> Void) {
-        DispatchQueue.global().async {
-            // 数字音频文件大小(Byte) = 采样频率(Hz)× 采样时长(S)×(采样位数 / 8)× 声道数(单声道为1,立体声为2)
-//        BFLog(message: "createEmptyWAVFile 1")
-            let size = Int64(self.mSampleRate * self.mduration * (self.mbit / 8) * self.mChannel)
-
-            let bufer = Array(repeating: 0, count: Int(size))
-//        BFLog(message: "createEmptyWAVFile 2 \(size)")
-            let data = Data(bytes: bufer, count: Int(size))
-            let totalAudioLen = size
-            let totalDataLen = totalAudioLen + 44
-//        BFLog(message: "createEmptyWAVFile 3")
-            self.writewaveFileHeader(output: url,
-                                     totalAudioLen: totalAudioLen,
-                                     totalDataLen: totalDataLen,
-                                     longSampleRate: Int64(self.mSampleRate),
-                                     channels: Int(self.mChannel),
-                                     byteRate: size,
-                                     audioData: data)
-
-            DispatchQueue.main.async {
-                completeHander(url)
-            }
-        }
-    }
-    
-    public  func createEmptyWAVFile(url: URL) {
- 
-            // 数字音频文件大小(Byte) = 采样频率(Hz)× 采样时长(S)×(采样位数 / 8)× 声道数(单声道为1,立体声为2)
-//        BFLog(message: "createEmptyWAVFile 1")
-            let size = Int64(self.mSampleRate * self.mduration * (self.mbit / 8) * self.mChannel)
-
-            let bufer = Array(repeating: 0, count: Int(size))
-//        BFLog(message: "createEmptyWAVFile 2 \(size)")
-            let data = Data(bytes: bufer, count: Int(size))
-            let totalAudioLen = size
-            let totalDataLen = totalAudioLen + 44
-//        BFLog(message: "createEmptyWAVFile 3")
-            self.writewaveFileHeader(output: url,
-                                     totalAudioLen: totalAudioLen,
-                                     totalDataLen: totalDataLen,
-                                     longSampleRate: Int64(self.mSampleRate),
-                                     channels: Int(self.mChannel),
-                                     byteRate: size,
-                                     audioData: data)
-
-        
-    }
-
-
-    public  func writewaveFileHeader(output: URL, totalAudioLen: Int64,
-                             totalDataLen: Int64,
-                             longSampleRate: Int64,
-                             channels: Int,
-                             byteRate: Int64,
-                             audioData: Data)
-    {
-        BFLog(message: "createEmptyWAVFile 4")
-        var header: [UInt8] = Array(repeating: 0, count: 44)
-
-        // RIFF/WAVE header
-        header[0] = UInt8(ascii: "R")
-        header[1] = UInt8(ascii: "I")
-        header[2] = UInt8(ascii: "F")
-        header[3] = UInt8(ascii: "F")
-        header[4] = (UInt8)(totalDataLen & 0xFF)
-        header[5] = (UInt8)((totalDataLen >> 8) & 0xFF)
-        header[6] = (UInt8)((totalDataLen >> 16) & 0xFF)
-        header[7] = (UInt8)((totalDataLen >> 24) & 0xFF)
-
-        // WAVE
-        header[8] = UInt8(ascii: "W")
-        header[9] = UInt8(ascii: "A")
-        header[10] = UInt8(ascii: "V")
-        header[11] = UInt8(ascii: "E")
-
-        // 'fmt' chunk
-        header[12] = UInt8(ascii: "f")
-        header[13] = UInt8(ascii: "m")
-        header[14] = UInt8(ascii: "t")
-        header[15] = UInt8(ascii: " ")
-
-        // 4 bytes: size of 'fmt ' chunk
-        header[16] = 16
-        header[17] = 0
-        header[18] = 0
-        header[19] = 0
-
-        // format = 1
-        header[20] = 1
-        header[21] = 0
-        header[22] = UInt8(channels)
-        header[23] = 0
-
-        header[24] = (UInt8)(longSampleRate & 0xFF)
-        header[25] = (UInt8)((longSampleRate >> 8) & 0xFF)
-        header[26] = (UInt8)((longSampleRate >> 16) & 0xFF)
-        header[27] = (UInt8)((longSampleRate >> 24) & 0xFF)
-
-        header[28] = (UInt8)(byteRate & 0xFF)
-        header[29] = (UInt8)((byteRate >> 8) & 0xFF)
-        header[30] = (UInt8)((byteRate >> 16) & 0xFF)
-        header[31] = (UInt8)((byteRate >> 24) & 0xFF)
-
-        // block align
-        header[32] = UInt8(2 * 16 / 8)
-        header[33] = 0
-
-        // bits per sample
-        header[34] = 16
-        header[35] = 0
-
-        // data
-        header[36] = UInt8(ascii: "d")
-        header[37] = UInt8(ascii: "a")
-        header[38] = UInt8(ascii: "t")
-        header[39] = UInt8(ascii: "a")
-        header[40] = UInt8(totalAudioLen & 0xFF)
-        header[41] = UInt8((totalAudioLen >> 8) & 0xFF)
-        header[42] = UInt8((totalAudioLen >> 16) & 0xFF)
-        header[43] = UInt8((totalAudioLen >> 24) & 0xFF)
-
-//        guard let writeHandler = try? FileHandle(forWritingTo: output) else { return }
-        var data = Data(header)
-        data.append(audioData)
-        BFLog(message: "createEmptyWAVFile 5")
-        do {
-            try data.write(to: output, options: .atomicWrite)
-            BFLog(message: "createEmptyWAVFile 6 \(data.count)")
-        } catch {
-            BFLog(message: " write file error \(error)")
-        }
-    }
-}

+ 0 - 526
BFFramework/Classes/BFModules/BFUtility/PQLZStringUtil.swift

@@ -1,526 +0,0 @@
-import Foundation
-
-private let keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
-private let keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$"
-
-private let getCharFromInt: (Int) -> Character = { a in
-    if let scalar = Unicode.Scalar(a) {
-        return Character(scalar)
-    } else {
-        return Character(" ")
-    }
-}
-
-private var baseReserveDict = [String: [Character: Int]]()
-
-private typealias GetCharFromInt<T> = (Int) -> T
-private typealias GetNextValue = (Int) -> Int
-
-private typealias DecompressData = (value: Int, position: Int, index: Int)
-private typealias CompressContext<T> = (dict: [String: Int], dictCreate: [String: Bool], data: T, val: Int, position: Int) where T: RangeReplaceableCollection
-
-private func getBaseValue(alphabet: String, char: Character) -> Int {
-    if let charcter = baseReserveDict[alphabet]?[char] {
-        return charcter
-    } else {
-        baseReserveDict[alphabet] = [Character: Int]()
-        for (index, char) in alphabet.enumerated() {
-            baseReserveDict[alphabet]![char] = index
-        }
-
-        return baseReserveDict[alphabet]![char]!
-    }
-}
-
-public func compressToBase64(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    let result = _compress(input: input, bitPerChar: 6, charFromInt: { a in String(keyStrBase64[a]) })
-    switch result.count % 4 {
-    case 0:
-        return result
-    case 1:
-        return result + "==="
-    case 2:
-        return result + "=="
-    case 3:
-        return result + "="
-    default:
-        return ""
-    }
-}
-
-public func decompressFromBase64(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _decompress(length: input.count, resetValue: 32, nextValue: { a in getBaseValue(alphabet: keyStrBase64, char: input[a]) })
-}
-
-public func compressToUTF16(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _compress(input: input, bitPerChar: 15, charFromInt: { a in String(getCharFromInt(a + 32)) }) + " "
-}
-
-public func decompressFromUTF16(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _decompress(length: input.utf16.count, resetValue: 16384, nextValue: { i in Int(input.utf16[i]) - 32 })
-}
-
-public func compressToUInt8Array(input: String) -> [UInt8] {
-    let compressed: Data = compress(input: input)
-    var buffer = [UInt8](repeating: 0, count: compressed.count)
-
-    for i in 0..<(compressed.count / 2) {
-        buffer[i * 2] = compressed[i * 2 + 1]
-        buffer[i * 2 + 1] = compressed[i * 2]
-    }
-
-    return buffer
-}
-
-public func decompressFromUInt8Array(input: [UInt8]) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _decompress(length: input.count / 2, resetValue: 32768, nextValue: { i in
-        let lower = Int(input[i * 2]) * 256
-        let upper = Int(input[i * 2 + 1])
-        return upper + lower
-    })
-}
-
-public func compressToEncodedURIComponent(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _compress(input: input, bitPerChar: 6, charFromInt: { i in String(keyStrUriSafe[i]) })
-}
-
-public func decompressFromEncodedURIComponent(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    let replaced = input.replacingOccurrences(of: " ", with: "+")
-
-    return _decompress(length: replaced.count, resetValue: 32, nextValue: { a in getBaseValue(alphabet: keyStrUriSafe, char: input[a]) })
-}
-
-public func compress(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _compress(input: input, bitPerChar: 16, charFromInt: { a in String(getCharFromInt(a)) })
-}
-
-public func compress(input: String) -> Data {
-    guard !input.isEmpty else {
-        return Data()
-    }
-
-    return _compress(input: input, bitPerChar: 16, charFromInt: { a in
-        Data(bytes: [UInt8(a % 256), UInt8(a >> 8)])
-    })
-}
-
-// TODO: Change Generics
-private func _compress<T: RangeReplaceableCollection>(input: String, bitPerChar: Int, charFromInt: GetCharFromInt<T>) -> T {
-    guard !input.isEmpty else {
-        return T()
-    }
-
-    var value = 0
-    var wc = ""
-    var w = ""
-    var enlargeIn = 2
-    var dictSize = 3
-    var numBits = 2
-    var context = (dict: [String: Int](), dictCreate: [String: Bool](), data: T(), val: 0, position: 0)
-
-    for c in input {
-        let s = String(c)
-
-        if context.dict.index(forKey: s) == nil {
-            context.dict[s] = dictSize
-            context.dictCreate[s] = true
-            dictSize += 1
-        }
-
-        wc = w + s
-
-        if context.dict[wc] != nil {
-            w = wc
-        } else {
-            if context.dictCreate.index(forKey: w) != nil {
-                if let scalar = w.unicodeScalars.first, scalar.value < 256 {
-                    for _ in 0..<numBits {
-                        context.val <<= 1
-
-                        if context.position == bitPerChar - 1 {
-                            context.position = 0
-                            context.data += charFromInt(context.val)
-                            context.val = 0
-                        } else {
-                            context.position += 1
-                        }
-                    }
-
-                    value = Int(w.unicodeScalars.first!.value)
-
-                    for _ in 0..<8 {
-                        context.val = (context.val << 1) | (value & 1)
-
-                        if context.position == bitPerChar - 1 {
-                            context.position = 0
-                            context.data += charFromInt(context.val)
-                            context.val = 0
-                        } else {
-                            context.position += 1
-                        }
-
-                        value >>= 1
-                    }
-                } else {
-                    value = 1
-
-                    for _ in 0..<numBits {
-                        context.val = (context.val << 1) | value
-
-                        if context.position == bitPerChar - 1 {
-                            context.position = 0
-                            context.data += charFromInt(context.val)
-                            context.val = 0
-                        } else {
-                            context.position += 1
-                        }
-                        value = 0
-                    }
-
-                    value = Int(w.unicodeScalars.first!.value)
-
-                    for _ in 0..<16 {
-                        context.val = (context.val << 1) | (value & 1)
-
-                        if context.position == bitPerChar - 1 {
-                            context.position = 0
-                            context.data += charFromInt(context.val)
-                            context.val = 0
-                        } else {
-                            context.position += 1
-                        }
-
-                        value >>= 1
-                    }
-                }
-
-                enlargeIn -= 1
-
-                if enlargeIn == 0 {
-                    enlargeIn = 2 << (numBits - 1)
-                    numBits += 1
-                }
-
-                context.dictCreate.removeValue(forKey: w)
-            } else {
-                value = context.dict[w]!
-
-                for _ in 0..<numBits {
-                    context.val = (context.val << 1) | (value & 1)
-
-                    if context.position == bitPerChar - 1 {
-                        context.position = 0
-                        context.data += charFromInt(context.val)
-                        context.val = 0
-                    } else {
-                        context.position += 1
-                    }
-
-                    value >>= 1
-                }
-            }
-            enlargeIn -= 1
-
-            if enlargeIn == 0 {
-                enlargeIn = 2 << (numBits - 1)
-                numBits += 1
-            }
-            context.dict[wc] = dictSize
-            dictSize += 1
-            w = s
-        }
-    }
-
-    if w != "" {
-        if context.dictCreate.index(forKey: w) != nil {
-            if let scalar = w.unicodeScalars.first, scalar.value < 256 {
-                for _ in 0..<numBits {
-                    context.val <<= 1
-
-                    if context.position == bitPerChar - 1 {
-                        context.position = 0
-                        context.data += charFromInt(context.val)
-                        context.val = 0
-                    } else {
-                        context.position += 1
-                    }
-                }
-
-                value = Int(w.unicodeScalars.first!.value)
-
-                for _ in 0..<8 {
-                    context.val = (context.val << 1) | (value & 1)
-
-                    if context.position == bitPerChar - 1 {
-                        context.position = 0
-                        context.data += charFromInt(context.val)
-                        context.val = 0
-                    } else {
-                        context.position += 1
-                    }
-
-                    value >>= 1
-                }
-            } else {
-                value = 1
-
-                for _ in 0..<numBits {
-                    context.val = (context.val << 1) | value
-
-                    if context.position == bitPerChar - 1 {
-                        context.position = 0
-                        context.data += charFromInt(context.val)
-                        context.val = 0
-                    } else {
-                        context.position += 1
-                    }
-
-                    value = 0
-                }
-
-                value = Int(w.unicodeScalars.first!.value)
-
-                for _ in 0..<16 {
-                    context.val = (context.val << 1) | (value & 1)
-
-                    if context.position == bitPerChar - 1 {
-                        context.position = 0
-                        context.data += charFromInt(context.val)
-                        context.val = 0
-                    } else {
-                        context.position += 1
-                    }
-
-                    value >>= 1
-                }
-            }
-
-            enlargeIn -= 1
-
-            if enlargeIn == 0 {
-                enlargeIn = 2 << (numBits - 1)
-                numBits += 1
-            }
-
-            context.dictCreate.removeValue(forKey: w)
-        } else {
-            value = context.dict[w]!
-
-            for _ in 0..<numBits {
-                context.val = (context.val << 1) | (value & 1)
-
-                if context.position == bitPerChar - 1 {
-                    context.position = 0
-                    context.data += charFromInt(context.val)
-                    context.val = 0
-                } else {
-                    context.position += 1
-                }
-
-                value >>= 1
-            }
-        }
-
-        enlargeIn -= 1
-
-        if enlargeIn == 0 {
-            enlargeIn = 2 << (numBits - 1)
-            numBits += 1
-        }
-    }
-    value = 2
-
-    for _ in 0..<numBits {
-        context.val = (context.val << 1) | (value & 1)
-
-        if context.position == bitPerChar - 1 {
-            context.position = 0
-            context.data += charFromInt(context.val)
-            context.val = 0
-        } else {
-            context.position += 1
-        }
-
-        value >>= 1
-    }
-
-    while true {
-        context.val <<= 1
-
-        if context.position == bitPerChar - 1 {
-            context.data += charFromInt(context.val)
-            break
-        } else {
-            context.position += 1
-        }
-    }
-
-    return context.data
-}
-
-public func decompress(input: String) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _decompress(length: input.utf16.count, resetValue: 32768, nextValue: { i in Int(input.utf16[i]) })
-}
-
-public func decompress(input: Data) -> String {
-    guard !input.isEmpty else {
-        return ""
-    }
-
-    return _decompress(length: input.count / 2, resetValue: 32768, nextValue: { i in
-        let lower = Int(input[i * 2])
-        let upper = Int(input[i * 2 + 1]) * 256
-        return upper + lower
-    })
-}
-
-private func _decompress(length: Int, resetValue: Int, nextValue: @escaping GetNextValue) -> String {
-    var dict: [Int: String] = [0: "\u{0}", 1: "\u{1}", 2: "\u{2}"]
-    var next = 0
-    var enlargeIn = 4
-    var dictSize = 4
-    var numBits = 3
-    var bits = 0
-    var c = 0
-    var entry = ""
-    var w = ""
-    var result = ""
-    var data = (value: nextValue(0), position: resetValue, index: 1)
-
-    func _slide(data: inout DecompressData, maxpower: Int) -> Int {
-        var bits = 0
-        var power = 1
-
-        while power != maxpower {
-            let resb = data.value & data.position
-            data.position >>= 1
-
-            if data.position == 0 {
-                data.position = resetValue
-                data.value = nextValue(data.index)
-                data.index += 1
-            }
-
-            bits |= (resb > 0 ? 1 : 0) * power
-            power <<= 1
-        }
-
-        return bits
-    }
-
-    bits = _slide(data: &data, maxpower: 2 << 1)
-    next = bits
-
-    if next == 0 {
-        bits = _slide(data: &data, maxpower: 2 << 7)
-        c = bits
-    } else if next == 1 {
-        bits = _slide(data: &data, maxpower: 2 << 15)
-        c = bits
-    } else if next == 2 {
-        return ""
-    }
-
-    w = String(Unicode.Scalar(c)!)
-    dict[3] = w
-    result += w
-
-    while true {
-        guard data.index <= length else {
-            return ""
-        }
-
-        bits = _slide(data: &data, maxpower: 2 << (numBits - 1))
-        c = bits
-
-        if c == 0 {
-            bits = _slide(data: &data, maxpower: 2 << 7)
-            dict[dictSize] = String(getCharFromInt(bits))
-            dictSize += 1
-            c = dictSize - 1
-            enlargeIn -= 1
-        } else if c == 1 {
-            bits = _slide(data: &data, maxpower: 2 << 15)
-            dict[dictSize] = String(getCharFromInt(bits))
-            dictSize += 1
-            c = dictSize - 1
-            enlargeIn -= 1
-        } else if c == 2 {
-            return result
-        }
-
-        if enlargeIn == 0 {
-            enlargeIn = 2 << (numBits - 1)
-            numBits += 1
-        }
-
-        if let e = dict[c] {
-            entry = e
-        } else {
-            if c == dictSize {
-                entry = w + String(w[0])
-            } else {
-                return ""
-            }
-        }
-
-        result += entry
-        dict[dictSize] = w + String(entry[0])
-        dictSize += 1
-        enlargeIn -= 1
-        w = entry
-
-        if enlargeIn == 0 {
-            enlargeIn = 2 << (numBits - 1)
-            numBits += 1
-        }
-    }
-}
-
-extension String {
-    subscript(pos: Int) -> Character {
-        return self[String.Index(encodedOffset: pos)]
-    }
-}
-
-extension String.UTF16View {
-    subscript(pos: Int) -> Unicode.UTF16.CodeUnit {
-        return self[String.UTF16View.Index(encodedOffset: pos)]
-    }
-}

+ 0 - 778
BFFramework/Classes/BFModules/BFUtility/PQPHAssetVideoParaseUtil.swift

@@ -1,778 +0,0 @@
-//
-//  PQPHAssetVideoParaseUtil.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/8/3.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import CoreServices
-import Photos
-import UIKit
-
-var currentExportSession: AVAssetExportSession?
-open class PQPHAssetVideoParaseUtil: NSObject {
-    static var imagesOptions: PHImageRequestOptions = {
-        let imagesOptions = PHImageRequestOptions()
-        imagesOptions.isSynchronous = false
-        imagesOptions.deliveryMode = .fastFormat
-        imagesOptions.resizeMode = .fast
-        imagesOptions.version = .current
-        return imagesOptions
-    }()
-
-    static var singleImageOptions: PHImageRequestOptions = {
-        let singleImageOptions = PHImageRequestOptions()
-        singleImageOptions.isSynchronous = true
-        singleImageOptions.isNetworkAccessAllowed = true
-        singleImageOptions.deliveryMode = .highQualityFormat
-        singleImageOptions.resizeMode = .none
-        singleImageOptions.version = .current
-        return singleImageOptions
-    }()
-
-    static var videoRequestOptions: PHVideoRequestOptions = {
-        let videoRequestOptions = PHVideoRequestOptions()
-        // 解决慢动作视频返回AVComposition而不是AVURLAsset
-//        videoRequestOptions.version = .original
-        videoRequestOptions.version = .current
-        // 下载iCloud视频
-        videoRequestOptions.isNetworkAccessAllowed = true
-        videoRequestOptions.deliveryMode = .mediumQualityFormat
-        return videoRequestOptions
-    }()
-
-    /// PHAsset解析为AVPlayerItem
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func parasToAVPlayerItem(phAsset: PHAsset, isHighQuality: Bool = false, resultHandler: @escaping (AVPlayerItem?, Float64, [AnyHashable: Any]?) -> Void) {
-        PHImageManager().requestPlayerItem(forVideo: phAsset, options: videoRequestOptions) { playerItem, info in
-            if isHighQuality, (playerItem?.asset as? AVURLAsset)?.url.absoluteString.components(separatedBy: "/").last?.contains(".medium.") ?? false {
-                let tempVideoOptions = PHVideoRequestOptions()
-                tempVideoOptions.version = .original
-                // 下载iCloud视频
-                tempVideoOptions.isNetworkAccessAllowed = true
-                tempVideoOptions.deliveryMode = .highQualityFormat
-                tempVideoOptions.progressHandler = { progress, error, pointer, info in
-                    BFLog(message: "导出playerItem-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-                }
-                PHImageManager().requestPlayerItem(forVideo: phAsset, options: tempVideoOptions) { playerItem, info in
-                    let size = try! (playerItem?.asset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                    BFLog(message: "size = \(String(describing: size))")
-                    resultHandler(playerItem, Float64(size?.fileSize ?? 0), info)
-                }
-            } else {
-                let size = try! (playerItem?.asset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                BFLog(message: "size = \(String(describing: size))")
-                resultHandler(playerItem, Float64(size?.fileSize ?? 0), info)
-            }
-        }
-    }
-
-    /// PHAsset解析为AVAsset
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func parasToAVAsset(phAsset: PHAsset, isHighQuality: Bool = true, resultHandler: @escaping (AVAsset?, Int, AVAudioMix?, [AnyHashable: Any]?) -> Void) {
-        PHImageManager.default().requestAVAsset(forVideo: phAsset, options: videoRequestOptions) { avAsset, audioMix, info in
-            if isHighQuality, (avAsset as? AVURLAsset)?.url.absoluteString.components(separatedBy: "/").last?.contains(".medium.") ?? false {
-                let tempVideoOptions = PHVideoRequestOptions()
-                tempVideoOptions.version = .original
-                // 下载iCloud视频
-                tempVideoOptions.isNetworkAccessAllowed = true
-                tempVideoOptions.deliveryMode = .highQualityFormat
-                tempVideoOptions.progressHandler = { progress, error, pointer, info in
-                    BFLog(message: "导出playerItem-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-                }
-                PHImageManager.default().requestAVAsset(forVideo: phAsset, options: tempVideoOptions) { tempAvAsset, tempAudioMix, tempInfo in
-                    let size = try! (tempAvAsset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                    BFLog(message: "size = \(String(describing: size))")
-                    resultHandler(tempAvAsset, size?.fileSize ?? 0, tempAudioMix, tempInfo)
-                }
-            } else {
-                let size = try! (avAsset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                resultHandler(avAsset, size?.fileSize ?? 0, audioMix, info)
-                BFLog(message: "size = \(String(describing: size))")
-            }
-        }
-    }
-
-    /// PHAsset 转码为.mp4保存本地
-    /// - Parameters:
-    ///   - phAsset: <#phAsset description#>
-    ///   - isAdjustRotationAngle: 是否调整旋转角度
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func exportPHAssetToMP4(phAsset: PHAsset, isAdjustRotationAngle: Bool = true, isCancelCurrentExport: Bool = false, deliveryMode: PHVideoRequestOptionsDeliveryMode? = .automatic, resultHandler: @escaping (_ phAsset: PHAsset, _ aVAsset: AVAsset?, _ filePath: String?, _ errorMsg: String?) -> Void) {
-        BFLog(message: "导出相册视频-开始导出:phAsset = \(phAsset)")
-        if isCancelCurrentExport {
-            currentExportSession?.cancelExport()
-        }
-        PQPHAssetVideoParaseUtil.parasToAVAsset(phAsset: phAsset) { avAsset, fileSize, _, _ in
-            if avAsset is AVURLAsset {
-                // 创建目录
-                createDirectory(path: photoLibraryDirectory)
-                let fileName = (avAsset as! AVURLAsset).url.absoluteString
-                let filePath = photoLibraryDirectory + fileName.md5.md5 + ".mp4"
-                let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                    BFLog(message: "导出相册视频-已经导出完成:\(filePath)")
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, filePath, nil)
-                    }
-                } else {
-                    let tempExportSession = PQSingletoMemoryUtil.shared.allExportSession[phAsset]
-                    if tempExportSession != nil {
-                        BFLog(message: "导出相册视频-正在导出")
-                        return
-                    }
-                    BFLog(message: "导出相册视频-未导出视频过,开始导出:phAsset = \(phAsset)")
-                    // 删除以创建地址
-                    if FileManager.default.fileExists(atPath: filePath) {
-                        do {
-                            try FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-                        } catch {
-                            BFLog(message: "导出相册视频-error == \(error)")
-                        }
-                    }
-                    let requestOptions = PHVideoRequestOptions()
-                    // 解决慢动作视频返回AVComposition而不是AVURLAsset
-                    //        videoRequestOptions.version = .original
-                    requestOptions.version = .current
-                    // 下载iCloud视频
-                    requestOptions.isNetworkAccessAllowed = false
-                    requestOptions.progressHandler = { progress, error, pointer, info in
-                        BFLog(message: "导出相册视频-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-                    }
-                    requestOptions.deliveryMode = deliveryMode ?? .automatic
-                    PHImageManager.default().requestExportSession(forVideo: phAsset, options: requestOptions, exportPreset: (deliveryMode == .automatic || deliveryMode == .mediumQualityFormat) ? AVAssetExportPresetMediumQuality : (deliveryMode == .highQualityFormat ? AVAssetExportPresetHighestQuality : AVAssetExportPresetLowQuality), resultHandler: { avAssetExportSession, _ in
-                        BFLog(message: "导出相册视频-请求到导出 avAssetExportSession = \(String(describing: avAssetExportSession))")
-                        currentExportSession = avAssetExportSession
-                        if avAssetExportSession != nil {
-                            PQSingletoMemoryUtil.shared.allExportSession[phAsset] = avAssetExportSession!
-                        }
-                        avAssetExportSession?.outputURL = NSURL(fileURLWithPath: filePath) as URL
-                        avAssetExportSession?.shouldOptimizeForNetworkUse = true
-                        avAssetExportSession?.outputFileType = .mp4
-                        if isAdjustRotationAngle {
-                            let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: avAsset!)
-                            // mdf by ak 统一导出的视频为30FPS
-                            var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
-                            var mixedTransform: CGAffineTransform = CGAffineTransform()
-                            let videoComposition = AVMutableVideoComposition()
-                            videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
-                            let tracks = avAsset?.tracks(withMediaType: .video)
-                            let firstTrack = tracks?.first
-
-                            videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-
-                            mixedTransform = centerTranslate.rotated(by: 0)
-
-                            if rotationAngle == 90 {
-                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.height ?? 0, y: 0)
-                                mixedTransform = centerTranslate.rotated(by: .pi / 2)
-                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                            } else if rotationAngle == 180 {
-                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.width ?? 0, y: firstTrack?.naturalSize.height ?? 0)
-                                mixedTransform = centerTranslate.rotated(by: .pi)
-                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-                            } else if rotationAngle == 270 {
-                                centerTranslate = CGAffineTransform(translationX: 0, y: firstTrack?.naturalSize.width ?? 0)
-                                mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
-                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                            }
-                            let roateInstruction = AVMutableVideoCompositionInstruction()
-                            roateInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: avAsset?.duration ?? CMTime.zero)
-                            if firstTrack != nil {
-                                let layRoateInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
-                                layRoateInstruction.setTransform(mixedTransform, at: CMTime.zero)
-                                roateInstruction.layerInstructions = [layRoateInstruction]
-                                videoComposition.instructions = [roateInstruction]
-                                avAssetExportSession?.videoComposition = videoComposition
-                            } else {
-                                BFLog(message: "firstTrack is error !!!")
-                            }
-                        }
-                        avAssetExportSession?.exportAsynchronously(completionHandler: {
-                            BFLog(message: "导出相册视频-progress = \(avAssetExportSession?.progress ?? 0),status = \(String(describing: avAssetExportSession?.status))")
-                            switch avAssetExportSession?.status {
-                            case .unknown:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                                }
-                                avAssetExportSession?.cancelExport()
-                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-发生未知错误:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                            case .waiting:
-                                BFLog(message: "导出相册视频-等待导出mp4:\(filePath)")
-                            case .exporting:
-                                BFLog(message: "导出相册视频-导出相册视频中...:\(filePath)")
-                            case .completed:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, filePath, nil)
-                                }
-                                avAssetExportSession?.cancelExport()
-                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-导出完成:\(filePath)")
-                            case .failed:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                                }
-                                avAssetExportSession?.cancelExport()
-                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-导出失败:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                            case .cancelled:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                                }
-                                avAssetExportSession?.cancelExport()
-                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-取消导出:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                            default:
-                                break
-                            }
-                        })
-                    })
-                }
-            } else if avAsset is AVComposition {
-                BFLog(message: "导出相册视频-是AVComposition = \(String(describing: avAsset))")
-                let assetResources = PHAssetResource.assetResources(for: phAsset)
-                var resource: PHAssetResource?
-                for assetRes in assetResources {
-                    if assetRes.type == .video || assetRes.type == .pairedVideo {
-                        resource = assetRes
-                    }
-                }
-                if phAsset.mediaType == .video, resource != nil {
-                    let fileName = (resource?.originalFilename ?? "") + (resource?.assetLocalIdentifier ?? "") + (resource?.uniformTypeIdentifier ?? "")
-                    let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-                    let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                    if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                        DispatchQueue.main.async {
-                            resultHandler(phAsset, avAsset, filePath, nil)
-                        }
-                    } else {
-                        PHAssetResourceManager.default().writeData(for: resource!, toFile: URL(fileURLWithPath: filePath), options: nil) { error in
-                            DispatchQueue.main.async {
-                                resultHandler(phAsset, avAsset, error == nil ? filePath : nil, nil)
-                            }
-                        }
-                    }
-                } else {
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, nil, nil)
-                    }
-                }
-            } else {
-                DispatchQueue.main.async {
-                    resultHandler(phAsset, avAsset, nil, nil)
-                }
-            }
-        }
-    }
-
-    /// PHAsset 转码为.mp4保存本地
-    /// - Parameters:
-    ///   - phAsset: <#phAsset description#>
-    ///   - isAdjustRotationAngle: 是否调整旋转角度
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func writePHAssetDataToMP4(phAsset: PHAsset, isAdjustRotationAngle _: Bool = true, isCancelCurrentExport: Bool = false, deliveryMode _: PHVideoRequestOptionsDeliveryMode? = .automatic, resultHandler: @escaping (_ phAsset: PHAsset, _ aVAsset: AVAsset?, _ filePath: String?, _ errorMsg: String?) -> Void) {
-        BFLog(message: "导出相册视频-开始导出:phAsset = \(phAsset)")
-        if isCancelCurrentExport {
-            currentExportSession?.cancelExport()
-        }
-        PQPHAssetVideoParaseUtil.parasToAVAsset(phAsset: phAsset) { avAsset, fileSize, _, _ in
-            if avAsset is AVURLAsset {
-                // 创建目录
-                createDirectory(path: photoLibraryDirectory)
-                let fileName = (avAsset as! AVURLAsset).url.absoluteString
-                let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-                let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                    BFLog(message: "导出相册视频-已经导出完成:\(filePath)")
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, filePath, nil)
-                    }
-                } else {
-                    let tempExportSession = PQSingletoMemoryUtil.shared.allExportSession[phAsset]
-                    if tempExportSession != nil {
-                        BFLog(message: "导出相册视频-正在导出")
-                        return
-                    }
-                    BFLog(message: "导出相册视频-未导出视频过,开始导出:phAsset = \(phAsset)")
-                    // 删除以创建地址
-                    if FileManager.default.fileExists(atPath: filePath) {
-                        do {
-                            try FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-                        } catch {
-                            BFLog(message: "导出相册视频-error == \(error)")
-                        }
-                    }
-                    do {
-                        try FileManager.default.copyItem(at: (avAsset as! AVURLAsset).url, to: URL(fileURLWithPath: filePath))
-                    } catch {
-                        BFLog(message: "导出相册视频-error == \(error)")
-                    }
-
-//                    NSError *error;
-//                            AVURLAsset *avurlasset = (AVURLAsset*)asset;
-//                            NSURL *fileURL = [NSURL fileURLWithPath:savePath];
-//
-//                            if ([[NSFileManager defaultManager] copyItemAtURL:avurlasset.URL toURL:fileURL error:&error]) {
-//                                CBLog(@"保存成功");
-//                                dispatch_async(dispatch_get_main_queue(), ^{
-//                                    if (result) {
-//                                        result(savePath,[savePath lastPathComponent]);
-//                                    }
-//                                });
-//                            }else{
-//                                CBLog(@"error=%@",error);
-//                                [[NSFileManager defaultManager]removeItemAtPath:savePath error:nil];
-//                                dispatch_async(dispatch_get_main_queue(), ^{
-//                                    failure(error.description);
-//                                });
-//                            }
-//                    let requestOptions = PHVideoRequestOptions()
-//                    // 解决慢动作视频返回AVComposition而不是AVURLAsset
-//                    //        videoRequestOptions.version = .original
-//                    requestOptions.version = .current
-//                    // 下载iCloud视频
-//                    requestOptions.isNetworkAccessAllowed = false
-//                    requestOptions.progressHandler = { progress, error, pointer, info in
-//                        BFLog(message: "导出相册视频-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-//                    }
-//                    requestOptions.deliveryMode = deliveryMode ?? .automatic
-
-//                    PHImageManager.default().requestExportSession(forVideo: phAsset, options: requestOptions, exportPreset: (deliveryMode == .automatic || deliveryMode == .mediumQualityFormat) ? AVAssetExportPreset1920x1080 :(deliveryMode == .highQualityFormat ? AVAssetExportPresetHighestQuality : AVAssetExportPresetLowQuality) , resultHandler: { avAssetExportSession, _ in
-//                        BFLog(message: "导出相册视频-请求到导出 avAssetExportSession = \(avAssetExportSession)")
-//                        currentExportSession = avAssetExportSession
-//                        if avAssetExportSession != nil {
-//                            PQSingletoMemoryUtil.shared.allExportSession[phAsset] = avAssetExportSession!
-//                        }
-//                        avAssetExportSession?.outputURL = NSURL(fileURLWithPath: filePath) as URL
-//                        avAssetExportSession?.shouldOptimizeForNetworkUse = true
-//                        avAssetExportSession?.outputFileType = .mp4
-//                        if isAdjustRotationAngle {
-//                            let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: avAsset!)
-//                            // mdf by ak 统一导出的视频为30FPS
-//                            var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
-//                            var mixedTransform: CGAffineTransform = CGAffineTransform()
-//                            let videoComposition = AVMutableVideoComposition()
-//                            videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
-//                            let tracks = avAsset?.tracks(withMediaType: .video)
-//                            let firstTrack = tracks?.first
-//
-//                            videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-//
-//                            mixedTransform = centerTranslate.rotated(by: 0)
-//
-//                            if rotationAngle == 90 {
-//                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.height ?? 0, y: 0)
-//                                mixedTransform = centerTranslate.rotated(by: .pi / 2)
-//                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-//                            } else if rotationAngle == 180 {
-//                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.width ?? 0, y: firstTrack?.naturalSize.height ?? 0)
-//                                mixedTransform = centerTranslate.rotated(by: .pi)
-//                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-//                            } else if rotationAngle == 270 {
-//                                centerTranslate = CGAffineTransform(translationX: 0, y: firstTrack?.naturalSize.width ?? 0)
-//                                mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
-//                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-//                            }
-//                            let roateInstruction = AVMutableVideoCompositionInstruction()
-//                            roateInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: avAsset?.duration ?? CMTime.zero)
-//                            if firstTrack != nil {
-//                                let layRoateInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
-//                                layRoateInstruction.setTransform(mixedTransform, at: CMTime.zero)
-//                                roateInstruction.layerInstructions = [layRoateInstruction]
-//                                videoComposition.instructions = [roateInstruction]
-//                                avAssetExportSession?.videoComposition = videoComposition
-//                            } else {
-//                                BFLog(message: "firstTrack is error !!!")
-//                            }
-//                        }
-//                        avAssetExportSession?.shouldOptimizeForNetworkUse = true
-//                        avAssetExportSession?.exportAsynchronously(completionHandler: {
-//                            BFLog(message: "导出相册视频-progress = \(avAssetExportSession?.progress ?? 0),status = \(String(describing: avAssetExportSession?.status))")
-//                            switch avAssetExportSession?.status {
-//                            case .unknown:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-发生未知错误:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-//                            case .waiting:
-//                                BFLog(message: "导出相册视频-等待导出mp4:\(filePath)")
-//                            case .exporting:
-//                                BFLog(message: "导出相册视频-导出相册视频中...:\(filePath)")
-//                            case .completed:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, filePath, nil)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-导出完成:\(filePath)")
-//                            case .failed:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-导出失败:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-//                            case .cancelled:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-取消导出:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-//                            default:
-//                                break
-//                            }
-//                        })
-//                    })
-                }
-            } else if avAsset is AVComposition {
-                BFLog(message: "导出相册视频-是AVComposition = \(String(describing: avAsset))")
-                let assetResources = PHAssetResource.assetResources(for: phAsset)
-                var resource: PHAssetResource?
-                for assetRes in assetResources {
-                    if assetRes.type == .video || assetRes.type == .pairedVideo {
-                        resource = assetRes
-                    }
-                }
-                if phAsset.mediaType == .video, resource != nil {
-                    let fileName = (resource?.originalFilename ?? "") + (resource?.assetLocalIdentifier ?? "") + (resource?.uniformTypeIdentifier ?? "")
-                    let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-                    let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                    if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                        DispatchQueue.main.async {
-                            resultHandler(phAsset, avAsset, filePath, nil)
-                        }
-                    } else {
-                        PHAssetResourceManager.default().writeData(for: resource!, toFile: URL(fileURLWithPath: filePath), options: nil) { error in
-                            DispatchQueue.main.async {
-                                resultHandler(phAsset, avAsset, error == nil ? filePath : nil, nil)
-                            }
-                        }
-                    }
-                } else {
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, nil, nil)
-                    }
-                }
-            } else {
-                DispatchQueue.main.async {
-                    resultHandler(phAsset, avAsset, nil, nil)
-                }
-            }
-        }
-    }
-
-    /// 导出相册视频
-    /// - Parameters:
-    ///   - aVAsset: <#aVAsset description#>
-    ///   - isAdjustRotationAngle: <#isAdjustRotationAngle description#>
-    ///   - resultHandler: <#resultHandler description#>
-    public class func exportAVAssetToMP4(aVAsset: AVURLAsset, isAdjustRotationAngle: Bool = true, resultHandler: @escaping (_ aVAsset: AVURLAsset?, _ filePath: String?, _ errorMsg: String?) -> Void) {
-        currentExportSession?.cancelExport()
-        BFLog(message: "开始导出相册视频:url = \(aVAsset.url.absoluteString)")
-        // 创建目录
-        createDirectory(path: photoLibraryDirectory)
-        let fileName = aVAsset.url.absoluteString
-        let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-        let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-        let fileSize = try! aVAsset.url.resourceValues(forKeys: [.fileSizeKey]).fileSize ?? 0
-        if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-            DispatchQueue.main.async {
-                resultHandler(aVAsset, filePath, nil)
-            }
-        } else {
-            BFLog(message: "未导出视频过,开始导出:aVAsset = \(aVAsset)")
-            // 删除以创建地址
-            try? FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-            let avAssetExportSession = AVAssetExportSession(asset: aVAsset, presetName: AVAssetExportPreset1280x720)
-            currentExportSession = avAssetExportSession
-            avAssetExportSession?.outputURL = NSURL(fileURLWithPath: filePath) as URL
-            avAssetExportSession?.shouldOptimizeForNetworkUse = false
-            avAssetExportSession?.outputFileType = .mp4
-            if isAdjustRotationAngle {
-                let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: aVAsset)
-                // mdf by ak 统一导出的视频为30FPS
-                var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
-                var mixedTransform: CGAffineTransform = CGAffineTransform()
-                let videoComposition = AVMutableVideoComposition()
-                videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
-                let tracks = aVAsset.tracks(withMediaType: .video)
-                let firstTrack = tracks.first
-                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-
-                mixedTransform = centerTranslate.rotated(by: 0)
-
-                if rotationAngle == 90 {
-                    centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.height ?? 0, y: 0)
-                    mixedTransform = centerTranslate.rotated(by: .pi / 2)
-                    videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                } else if rotationAngle == 180 {
-                    centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.width ?? 0, y: firstTrack?.naturalSize.height ?? 0)
-                    mixedTransform = centerTranslate.rotated(by: .pi)
-                    videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-                } else if rotationAngle == 270 {
-                    centerTranslate = CGAffineTransform(translationX: 0, y: firstTrack?.naturalSize.width ?? 0)
-                    mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
-                    videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                }
-                let roateInstruction = AVMutableVideoCompositionInstruction()
-                roateInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: aVAsset.duration)
-                let layRoateInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
-                layRoateInstruction.setTransform(mixedTransform, at: CMTime.zero)
-                roateInstruction.layerInstructions = [layRoateInstruction]
-                videoComposition.instructions = [roateInstruction]
-                avAssetExportSession?.videoComposition = videoComposition
-            }
-
-            avAssetExportSession?.shouldOptimizeForNetworkUse = true
-            avAssetExportSession?.exportAsynchronously(completionHandler: {
-                BFLog(message: "导出相册视频progress = \(avAssetExportSession?.progress ?? 0)")
-                switch avAssetExportSession?.status {
-                case .unknown:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                    }
-                    BFLog(message: "导出相册视频发生未知错误:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                case .waiting:
-                    BFLog(message: "等待导出mp4:\(filePath)")
-                case .exporting:
-                    BFLog(message: "导出相册视频中...:\(filePath)")
-                case .completed:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, filePath, nil)
-                    }
-                    BFLog(message: "导出相册视频完成:\(filePath)")
-                case .failed:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                    }
-                    BFLog(message: "导出相册视频失败:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                case .cancelled:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                    }
-                    BFLog(message: "取消导出相册视频:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                default:
-                    break
-                }
-            })
-        }
-    }
-
-    /// 获取视频资源的旋转角度
-    /// - Parameter assert: <#assert description#>
-    /// - Returns: <#description#>
-    public class func videoRotationAngle(assert: AVAsset) -> Int {
-        var rotationAngle: Int = 0
-
-        let tracks = assert.tracks(withMediaType: .video)
-        if tracks.count > 0 {
-            let firstTrack = tracks.first
-            let transform = firstTrack?.preferredTransform
-            if transform?.a == 0, transform?.b == 1.0, transform?.c == -1.0, transform?.d == 0 {
-                rotationAngle = 90
-            } else if transform?.a == -1.0, transform?.b == 0, transform?.c == 0, transform?.d == -1.0 {
-                rotationAngle = 180
-            } else if transform?.a == 0, transform?.b == -1.0, transform?.c == 1.0, transform?.d == 0 {
-                rotationAngle = 270
-            } else if transform?.a == 1.0, transform?.b == 0, transform?.c == 0, transform?.d == 1.0 {
-                rotationAngle = 0
-            }
-        }
-        return rotationAngle
-    }
-
-    /// 裁剪背景音乐并导出
-    /// - Parameters:
-    ///   - url: 原始地址
-    ///   - startTime: 开始时间
-    ///   - endTime: 结束时间
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func cutAudioToLocal(url: String, startTime: Float, endTime: Float, resultHandler: @escaping (_ url: String, _ filePath: String?, _ startTime: Float, _ endTime: Float, _ errorMsg: String?) -> Void) {
-        // 创建目录
-        createDirectory(path: bgMusicDirectory)
-        let filePath = bgMusicDirectory + url.md5 + ".mp3"
-        let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-        if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > 0 {
-            DispatchQueue.main.async {
-                resultHandler(url, filePath, startTime, endTime, nil)
-            }
-        } else {
-            // 删除以创建地址
-            try? FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-            let audioAsset = AVURLAsset(url: URL(string: url)!)
-            audioAsset.loadValuesAsynchronously(forKeys: ["duration", "tracks"]) {
-                let status = audioAsset.statusOfValue(forKey: "tracks", error: nil)
-                switch status {
-                case .loaded: // 加载完成
-                    // AVAssetExportPresetPassthrough /AVAssetExportPresetAppleM4A
-                    let exportSession = AVAssetExportSession(asset: audioAsset, presetName: AVAssetExportPresetHighestQuality)
-                    exportSession?.outputURL = URL(fileURLWithPath: filePath)
-                    exportSession?.outputFileType = .mp3
-                    exportSession?.timeRange = CMTimeRange(start: CMTime(seconds: Double(startTime), preferredTimescale: 1000), end: CMTime(seconds: Double(endTime), preferredTimescale: 1000))
-                    exportSession?.exportAsynchronously(completionHandler: {
-                        switch exportSession?.status {
-                        case .waiting:
-                            BFLog(message: "等待导出mp3:\(filePath)")
-                        case .exporting:
-                            BFLog(message: "导出中...:\(filePath)")
-                        case .completed:
-                            DispatchQueue.main.async {
-                                resultHandler(url, filePath, startTime, endTime, nil)
-                            }
-                            BFLog(message: "导出完成:\(filePath)")
-
-                        case .cancelled, .failed, .unknown:
-                            DispatchQueue.main.async {
-                                resultHandler(url, nil, startTime, endTime, exportSession?.error?.localizedDescription)
-                            }
-                            BFLog(message: "导出失败:\(filePath),\(exportSession?.error?.localizedDescription ?? "")")
-                        default:
-                            break
-                        }
-                    })
-                case .loading:
-                    BFLog(message: "加载中...:\(url)")
-                case .failed, .cancelled, .unknown:
-                    DispatchQueue.main.async {
-                        resultHandler(url, nil, startTime, endTime, "导出失败")
-                    }
-                default:
-                    break
-                }
-            }
-        }
-    }
-
-    /// 创建本地保存地址
-    /// - Parameters:
-    ///   - sourceFilePath: <#sourceFilePath description#>
-    ///   - completeHandle: <#completeHandle description#>
-    /// - Returns: <#description#>
-    public class func createLocalFile(sourceFilePath: String, completeHandle: (_ isFileExists: Bool, _ isCreateSuccess: Bool, _ filePath: String) -> Void) {
-        let cLocalPath = NSString(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!).appendingPathComponent("\(sourceFilePath.md5).mp4")
-        if FileManager.default.fileExists(atPath: cLocalPath) {
-            BFLog(message: "文件已经存在:\(cLocalPath)")
-            completeHandle(true, false, cLocalPath)
-        } else {
-            let result = FileManager.default.createFile(atPath: cLocalPath, contents: nil, attributes: nil)
-            BFLog(message: "文件创建:\(cLocalPath),\(result)")
-            completeHandle(false, result, cLocalPath)
-        }
-    }
-
-    /// 获取图库图片
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - itemSize: <#itemSize description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func requestAssetImage(asset: PHAsset, itemSize: CGSize, resultHandler: @escaping (UIImage?, [AnyHashable: Any]?) -> Void) {
-        PHCachingImageManager().requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: imagesOptions, resultHandler: { image, info in
-            BFLog(message: "info = \(info ?? [:])")
-            if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0" {
-                resultHandler(image, info)
-            }
-        })
-    }
-
-    /// 获取图库原图
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func requestAssetOringinImage(asset: PHAsset, resultHandler: @escaping (_ isGIF: Bool, _ data: Data?, UIImage?, [AnyHashable: Any]?) -> Void) {
-        PHCachingImageManager().requestImageData(for: asset, options: singleImageOptions) { data, _, _, info in
-            var image: UIImage?
-            if data != nil {
-                image = UIImage(data: data!)
-            }
-            if info?.keys.contains("PHImageFileUTIKey") ?? false, "\(info?["PHImageFileUTIKey"] ?? "")" == "com.compuserve.gif" {
-                resultHandler(true, data, image, info)
-            } else {
-                resultHandler(false, data, image, info)
-            }
-        }
-    }
-
-    /// 获取gif帧跟时长
-    /// - Parameters:
-    ///   - data: <#data description#>
-    ///   - isRenderingTemplate
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func parasGIFImage(data: Data, isRenderingColor: UIColor? = nil, resultHandler: @escaping (_ data: Data, _ images: [UIImage]?, _ duration: Double?) -> Void) {
-        let info: [String: Any] = [
-            kCGImageSourceShouldCache as String: true,
-            kCGImageSourceTypeIdentifierHint as String: kUTTypeGIF,
-        ]
-        guard let imageSource = CGImageSourceCreateWithData(data as CFData, info as CFDictionary) else {
-            resultHandler(data, nil, nil)
-            BFLog(message: "获取gifimageSource 失败")
-            return
-        }
-        // 获取帧数
-        let frameCount = CGImageSourceGetCount(imageSource)
-        var gifDuration = 0.0
-        var images = [UIImage]()
-        for i in 0 ..< frameCount {
-            // 取出索引对应的图片
-            guard let imageRef = CGImageSourceCreateImageAtIndex(imageSource, i, info as CFDictionary) else {
-                BFLog(message: "取出对应的图片失败")
-                return
-            }
-            if frameCount == 1 {
-                // 单帧
-                gifDuration = .infinity
-            } else {
-                // 1.获取gif没帧的时间间隔
-                // 获取到该帧图片的属性字典
-                guard let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, i, nil) as? [String: Any] else {
-                    BFLog(message: "取出对应的图片属性失败")
-                    return
-                }
-                // 获取该帧图片中的GIF相关的属性字典
-                guard let gifInfo = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any] else {
-                    BFLog(message: "取出对应的图片属性失败")
-                    return
-                }
-                let defaultFrameDuration = 0.1
-                // 获取该帧图片的播放时间
-                let unclampedDelayTime = gifInfo[kCGImagePropertyGIFUnclampedDelayTime as String] as? NSNumber
-                // 如果通过kCGImagePropertyGIFUnclampedDelayTime没有获取到播放时长,就通过kCGImagePropertyGIFDelayTime来获取,两者的含义是相同的;
-                let delayTime = gifInfo[kCGImagePropertyGIFDelayTime as String] as? NSNumber
-                let duration = unclampedDelayTime ?? delayTime
-                guard let frameDuration = duration else {
-                    BFLog(message: "获取帧时间间隔失败")
-                    return
-                }
-                // 对于播放时间低于0.011s的,重新指定时长为0.100s;
-                let gifFrameDuration = frameDuration.doubleValue > 0.011 ? frameDuration.doubleValue : defaultFrameDuration
-                // 计算总时间
-                gifDuration += gifFrameDuration
-                // 2.图片
-                var frameImage: UIImage? = UIImage(cgImage: imageRef, scale: 1.0, orientation: .up)
-                if isRenderingColor != nil {
-                    frameImage = frameImage?.tintImage(color: isRenderingColor!, blendMode: .destinationIn)
-                }
-                if frameImage != nil {
-                    images.append(frameImage!)
-                }
-            }
-        }
-        resultHandler(data, images, gifDuration)
-    }
-}

+ 0 - 95
BFFramework/Classes/BFModules/BFUtility/PQVideoSnapshotUtil.swift

@@ -1,95 +0,0 @@
-//
-//  PQVideoSnapshotUtil.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/8/14.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import AVFoundation
-import AVKit
-import UIKit
-
-public class PQVideoSnapshotUtil: NSObject {
-    /// AVPlayer截屏
-    /// - Parameter playerItem: <#playerItem description#>
-    /// - Returns: <#description#>
-    class public  func snapshotImage(avPlayer: AVPlayer, complateHandle: @escaping (_ image: UIImage?) -> Void) {
-        guard let playerItem = avPlayer.currentItem else { // playerItem is AVPlayerItem
-            complateHandle(nil)
-            return
-        }
-        let videoOutput = AVPlayerItemVideoOutput(pixelBufferAttributes: nil)
-        playerItem.add(videoOutput)
-        let time = videoOutput.itemTime(forHostTime: CACurrentMediaTime())
-        if videoOutput.hasNewPixelBuffer(forItemTime: time) {
-            let lastSnapshotPixelBuffer = videoOutput.copyPixelBuffer(forItemTime: time, itemTimeForDisplay: nil)
-            if lastSnapshotPixelBuffer != nil {
-                let ciImage = CIImage(cvPixelBuffer: lastSnapshotPixelBuffer!)
-                let context = CIContext(options: nil)
-                let rect = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(CVPixelBufferGetWidth(lastSnapshotPixelBuffer!)), height: CGFloat(CVPixelBufferGetHeight(lastSnapshotPixelBuffer!)))
-                let cgImage = context.createCGImage(ciImage, from: rect)
-                if cgImage != nil {
-                    complateHandle(UIImage(cgImage: cgImage!))
-                    return
-                }
-            }
-        } else {
-            complateHandle(nil)
-        }
-    }
-
-    /// 非m3u8视频截屏
-    /// - Parameters:
-    ///   - videoURL: 视频地址
-    ///   - time: 视频某个时间点
-    /// - Returns: <#description#>
-    class public  func videoSnapshot(videoURL: URL, time: TimeInterval) -> UIImage? {
-        let asset = AVURLAsset(url: videoURL, options: avAssertOptions)
-        let assetImageGenerator = AVAssetImageGenerator(asset: asset)
-        assetImageGenerator.appliesPreferredTrackTransform = true
-        assetImageGenerator.requestedTimeToleranceBefore = CMTime.zero
-        assetImageGenerator.requestedTimeToleranceAfter = CMTime.zero
-        assetImageGenerator.apertureMode = .encodedPixels
-        let thumbnailCGImage: CGImage?
-        let thumbnailImageTime: CFTimeInterval = time
-        var thumbnailImage: UIImage?
-        do {
-            thumbnailCGImage = try assetImageGenerator.copyCGImage(at: CMTimeMake(value: Int64(thumbnailImageTime), timescale: 1), actualTime: nil)
-            if let cgImage = thumbnailCGImage {
-                thumbnailImage = UIImage(cgImage: cgImage)
-            }
-        } catch {}
-        return thumbnailImage
-    }
-
-    /// 获取非m3u8多张视频截图
-    /// - Parameters:
-    ///   - videoURL: 视频地址
-    ///   - duration: 视频时长
-    ///   - count: 截取数量
-    /// - Returns: <#description#>
-    class public  func videoSnapshot(videoURL: URL, duration: TimeInterval, count: Int, complateHandle: @escaping ([UIImage]?) -> Void) {
-        DispatchQueue.global().async {
-            var images: [UIImage]? = Array()
-            let asset = AVURLAsset(url: videoURL, options: avAssertOptions)
-            let assetImageGenerator = AVAssetImageGenerator(asset: asset)
-            assetImageGenerator.requestedTimeToleranceBefore = CMTime.zero
-            assetImageGenerator.requestedTimeToleranceAfter = CMTime.zero
-            assetImageGenerator.appliesPreferredTrackTransform = true
-            assetImageGenerator.apertureMode = .encodedPixels
-            for index in 0...count - 1 {
-                let thumbnailCGImage: CGImage?
-                let thumbnailImageTime: CFTimeInterval = ((duration / Double(count)) * Double(index))
-                BFLog(message: "截取视频时长 =(\(videoURL),duration = \(duration),count = \(count),line = \(thumbnailImageTime)")
-                do {
-                    thumbnailCGImage = try assetImageGenerator.copyCGImage(at: CMTimeMake(value: Int64(thumbnailImageTime), timescale: 1), actualTime: nil)
-                    if let cgImage = thumbnailCGImage {
-                        images?.append(UIImage(cgImage: cgImage))
-                    }
-                } catch {}
-            }
-            complateHandle(images)
-        }
-    }
-}

+ 0 - 48
BFFramework/Classes/BFModules/BFUtility/PQWeakTimer.swift

@@ -1,48 +0,0 @@
-//
-//  PQWeakTimer.swift
-//  PQSpeed
-//
-//  Created by lieyunye on 2020/6/18.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-
-public class PQWeakTimer {
-     public weak var timer: Timer?
-    public weak var target: AnyObject?
-    public let action: (Timer) -> Void
-
-    public init(timeInterval: TimeInterval,
-                 target: AnyObject,
-                 repeats: Bool,
-                 action: @escaping (Timer) -> Void)
-    {
-        self.target = target
-        self.action = action
-        timer = Timer.scheduledTimer(timeInterval: timeInterval,
-                                     target: self,
-                                     selector: #selector(fire),
-                                     userInfo: nil,
-                                     repeats: repeats)
-    }
-
-    public class func scheduledTimer(timeInterval: TimeInterval,
-                              target: AnyObject,
-                              repeats: Bool,
-                              action: @escaping (Timer) -> Void) -> Timer
-    {
-        return PQWeakTimer(timeInterval: timeInterval,
-                           target: target,
-                           repeats: repeats,
-                           action: action).timer!
-    }
-
-    @objc public func fire(timer: Timer) {
-        if target != nil {
-            action(timer)
-        } else {
-            timer.invalidate()
-        }
-    }
-}

+ 0 - 156
BFFramework/Classes/BFModules/BFUtility/SWNetRequest.swift

@@ -1,156 +0,0 @@
-//
-//  SWNetRequest.swift
-//  LiteraryHeaven
-//
-//  Created by SanW on 2017/8/2.
-//  Copyright © 2017年 ONON. All rights reserved.
-//
-
-import Alamofire
-import UIKit
-
-// 默认超时时间
-public let timeoutInterval: TimeInterval = 30
-
-// MARK: - 错误
-
-/// 错误
-public struct PQError: Error {
-    public var msg: String? // 提示信息
-    public var code: Int // 错误吗
-
-    init(msg: String?, code: Int = 0) {
-        self.msg = msg
-        self.code = code
-    }
-
-    public var localizedDescription: String {
-        return msg ?? ""
-    }
-}
-
-// MARK: - 网络请求
-
-/// 网络请求
-public class SWNetRequest: NSObject {
-    static let sessionManager: Alamofire.SessionManager = {
-        let configuration = URLSessionConfiguration.default
-        configuration.timeoutIntervalForRequest = timeoutInterval
-        return Alamofire.SessionManager(configuration: configuration)
-    }()
-
-    static let reTrySessionManager: Alamofire.SessionManager = {
-        let configuration = URLSessionConfiguration.default
-        configuration.timeoutIntervalForRequest = 5
-        return Alamofire.SessionManager(configuration: configuration)
-    }()
-
-    /// 回调方法
-    public typealias completeHander = (_ responseobject: Any?, _ extData: [String: Any]?, _ error: PQError?, _ timeline: Timeline) -> Void
-    /// get请求
-    public class func getRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = timeoutInterval, response: @escaping completeHander) {
-        requestData(method: .get, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, extData, error, timeline in
-            response(responseObject, extData, error, timeline)
-        }
-    }
-
-    /// post请求
-    public class func postRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = timeoutInterval, response: @escaping completeHander) {
-        requestData(method: .post, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, extData, error, timeline in
-            response(responseObject, extData, error, timeline)
-        }
-    }
-
-    /// 发送head请求
-    /// - Parameter url: <#url description#>
-    /// - Returns: <#description#>
-    class public func headRequestData(url: String, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) {
-        BFLog(message: "发起head请求 = \(url)")
-        if !isValidURL(url: url) {
-            completionHandler(nil, nil, PQError(msg: "url错误", code: 1001))
-            return
-        }
-        // http://www.mxfjx.com/uploadfiles/2014/4/小鸡%20鸡蛋%20蛋生鸡%20鸡生蛋_conew1.gif
-        url.urlEncoded()
-        let reqUrl = URL(string: url)!
-        var request = URLRequest(url: reqUrl)
-        request.timeoutInterval = 1 // 设置超时1s
-        request.httpMethod = "HEAD"
-        let session = URLSession.shared
-        let headTask = session.dataTask(with: request) { data, response, error in
-            completionHandler(data, response, error)
-            BFLog(message: "head请求返回 = \(url),code = \((response as? HTTPURLResponse)?.statusCode ?? 0),response = \(String(describing: response))")
-        }
-        headTask.resume()
-    }
-
-    /// put请求
-    public class func putRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = timeoutInterval, response: @escaping completeHander) {
-        requestData(method: .put, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, extData, error, timeline in
-            response(responseObject, extData, error, timeline)
-        }
-    }
-
-    /// delete请求
-    public class func deleteRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = timeoutInterval, response: @escaping completeHander) {
-        requestData(method: .delete, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, extData, error, timeline in
-            response(responseObject, extData, error, timeline)
-        }
-    }
-
-    /// 网络请求
-    fileprivate class func requestData(method: HTTPMethod, encoding: ParameterEncoding, url: String, parames: [String: Any]?, timeoutInterval _: TimeInterval = timeoutInterval, response: @escaping completeHander) {
-        var requestParams: [String: Any] = Dictionary<String, Any>.init()
-        if encoding is JSONEncoding, !url.hasSuffix(searchMaterialUrl), !url.hasSuffix(searchRecommendMaterialUrl), !url.hasSuffix(datashowAllowUrl),!url.hasSuffix(searchBGMMaterialUrl) {
-            requestParams["baseInfo"] = commonParams()
-            requestParams["params"] = parames
-        } else {
-            requestParams = commonParams()
-            if parames != nil, parames?.count ?? 0 > 0 {
-                if parames?.keys.contains("abInfoData") ?? false, "\(parames?["abInfoData"] ?? "")".count > 0, "\(parames?["abInfoData"] ?? "")" != "{}" {
-                    requestParams.removeValue(forKey: "abInfoData")
-                }
-                for (key, value) in parames!.reversed() {
-                    requestParams[key] = value
-                }
-            }
-        }
-        BFLog(message: "发起请求:\(url),params:\(requestParams)")
-        (timeoutInterval <= 5 ? reTrySessionManager : sessionManager).request(url, method: method, parameters: requestParams, encoding: encoding, headers: nil).responseJSON { jsonResponse in
-            BFLog(message: "jsonResponse = \(jsonResponse.timeline)")
-            /// 返回值
-            if jsonResponse.result.isSuccess {
-                let respondDict: [String: Any] = try! JSONSerialization.jsonObject(with: jsonResponse.data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any]
-                BFLog(message: "请求成功:\(url),respond:\(respondDict)")
-                if respondDict.keys.contains("code") && "\(respondDict["code"] ?? "")" == "0" && respondDict.keys.contains("data") {
-                    let extData = respondDict["extData"] as? [String: Any]
-                    if extData != nil && (extData?.keys.contains("abInfoData") ?? false) {
-                        PQSingletoMemoryUtil.shared.parasABinfoData(abInfo: extData?["abInfoData"] as? String)
-                    }
-                    response(respondDict["data"], extData, nil, jsonResponse.timeline)
-                } else if (respondDict.keys.contains("msg") && "\(respondDict["msg"] ?? "")".count > 0) || (respondDict.keys.contains("message") && "\(respondDict["message"] ?? "")".count > 0) {
-                    response(respondDict["data"], nil, PQError(msg: "\(respondDict["msg"] ?? "")", code: Int("\(respondDict["code"] ?? "")") ?? 10001), jsonResponse.timeline)
-                } else {
-                    response(nil, nil, PQError(msg: jsonResponse.result.error?.localizedDescription, code: 10001), jsonResponse.timeline)
-                }
-            } else {
-                BFLog(message: "请求失败:\(url),error:\(jsonResponse.result.error?.localizedDescription ?? "")")
-                let code: Int? = (jsonResponse.result.error as NSError?)?.code
-                response(nil, nil, PQError(msg: (code == -1009 || code == -1001) ? "网络不可用" : jsonResponse.result.error?.localizedDescription, code: code ?? 10001), jsonResponse.timeline)
-            }
-        }
-    }
-
-    /// 取消网络请求
-    /// - Parameter url: 某一个地址,空则取消所有
-    /// - Returns: <#description#>
-    public class func cancelTask(url: String?) {
-        sessionManager.session.getAllTasks(completionHandler: { tasks in
-            tasks.forEach { task in
-                if task.currentRequest?.url?.absoluteString == url {
-                    task.cancel()
-                }
-            }
-        })
-    }
-}

+ 0 - 203
BFFramework/Classes/Base/Controller/PQBaseViewController.swift

@@ -1,203 +0,0 @@
-//
-//  PQBaseViewController.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/25.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-// import MediaPlayer
-import Alamofire
-import UIKit
-open class PQBaseViewController: UIViewController, UIGestureRecognizerDelegate {
-    // 侧滑拦截返回
-    public var popGestureHandle: (() -> Void)?
-    public var naviTitle: String? // 标题
-    public var rightButton: UIButton? // 右边按钮
-    public var backButton: UIButton? // 左边按钮
-    public var navTitleLabel: UILabel? // 标题
-    public var navHeadImageView: UIImageView? // 导航条
-    public var lineView: UIView? // 导航分隔线
-    public var isHiddenStatus: Bool = false { // 更新状态栏
-        didSet {
-            setNeedsStatusBarAppearanceUpdate()
-        }
-    }
-
-    /// <#Description#>
-    public var isPresent: Bool {
-        var isPresent = true
-        let viewcontrollers = navigationController?.viewControllers
-        if (viewcontrollers?.count ?? 0) > 1 {
-            if viewcontrollers?[(viewcontrollers?.count ?? 1) - 1] == self {
-                isPresent = false
-            }
-        }
-        return isPresent
-    }
-
-    public lazy var manager: NetworkReachabilityManager? = {
-        let manager = NetworkReachabilityManager(host: "www.baidu.com")
-        manager?.listener = { status in
-            if status == .reachable(.wwan) || status == .reachable(.ethernetOrWiFi) {}
-        }
-        return manager
-    }()
-
-    override open func viewDidLoad() {
-        super.viewDidLoad()
-        navigationController?.isNavigationBarHidden = true
-        view.backgroundColor = PQBFConfig.shared.styleBackGroundColor
-        navHeadImageView = UIImageView(image: UIImage())
-        navHeadImageView?.isUserInteractionEnabled = true
-        navHeadImageView?.backgroundColor = PQBFConfig.shared.styleBackGroundColor
-        navHeadImageView?.frame = CGRect(x: 0, y: 0, width: cScreenWidth, height: cDevice_iPhoneNavBarAndStatusBarHei)
-        view.addSubview(navHeadImageView!)
-
-        lineView = UIView(frame: CGRect(x: 0, y: (navHeadImageView?.frame.maxY ?? cDevice_iPhoneNavBarAndStatusBarHei) - 0.5, width: cScreenWidth, height: 0.5))
-        lineView?.backgroundColor = PQBFConfig.shared.styleBackGroundColor
-        view.addSubview(lineView!)
-        UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
-        automaticallyAdjustsScrollViewInsets = false
-        navigationController?.interactivePopGestureRecognizer?.delegate = self
-        fd_prefersNavigationBarHidden = true
-    }
-
-    public func hiddenNavigation() {
-        navHeadImageView?.isHidden = true
-        lineView?.isHidden = true
-    }
-
-    public func showNavigation() {
-        if navHeadImageView != nil {
-            navHeadImageView?.isHidden = false
-            lineView?.isHidden = false
-            view.bringSubviewToFront(navHeadImageView!)
-        }
-    }
-
-    open func leftBackButton() {
-        leftButton(image: "icon_detail_back")
-    }
-
-    public func leftButton(image: String?, tintColor: UIColor? = nil) {
-        let leftButton = UIButton(type: .custom)
-        leftButton.frame = CGRect(x: 0, y: cDevice_iPhoneStatusBarHei, width: cDefaultMargin * 4, height: cDefaultMargin * 4)
-        leftButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: -5, right: 0)
-        if tintColor != nil {
-            leftButton.tintColor = tintColor
-            leftButton.setImage(UIImage().BF_Image(named: image ?? "icon_detail_back").withRenderingMode(.alwaysTemplate), for: .normal)
-        } else {
-            leftButton.setImage(UIImage().BF_Image(named: image ?? "icon_detail_back"), for: .normal)
-        }
-        leftButton.addTarget(self, action: #selector(backBtnClick), for: .touchUpInside)
-        navHeadImageView?.addSubview(leftButton)
-        backButton = leftButton
-    }
-
-    public func rightButtonItem(image: String?, title: String?) {
-        let rightButtonItem = UIButton(type: .custom)
-        var rightW: CGFloat = cDefaultMargin
-        if title != nil, title?.count ?? 0 > 0 {
-            rightW = rightW + sizeWithText(text: title ?? "", font: UIFont.systemFont(ofSize: 16), size: CGSize(width: CGFloat.greatestFiniteMagnitude, height: cDefaultMargin * 4)).width
-            rightButtonItem.setTitle(title, for: .normal)
-            rightButtonItem.setTitleColor(UIColor.hexColor(hexadecimal: "#242F44"), for: .normal)
-            rightButtonItem.titleLabel?.font = UIFont.systemFont(ofSize: 16)
-        }
-        if image != nil, image?.count ?? 0 > 0 {
-            rightW = rightW + cDefaultMargin * 4
-            rightButtonItem.setImage(UIImage(named: image ?? ""), for: .normal)
-            rightButtonItem.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: (title != nil && title?.count ?? 0 > 0) ? 0 : -5, right: 0)
-        }
-        rightButtonItem.adjustsImageWhenHighlighted = false
-        rightButtonItem.frame = CGRect(x: cScreenWidth - rightW, y: cDevice_iPhoneStatusBarHei, width: rightW, height: cDefaultMargin * 4)
-        rightButtonItem.addTarget(self, action: #selector(rightBtnClick(sender:)), for: .touchUpInside)
-        rightButtonItem.contentHorizontalAlignment = .center
-        navHeadImageView?.addSubview(rightButtonItem)
-        rightButton = rightButtonItem
-    }
-
-    public func setTitle(title: String?, color: UIColor = UIColor.white) {
-        naviTitle = title
-        if navTitleLabel == nil {
-            let titleLabel = UILabel(frame: CGRect(x: cDefaultMargin * 5, y: cDevice_iPhoneStatusBarHei, width: cScreenWidth - 100, height: cDefaultMargin * 4))
-            titleLabel.textColor = color
-            titleLabel.textAlignment = .center
-            navTitleLabel = titleLabel
-            navHeadImageView?.addSubview(titleLabel)
-        }
-        navTitleLabel?.text = title
-    }
-
-    @objc open func rightBtnClick(sender _: UIButton) {}
-
-    @objc open func backBtnClick() {
-        if isPresent {
-            dismiss(animated: true, completion: nil)
-        } else {
-            navigationController?.popViewController(animated: true)
-        }
-    }
-
-    override open func viewDidAppear(_ animated: Bool) {
-        super.viewDidAppear(animated)
-    }
-
-    override open func viewWillDisappear(_ animated: Bool) {
-        super.viewWillDisappear(animated)
-        PQLoadingHUB.shared.dismissHUB()
-    }
-
-    override open func viewDidDisappear(_ animated: Bool) {
-        super.viewDidDisappear(animated)
-
-        if view.viewWithTag(cGuideTag) != nil {
-            view.viewWithTag(cGuideTag)?.removeFromSuperview()
-        }
-    }
-
-    deinit {
-        PQNotification.removeObserver(self)
-        BFLog(message: "\(String(describing: type(of: self)))被销毁")
-    }
-
-    override open var preferredStatusBarStyle: UIStatusBarStyle {
-        if PQBFConfig.shared.statusBarStyle == .dark {
-            if #available(iOS 13.0, *) {
-                return .darkContent
-            } else {
-                return .default
-            }
-        } else {
-            return .lightContent
-        }
-    }
-
-    override open var prefersStatusBarHidden: Bool {
-        return isHiddenStatus
-    }
-
-    /// 禁止滑动返回
-    /// - Returns: <#description#>
-    public func disablePopGesture() -> PQBaseViewController {
-        let traget = navigationController?.interactivePopGestureRecognizer?.delegate
-        let pan = UIPanGestureRecognizer(target: traget, action: #selector(popGesture(panGes:)))
-        view.addGestureRecognizer(pan)
-        return self
-    }
-
-    /// 拦截侧滑手势
-    /// - Returns: <#description#>
-    @objc private  func popGesture(panGes: UIPanGestureRecognizer) {
-        if panGes.state == .ended, popGestureHandle != nil {
-            popGestureHandle!()
-        }
-    }
-
-    open func gestureRecognizer(_: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
-        if touch.view is UISlider {
-            return false
-        }
-        return true
-    }
-}

+ 0 - 184
BFFramework/Classes/Base/Controller/PQBaseWebViewController.swift

@@ -1,184 +0,0 @@
-
-//
-//  PQBaseWebViewController.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/27.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-import WebKit
-
-open class PQBaseWebViewController: PQBaseViewController {
-   public var emptyData: PQEmptyModel? = {
-        let emptyData = PQEmptyModel()
-        emptyData.title = "网页加载失败,请重试~"
-        emptyData.emptyImage = "pic_network"
-        return emptyData
-    }()
-
-    lazy public var webView: WKWebView = {
-        let config: WKWebViewConfiguration = WKWebViewConfiguration()
-        config.allowsInlineMediaPlayback = true
-        let webView: WKWebView = WKWebView(frame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth, height: cScreenHeigth - cDevice_iPhoneNavBarAndStatusBarHei), configuration: config)
-        webView.backgroundColor = UIColor.white
-        if #available(iOS 11.0, *) {
-            webView.scrollView.contentInsetAdjustmentBehavior = .never
-        } else {
-            automaticallyAdjustsScrollViewInsets = false
-        }
-        webView.navigationDelegate = self
-        return webView
-    }()
-
-    lazy public var progresslayer: CALayer = {
-        let progresslayer = CALayer()
-        progresslayer.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth * 0.1, height: 2)
-        progresslayer.backgroundColor = UIColor.hexColor(hexadecimal: "#FF9500").cgColor
-        return progresslayer
-    }()
-
-    @objc public var baseUrl: String? {
-        didSet {
-            if baseUrl != nil, baseUrl?.count ?? 0 > 0 {
-                webView.load(URLRequest(url: NSURL(string: baseUrl ?? "")! as URL, cachePolicy: .reloadIgnoringCacheData))
-                // 添加属性监听
-                webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
-                isAddObserve = true
-                view.layer.addSublayer(progresslayer)
-            }
-        }
-    }
-
-    @objc public var baseTitle: String?
-    public var evaluateJavaScript: String? // 交互
-    var isAddObserve: Bool = false
-    override open func viewDidLoad() {
-        super.viewDidLoad()
-        // Do any additional setup after loading the view.
-        view.addSubview(webView)
-        leftButton(image: "icon_blanc_back")
-        navHeadImageView?.backgroundColor = UIColor.white
-    }
-
-    override public func viewWillAppear(_ animated: Bool) {
-        super.viewWillAppear(animated)
-        if (UIApplication.shared.keyWindow?.viewWithTag(cProtocalViewTag)) != nil {
-            (UIApplication.shared.keyWindow?.viewWithTag(cProtocalViewTag))?.isHidden = true
-        }
-    }
-
-    override public func viewWillDisappear(_ animated: Bool) {
-        super.viewWillDisappear(animated)
-        if (UIApplication.shared.keyWindow?.viewWithTag(cProtocalViewTag)) != nil {
-            (UIApplication.shared.keyWindow?.viewWithTag(cProtocalViewTag))?.isHidden = false
-        }
-    }
-
-    deinit {
-        if isAddObserve {
-            webView.removeObserver(self, forKeyPath: "estimatedProgress")
-        }
-    }
-}
-
-extension PQBaseWebViewController: WKNavigationDelegate {
-   public func refreshClick() {
-        if baseUrl != nil, baseUrl?.count ?? 0 > 0 {
-            webView.load(URLRequest(url: NSURL(string: baseUrl ?? "")! as URL, cachePolicy: .useProtocolCachePolicy))
-        }
-    }
-
-    @objc public func back() {
-        if webView.canGoBack {
-            webView.goBack()
-        } else if navigationController != nil {
-            navigationController?.popViewController(animated: true)
-        } else {
-            dismiss(animated: true, completion: nil)
-        }
-    }
-
-    override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
-        if keyPath == "estimatedProgress" {
-            progresslayer.opacity = 1
-            let float = (change?[NSKeyValueChangeKey.newKey] as! NSNumber).floatValue
-            progresslayer.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth * CGFloat(float), height: 3)
-            if float == 1 {
-                weak var weakself = self
-                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) {
-                    weakself?.progresslayer.opacity = 0
-                }
-                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.8) {
-                    weakself?.progresslayer.frame = CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: 0, height: 3)
-                }
-            }
-        } else {
-            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
-        }
-    }
-
-    public func webView(_ webView: WKWebView, didFinish _: WKNavigation!) {
-        if baseTitle == nil || baseTitle?.count ?? 0 <= 0 {
-            webView.evaluateJavaScript("document.title") { [weak self] (any, _) -> Void in
-                self?.setTitle(title: any as? String)
-                self?.baseTitle = any as? String
-            }
-        }
-        if evaluateJavaScript != nil, (evaluateJavaScript?.count ?? 0) > 0 {
-            webView.evaluateJavaScript(evaluateJavaScript!) { _, _ in
-            }
-        }
-    }
-
-    public func webView(_ webView: WKWebView, didFail _: WKNavigation!, withError error: Error) {
-        BFLog(message: error)
-        if baseTitle == nil || baseTitle?.count ?? 0 <= 0 {
-            webView.evaluateJavaScript("document.title") { [weak self] (any, _) -> Void in
-                self?.setTitle(title: any as? String)
-                self?.baseTitle = any as? String
-            }
-        }
-    }
-
-    public func webView(_: WKWebView, didFailProvisionalNavigation _: WKNavigation!, withError _: Error) {}
-
-    public func webView(_: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
-        BFLog(message: "navigationResponse:\(String(describing: navigationResponse))")
-        decisionHandler(.allow)
-    }
-
-    public func webView(_: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
-        BFLog(message: "didStartProvisionalNavigation:\(String(describing: navigation))")
-    }
-
-    public func webView(_: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
-        BFLog(message: "didReceiveServerRedirectForProvisionalNavigation:\(String(describing: navigation))")
-    }
-
-    public func webView(_: WKWebView, didCommit navigation: WKNavigation!) {
-        BFLog(message: "\(String(describing: navigation))")
-    }
-
-//    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
-//        let url : String = navigationAction.request.url?.absoluteString ?? "";
-//        if(url.count == 0 || url == "about:blank"){
-//            decisionHandler(.cancel)
-//            return
-//        }
-//        let vc = PQBaseWebViewController.init()
-//        vc.baseUrl = url
-//        navigationController?.pushViewController(vc, animated: true)
-//        BFLog(message: "decidePolicyFor \(String(describing: navigationAction))")
-//        decisionHandler(.allow)
-//    }
-    override public var preferredStatusBarStyle: UIStatusBarStyle {
-        if #available(iOS 13.0, *) {
-            return .darkContent
-        } else {
-            // Fallback on earlier versions
-            return .default
-        }
-    }
-}

+ 0 - 46
BFFramework/Classes/Base/Controller/PQNavigatinController.swift

@@ -1,46 +0,0 @@
-//
-//  PQNavigatinController.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/25.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-
-open class PQNavigatinController: UINavigationController, UIGestureRecognizerDelegate {
-    public var isPop: Bool = false
-
-   open  override func viewDidLoad() {
-        super.viewDidLoad()
-
-        // Do any additional setup after loading the view.
-    }
-
-   open override func pushViewController(_ viewController: UIViewController, animated _: Bool) {
-        if viewControllers.count > 0 {
-            viewController.hidesBottomBarWhenPushed = true
-        }
-        super.pushViewController(viewController, animated: true)
-    }
-
-   public func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
-        return topViewController!.supportedInterfaceOrientations
-    }
-
-   public func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
-        return topViewController!.preferredInterfaceOrientationForPresentation
-    }
-
-   open override var childForStatusBarStyle: UIViewController? {
-        return topViewController
-    }
-
-   open override var childForStatusBarHidden: UIViewController? {
-        return topViewController
-    }
-
-   public func gestureRecognizerShouldBegin(_: UIGestureRecognizer) -> Bool {
-        return viewControllers.count > 1
-    }
-}

+ 0 - 189
BFFramework/Classes/Base/Model/PQBaseModel.swift

@@ -1,189 +0,0 @@
-//
-//  PQBaseModel.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/25.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import RealmSwift
-import UIKit
-
-open class PQBaseModel: Object {
-    @objc dynamic public var uniqueId: String? // 唯一ID
-    @objc dynamic public var videoId: Int = 0 // 视频ID
-    @objc dynamic public var eventId: String? // 事件ID
-    @objc dynamic public var title: String? // 标题
-    @objc dynamic public var attributedTitle: NSMutableAttributedString? // 富文本标题
-    @objc dynamic public var summary: String? // 描述
-    @objc dynamic public var imageUrl: String = "" // 图片地址
-    @objc dynamic public var selectedImage: String = "" // 图片地址
-    @objc dynamic public var isSelected: Bool = false
-    @objc dynamic public var recommendLogVO: String? // 推荐日志对象
-    @objc dynamic public var abInfoData: String? // AB
-    @objc dynamic public var pageCategoryId: Int = 0 // 页面分类ID
-    @objc dynamic public var version: String = versionName // 版本号
-    @objc dynamic public var mid = getMachineCode() // 设备ID
-    @objc dynamic public var date: Int = 0 // 当前时间戳  CGFloat(Date.init().timeIntervalSince1970) * 1000
-    @objc dynamic public var itemWidth: Float = 0 // cell宽
-    @objc dynamic public var primaryKeys: String? // 区分存储唯一值
-    override class public func primaryKey() -> String? {
-        return "uniqueId"
-    }
-
-    public override required  init() {
-        super.init()
-        uniqueId = getUniqueId(desc: "uniqueId")
-    }
-
-    override class open func ignoredProperties() -> [String] {
-        return ["attributedTitle"]
-    }
-
-    @objc func toString() -> String {
-        var json: [String: Any] = [
-            "version": version,
-            "mid": mid,
-            "pageCategoryId": pageCategoryId,
-            "selectedImage": selectedImage,
-            "isSelected": isSelected,
-            "imageUrl": imageUrl,
-        ]
-        if uniqueId != nil {
-            json["uniqueId"] = uniqueId
-            json["videoId"] = videoId
-        }
-        if eventId != nil {
-            json["eventId"] = eventId
-        }
-        if title != nil {
-            json["title"] = title
-        }
-        if summary != nil {
-            json["summary"] = summary
-        }
-        if recommendLogVO != nil {
-            json["recommendLogVO"] = recommendLogVO
-        }
-        return dictionaryToJsonString(json) ?? ""
-    }
-
-    public init(jsonDict: [String: Any]) {
-        super.init()
-        if jsonDict.keys.contains("id") {
-            uniqueId = "\(jsonDict["id"] ?? "")"
-            videoId = Int(uniqueId ?? "0") ?? 0
-        }
-        if jsonDict.keys.contains("uniqueId") {
-            uniqueId = "\(jsonDict["uniqueId"] ?? "")"
-            videoId = Int(uniqueId ?? "0") ?? 0
-        }
-        if jsonDict.keys.contains("eventId") {
-            eventId = "\(jsonDict["eventId"] ?? "")"
-        }
-        if jsonDict.keys.contains("title") {
-            title = "\(jsonDict["title"] ?? "")"
-        }
-        if jsonDict.keys.contains("summary") {
-            summary = "\(jsonDict["summary"] ?? "")"
-        }
-        if jsonDict.keys.contains("imageUrl") {
-            imageUrl = "\(jsonDict["imageUrl"] ?? "")"
-        }
-        if jsonDict.keys.contains("selectedImage") {
-            selectedImage = "\(jsonDict["selectedImage"] ?? "")"
-        }
-        if jsonDict.keys.contains("isSelected") {
-            isSelected = jsonDict["isSelected"] as! Bool
-        }
-        if jsonDict.keys.contains("recommendLogVO") {
-            recommendLogVO = "\(jsonDict["recommendLogVO"] ?? "")"
-        }
-        if jsonDict.keys.contains("pageCategoryId") {
-            pageCategoryId = Int("\(jsonDict["pageCategoryId"] ?? "0")") ?? 0
-        }
-        if jsonDict.keys.contains("version") {
-            version = "\(jsonDict["version"] ?? "")"
-        }
-        if jsonDict.keys.contains("mid") {
-            mid = "\(jsonDict["mid"] ?? "")"
-        }
-    }
-}
-
-// MARK: - 当前应用本地存储的model
-
-/// 当前应用本地存储的model
-public  class PQLocalStoreModel: PQBaseModel {
-    @objc dynamic public var currentDate: String?
-    @objc required init() {
-        super.init()
-        currentDate = systemCurrentDate()
-    }
-}
-
-// MARK: - oss上传model
-
-/// oss上传model
-public class PQOssUploadModel: NSObject {
-    public var accessKeyId: String?
-    public var secretKeyId: String?
-    public var securityToken: String?
-    public var endpoint: String?
-    public var endpoints: [String]?
-    public var bucketName: String?
-    public var fileName: String?
-    public var uploadID: String?
-    public var expiration: String? // 过期时间
-    public init(jsonDict: [String: Any]) {
-        super.init()
-
-        if jsonDict.keys.contains("AccessKeyId") {
-            accessKeyId = "\(jsonDict["AccessKeyId"] ?? "")"
-        }
-        if jsonDict.keys.contains("AccessKeySecret") {
-            secretKeyId = "\(jsonDict["AccessKeySecret"] ?? "")"
-        }
-        if jsonDict.keys.contains("SecurityToken") {
-            securityToken = "\(jsonDict["SecurityToken"] ?? "")"
-        }
-        if jsonDict.keys.contains("Hosts") {
-            endpoints = jsonDict["Hosts"] as? [String]
-        }
-        if jsonDict.keys.contains("Host") {
-            endpoint = "\(jsonDict["Host"] ?? "")"
-            if endpoint != nil {
-                if endpoints == nil {
-                    endpoints = [endpoint!]
-                } else {
-                    endpoints?.append(endpoint!)
-                }
-            }
-        }
-        if jsonDict.keys.contains("Bucket") {
-            bucketName = "\(jsonDict["Bucket"] ?? "")"
-        }
-        if jsonDict.keys.contains("FileName") {
-            fileName = "\(jsonDict["FileName"] ?? "")"
-        }
-        if jsonDict.keys.contains("Upload") {
-            uploadID = "\(jsonDict["Upload"] ?? "")"
-        }
-        if jsonDict.keys.contains("Expiration") {
-            expiration = "\(jsonDict["Expiration"] ?? "")"
-        }
-    }
-}
-
-// MARK: - 空白页面model
-
-/// 空白页面model
-public class PQEmptyModel: NSObject {
-    public var title: String? // 标题
-    public var summary: String? // 描述
-    public var emptyImage: String? // 空白提示图
-    public var isRefreshHidden: Bool = true // 是否隐藏刷新按钮
-    public var refreshImage: String? // 刷新按钮图片
-    public var refreshTitle: NSMutableAttributedString? // 刷新按钮文字
-    public var refreshBgColor: UIColor? // 刷新按钮背景颜色
-}

+ 0 - 121
BFFramework/Classes/Base/View/PQFollowButton.swift

@@ -1,121 +0,0 @@
-//
-//  PQFollowButton.swift
-//  PQSpeed
-//
-//  Created by lieyunye on 2020/6/18.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-
-public class PQFollowButton: UIButton {
-    public  let bgLayer = CAShapeLayer()
-
-    public  var attenBtn: UIButton = {
-        let attenBtn = UIButton(type: .custom)
-        attenBtn.isUserInteractionEnabled = false
-        attenBtn.setTitle("", for: .selected)
-        attenBtn.setImage(UIImage.init().BF_Image(named: "icon_oder"), for: .selected)
-        attenBtn.setTitle("+", for: .normal)
-        attenBtn.setImage(nil, for: .normal)
-        attenBtn.setTitleColor(UIColor.white, for: .normal)
-        attenBtn.titleLabel?.font = UIFont.systemFont(ofSize: 20, weight: .bold)
-        attenBtn.layer.cornerRadius = 10
-//        attenBtn.layer.masksToBounds = true
-        attenBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#EE0051")
-        attenBtn.tag = 2
-        attenBtn.titleEdgeInsets = UIEdgeInsets(top: -3, left: 0, bottom: 0, right: 0)
-        return attenBtn
-    }()
-
-    override public  init(frame: CGRect) {
-        super.init(frame: frame)
-        addSubview(attenBtn)
-    }
-
-    required public  init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    override public func layoutSubviews() {
-        super.layoutSubviews()
-        attenBtn.snp.makeConstraints { make in
-            make.edges.equalTo(self).inset(UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
-        }
-    }
-
-    public  func reset() {
-        attenBtn.isHidden = false
-        attenBtn.layer.removeAllAnimations()
-        bgLayer.removeAllAnimations()
-        bgLayer.sublayers?.forEach {
-            $0.removeAllAnimations()
-            $0.removeFromSuperlayer()
-        }
-        bgLayer.removeFromSuperlayer()
-    }
-
-    public  func start() {
-        let bounds = self.bounds
-
-        bgLayer.frame = bounds
-        bgLayer.cornerRadius = bounds.height / 2.0
-        bgLayer.masksToBounds = true
-        layer.addSublayer(bgLayer)
-
-        let bgScale = CABasicAnimation(keyPath: "transform.scale")
-        bgScale.fromValue = 1
-        bgScale.toValue = 1.2
-        bgScale.duration = 0.2
-        attenBtn.layer.add(bgScale, forKey: nil)
-
-        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) {
-            self.attenBtn.isHidden = true
-            let opacity = CAKeyframeAnimation(keyPath: "backgroundColor")
-            opacity.values = [UIColor.red.cgColor, UIColor.white.cgColor]
-            opacity.duration = 0.5
-            opacity.fillMode = .forwards
-            opacity.isRemovedOnCompletion = false
-            self.bgLayer.add(opacity, forKey: nil)
-
-            let bgLayer1 = CAShapeLayer()
-            let frame = CGRect(x: (bounds.size.width - bounds.size.height) / 2.0, y: 0, width: bounds.size.height, height: bounds.size.height)
-            bgLayer1.frame = frame
-            self.bgLayer.addSublayer(bgLayer1)
-
-            let linePath = UIBezierPath()
-
-            let radius: CGFloat = frame.size.width / 2.0
-            linePath.move(to: CGPoint(x: radius * 0.45, y: radius * 1.0))
-            linePath.addLine(to: CGPoint(x: radius * 0.84, y: radius * 1.32))
-            linePath.addLine(to: CGPoint(x: radius * 1.48, y: radius * 0.68))
-
-            let layer = CAShapeLayer()
-
-            layer.path = linePath.cgPath
-            layer.fillColor = UIColor.clear.cgColor
-            layer.strokeColor = UIColor.hexColor(hexadecimal: "#EE0051").cgColor
-            layer.lineWidth = 2.5
-            bgLayer1.addSublayer(layer)
-
-            let animation = CABasicAnimation()
-            animation.duration = 0.5
-            animation.keyPath = "strokeEnd"
-            animation.fromValue = 0
-            animation.toValue = 1
-            animation.fillMode = .forwards
-            animation.isRemovedOnCompletion = false
-
-            layer.add(animation, forKey: "strokeEnd")
-
-            let scale = CABasicAnimation(keyPath: "transform.scale")
-            scale.fromValue = 1
-            scale.toValue = 0
-            scale.duration = 0.2
-            scale.beginTime = CACurrentMediaTime() + 1.5
-            scale.fillMode = .forwards
-            scale.isRemovedOnCompletion = false
-            self.bgLayer.add(scale, forKey: nil)
-        }
-    }
-}

+ 0 - 41
BFFramework/Classes/Base/View/PQGIFImageView.swift

@@ -1,41 +0,0 @@
-//
-//  PQGIFImageView.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/9/2.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-
-public class PQGIFImageView: UIImageView {
-   public var imagesDara: [String]? {
-        didSet {
-            generateImages()
-            displayGIF(1, Int.max)
-        }
-    }
-
-    public var images: [UIImage] = Array<UIImage>.init()
-    public func generateImages() {
-        if imagesDara != nil, (imagesDara?.count ?? 0) > 0 {
-            for item in imagesDara! {
-                let image = UIImage(named: item)!
-                images.append(image)
-            }
-        }
-    }
-
-    public func displayGIF(_ duration: TimeInterval, _ repeatCount: Int) {
-        if !isAnimating {
-            layer.removeAllAnimations()
-            if images.count <= 0 {
-                return
-            }
-            animationImages = images
-            animationDuration = duration
-            animationRepeatCount = repeatCount
-            startAnimating()
-        }
-    }
-}

+ 0 - 53
BFFramework/Classes/Base/View/PQHeartAnimation.swift

@@ -1,53 +0,0 @@
-//
-//  PQHeartAnimation.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/6/11.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-
-public class PQHeartAnimation: NSObject {
-    static let angleArr: [CGFloat] = [CGFloat.pi / 4.0, -CGFloat.pi / 4.0, 0.0]
-    var isRepeat: Bool = false
-
-    static public func showAnimation(isRepeat: Bool = false, point: CGPoint, size: CGFloat = 80.0, baseView: UIView, completeHander: @escaping (_ isFinised: Bool) -> Void) {
-        if isRepeat, baseView.viewWithTag(cHeartTag) != nil {
-            return
-        }
-        let imgV = UIImageView(frame: CGRect(x: point.x - size / 2.0, y: point.y - size / 2.0, width: size, height: size))
-        imgV.tag = cHeartTag
-        imgV.image = UIImage.init().BF_Image(named:  "ic_heart")
-        imgV.contentMode = .scaleAspectFill
-        baseView.addSubview(imgV)
-
-        // 偏移角度
-        var num = 2
-        if !isRepeat {
-            num = Int(arc4random_uniform(3))
-        }
-//      BFLog(message: "num = \(num)")
-        imgV.transform = CGAffineTransform(rotationAngle: angleArr[num])
-        // 放大动画
-        let animation = CAKeyframeAnimation(keyPath: "transform.scale")
-        animation.duration = 0.5
-        animation.calculationMode = CAAnimationCalculationMode.cubic
-        animation.values = [1.3, 0.8, 1.0]
-        imgV.layer.add(animation, forKey: "transform.scale")
-
-        UIView.animate(withDuration: 1, delay: 0.5, options: .layoutSubviews, animations: {
-            imgV.alpha = 0.0
-            var newFrame = imgV.frame
-            newFrame.origin.x -= (isRepeat ? -cDefaultMargin * 2 : cDefaultMargin)
-            newFrame.origin.y -= 45.0
-            newFrame.size.height += 10.0
-            newFrame.size.width += 10.0
-            imgV.frame = newFrame
-        }) { isOK in
-            imgV.layer.removeAllAnimations()
-            imgV.removeFromSuperview()
-            completeHander(isOK)
-        }
-    }
-}

+ 0 - 141
BFFramework/Classes/Base/View/PQLoadingHUB.swift

@@ -1,141 +0,0 @@
-//
-//  PQLoadingHUB.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/6/5.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-
-public class PQLoadingHUBView: UIView {
-    // gif每一帧图
-    public var gifImages: [UIImage]?
-    // gif播放时长
-    public var duration: Double?
-
-    public lazy var loadingImage: UIImageView = {
-        let loadingImage = UIImageView()
-        loadingImage.tintColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
-        return loadingImage
-    }()
-
-    override public init(frame: CGRect) {
-        super.init(frame: frame)
-        addSubview(loadingImage)
-        isUserInteractionEnabled = false
-        let data = try? Data(contentsOf: URL(fileURLWithPath: Bundle().BF_mainbundle().path(forResource: "stuckPoint_music_loading", ofType: ".gif")!))
-        if data != nil {
-            PQPHAssetVideoParaseUtil.parasGIFImage(data: data!, isRenderingColor: UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)) { [weak self] _, images, duration in
-                self?.gifImages = images
-                self?.duration = duration
-            }
-        }
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    override public func layoutSubviews() {
-        super.layoutSubviews()
-        // 334 * 307
-        let imageW: CGFloat = 67
-        let imageH: CGFloat = 62
-        loadingImage.frame = CGRect(x: (frame.width - imageW) / 2, y: (frame.height - imageW) / 2, width: imageW, height: imageH)
-    }
-
-    /// 开始加载
-    public func loading() {
-        loadingImage.displayGIF(data: nil, images: gifImages, repeatCount: .max, duration: duration ?? 2)
-    }
-
-    /// 停止加载
-    public func endLoading() {
-        loadingImage.removePlayGIF()
-    }
-
-    override public func removeFromSuperview() {
-        loadingImage.removePlayGIF()
-        loadingImage.removeFromSuperview()
-    }
-}
-
-public class PQLoadingHUB: NSObject {
-    public static let shared = PQLoadingHUB()
-    public let viewTag = 11111
-    public var isLoading: Bool = false
-
-    public func showHUB(isMode:Bool = false) {
-        DispatchQueue.main.async { [weak self] in
-            let window = UIApplication.shared.keyWindow
-            if (window?.viewWithTag(self!.viewTag)) == nil {
-                let loadingHUB: PQLoadingHUBView = PQLoadingHUBView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
-            
-                if(isMode){
-                    let backView = UIImageView.init(frame: window?.frame ?? .zero)
-                    backView.backgroundColor = .clear
-                    backView.isUserInteractionEnabled = true
-                    backView.addSubview(loadingHUB)
-                    backView.tag = self!.viewTag
-                    window?.addSubview(backView)
-                }else{
-                    loadingHUB.tag = self!.viewTag
-                    window?.addSubview(loadingHUB)
-                }
-             
-                loadingHUB.center = window?.center as! CGPoint
-                loadingHUB.loading()
-                self?.isLoading = true
-            }
-        }
-    }
-
-    public func dismissHUB() {
-        DispatchQueue.main.async { [weak self] in
-            let window = UIApplication.shared.keyWindow
-            if (window?.viewWithTag(self!.viewTag)) != nil {
-                window?.viewWithTag(self!.viewTag)?.removeFromSuperview()
-                self?.isLoading = false
-            }
-        }
-    }
-
-    public func showHUB(superView: UIView, isVerticality: Bool = false) {
-        DispatchQueue.main.async { [weak self] in
-            if superView.viewWithTag(self!.viewTag) == nil {
-                let hubW: CGFloat = 100
-                let supW: CGFloat = superView.frame.width
-                let supH: CGFloat = superView.frame.height
-                let hubY: CGFloat = isVerticality ? ((supW - hubW) / 2) : ((supH - hubW) / 2)
-                let hubX: CGFloat = isVerticality ? ((supH - hubW) / 2) : ((supW - hubW) / 2)
-                let loadingHUB: PQLoadingHUBView = PQLoadingHUBView(frame: CGRect(x: hubX, y: hubY, width: 100, height: 100))
-                loadingHUB.tag = self!.viewTag
-                superView.addSubview(loadingHUB)
-                loadingHUB.loading()
-                self?.isLoading = true
-            }
-        }
-    }
-
-    public func dismissHUB(superView: UIView) {
-        DispatchQueue.main.async { [weak self] in
-            if superView.viewWithTag(self!.viewTag) != nil {
-                superView.viewWithTag(self!.viewTag)?.removeFromSuperview()
-                self?.isLoading = false
-            }
-        }
-    }
-
-    override private init() {
-        super.init()
-    }
-
-    override public func copy() -> Any {
-        return self
-    }
-
-    override public func mutableCopy() -> Any {
-        return self
-    }
-}

+ 0 - 515
BFFramework/Classes/Base/View/PQRemindView.swift

@@ -1,515 +0,0 @@
-
-// MARK: - 设置页退出登录跟注销账号提示视图
-
-/// 设置页退出登录跟注销账号提示视图
-open class PQRemindView: UIView {
-    public var isBanned: Bool = false // 是否是拉黑用户提示
-    public var isBlank: Bool = false { // 是否是黑色弹窗
-        didSet {
-            if isBlank {
-                contentView.backgroundColor = UIColor.hexColor(hexadecimal: "#212223")
-                titleLab.textColor = UIColor.white
-                contentLab.textColor = UIColor.white
-                cancelBtn.setTitleColor(UIColor.white, for: .normal)
-                confirmBtn.setTitleColor(UIColor.white, for: .normal)
-            } else {
-                contentView.backgroundColor = UIColor.white
-                contentLab.textColor = UIColor.hexColor(hexadecimal: "#666666")
-                titleLab.textColor = UIColor.black
-                cancelBtn.setTitleColor(UIColor.black, for: .normal)
-                confirmBtn.setTitleColor(UIColor.black, for: .normal)
-            }
-        }
-    }
-
-    public var remindBlock: ((_ sender: UIButton, _ remindData: PQBaseModel?) -> Void)?
-
-    lazy public var contentView: UIView = {
-        let contentView = UIView()
-        contentView.backgroundColor = UIColor.white
-        contentView.addCorner(corner: 4)
-        return contentView
-    }()
-
-    lazy public var titleLab: UILabel = {
-        let titleLab = UILabel()
-        titleLab.font = UIFont.systemFont(ofSize: 18, weight: .medium)
-        titleLab.textAlignment = .center
-        titleLab.numberOfLines = 0
-        titleLab.textColor = UIColor.black
-        return titleLab
-    }()
-
-    lazy public var contentLab: UILabel = {
-        //        let contentLab = TYAttributedLabel.init()
-        //        contentLab.textAlignment = CTTextAlignment.center
-        //        contentLab.verticalAlignment = .center
-        //        contentLab.highlightedLinkBackgroundColor = UIColor.white
-        //        contentLab.numberOfLines = 0
-        //        contentLab.font = UIFont.systemFont(ofSize: 14)
-        //        contentLab.textColor = UIColor.hexColor(hexadecimal: "#666666")
-        let contentLab = UILabel()
-        contentLab.font = UIFont.systemFont(ofSize: 16)
-        contentLab.textAlignment = .center
-        contentLab.numberOfLines = 0
-        contentLab.textColor = UIColor.hexColor(hexadecimal: "#666666")
-        return contentLab
-    }()
-
-    lazy public var cancelBtn: UIButton = {
-        let cancelBtn = UIButton(type: .custom)
-        cancelBtn.setTitle("取消", for: .normal)
-        cancelBtn.setTitleColor(UIColor.black, for: .normal)
-        cancelBtn.tag = 1
-        cancelBtn.addTarget(self, action: #selector(btnClck(sender:)), for: .touchUpInside)
-        cancelBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium)
-        return cancelBtn
-    }()
-
-    lazy public var confirmBtn: UIButton = {
-        let confirmBtn = UIButton(type: .custom)
-        confirmBtn.setTitle("确定", for: .normal)
-        confirmBtn.setTitleColor(UIColor.black, for: .normal)
-        confirmBtn.tag = 2
-        confirmBtn.addTarget(self, action: #selector(btnClck(sender:)), for: .touchUpInside)
-        confirmBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium)
-        return confirmBtn
-    }()
-
-    lazy public var verticalLine: UIView = {
-        let verticalLine = UIView()
-        verticalLine.backgroundColor = UIColor.hexColor(hexadecimal: "#E5E5E5")
-        return verticalLine
-    }()
-
-    lazy public var horizonLine: UIView = {
-        let horizonLine = UIView()
-        horizonLine.backgroundColor = UIColor.hexColor(hexadecimal: "#E5E5E5")
-        return horizonLine
-    }()
-
-    override public init(frame: CGRect) {
-        super.init(frame: frame)
-        addSubview(contentView)
-        contentView.addSubview(titleLab)
-        contentView.addSubview(contentLab)
-        contentView.addSubview(cancelBtn)
-        contentView.addSubview(confirmBtn)
-        contentView.addSubview(verticalLine)
-        contentView.addSubview(horizonLine)
-        backgroundColor = cShadowColor
-    }
-
-    required public init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    public var  remindData: PQBaseModel? {
-        didSet {
-            addData()
-            addLayout()
-        }
-    }
-
-    open func addData() {
-        titleLab.text = remindData?.title
-        contentLab.text = remindData?.summary
-        cancelBtn.setTitleColor(isBanned ? (isBlank ? UIColor.white : UIColor.black) : (isBlank ? UIColor.white : UIColor.hexColor(hexadecimal: "#666666")), for: .normal)
-        if isBanned {
-            titleLab.textAlignment = .center
-        } else {
-            titleLab.textAlignment = .left
-        }
-    }
-
-   open func addLayout() {
-        var summH: CGFloat = 0
-        var titleH: CGFloat = 0
-        if (remindData?.summary?.count ?? 0) > 0 {
-            summH = sizeWithText(text: remindData?.summary ?? "", font: UIFont.systemFont(ofSize: 16, weight: .medium), size: CGSize(width: cScreenWidth - cDefaultMargin * 12, height: CGFloat.greatestFiniteMagnitude)).height + cDefaultMargin
-        }
-        if (remindData?.title?.count ?? 0) > 0 {
-            titleH = sizeWithText(text: remindData?.title ?? "", font: UIFont.systemFont(ofSize: 18, weight: .medium), size: CGSize(width: cScreenWidth - cDefaultMargin * 12, height: CGFloat.greatestFiniteMagnitude)).height + cDefaultMargin
-            if titleH < cDefaultMargin * 2 {
-                titleH = cDefaultMargin * 2
-            }
-        }
-        let contentH: CGFloat = cDefaultMargin * 2 + (titleH > 0 ? titleH + cDefaultMargin : 0) + (summH > 0 ? summH + cDefaultMargin : 0) + cDefaultMargin * 3 + (isBanned ? cDefaultMargin * 2 : 0)
-        contentView.snp.makeConstraints { make in
-            make.left.equalTo(self).offset(cDefaultMargin * 4)
-            make.right.equalTo(self).offset(-cDefaultMargin * 4)
-            make.height.equalTo(contentH)
-            make.center.equalTo(self)
-        }
-        titleLab.snp.makeConstraints { make in
-            make.left.equalTo(contentView).offset(cDefaultMargin * 2)
-            make.right.equalTo(contentView).offset(-cDefaultMargin * 2)
-            make.height.equalTo(titleH)
-            make.top.equalTo(contentView).offset(cDefaultMargin * 2)
-        }
-        contentLab.snp.makeConstraints { make in
-            make.top.equalTo(titleLab.snp_bottom).offset(summH > 0 ? cDefaultMargin : 0)
-            make.left.right.equalTo(titleLab)
-            make.height.equalTo(summH)
-        }
-        if isBanned {
-            let btnW: CGFloat = (cScreenWidth - 1 - cDefaultMargin * 8) / 2
-            verticalLine.snp.makeConstraints { make in
-                make.top.equalTo(contentLab.snp_bottom).offset(cDefaultMargin)
-                make.height.equalTo(1)
-                make.left.width.equalToSuperview()
-            }
-            cancelBtn.snp.makeConstraints { make in
-                make.left.equalToSuperview()
-                make.top.equalTo(verticalLine.snp_bottom)
-                make.width.equalTo(btnW)
-                make.bottom.equalTo(contentView)
-            }
-            horizonLine.snp.makeConstraints { make in
-                make.left.equalTo(cancelBtn.snp_right)
-                make.height.top.equalTo(cancelBtn)
-                make.width.equalTo(1)
-            }
-            confirmBtn.snp.makeConstraints { make in
-                make.right.equalToSuperview()
-                make.height.width.bottom.equalTo(cancelBtn)
-            }
-        } else {
-            confirmBtn.snp.makeConstraints { make in
-                make.right.equalTo(titleLab)
-                make.height.equalTo(cDefaultMargin * 4)
-                make.width.equalTo(cDefaultMargin * 6)
-                make.bottom.equalTo(contentView).offset(-cDefaultMargin)
-            }
-            cancelBtn.snp.makeConstraints { make in
-                make.right.equalTo(confirmBtn.snp_left).offset(-cDefaultMargin)
-                make.height.equalTo(cDefaultMargin * 4)
-                make.width.equalTo(cDefaultMargin * 6)
-                make.bottom.equalTo(confirmBtn)
-            }
-        }
-    }
-
-    @objc open func btnClck(sender: UIButton) {
-        removeFromSuperview()
-        if remindBlock != nil {
-            remindBlock!(sender, remindData!)
-        }
-    }
-}
-
-// MARK: 空白提示页
-
-/// 空白提示页
-open class PQEmptyRemindView: UIView {
-    // 回调
-    public var fullRefreshBloc: ((_ isNetConnected: Bool, _ emptyData: PQEmptyModel?) -> Void)?
-
-    lazy public var imageView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.backgroundColor = UIColor.clear
-        imageView.contentMode = .scaleAspectFit
-        return imageView
-    }()
-
-    lazy public var remindLab: UILabel = {
-        let remindLab = UILabel()
-        remindLab.font = UIFont.systemFont(ofSize: 16)
-        remindLab.numberOfLines = 1
-        remindLab.textAlignment = NSTextAlignment.center
-        remindLab.textColor = UIColor.white
-        return remindLab
-    }()
-
-    lazy public var shimmeringView: FBShimmeringView = {
-        let shimmeringView = FBShimmeringView()
-        shimmeringView.isShimmering = false
-        shimmeringView.shimmeringBeginFadeDuration = 0.3
-        shimmeringView.shimmeringEndFadeDuration = 0.1
-        shimmeringView.shimmeringOpacity = 0.2
-        shimmeringView.shimmeringSpeed = 300
-        shimmeringView.contentView = remindLab
-        return shimmeringView
-    }()
-
-    lazy public var remindSubLab: UILabel = {
-        let remindSubLab = UILabel()
-        remindSubLab.font = UIFont.systemFont(ofSize: 14)
-        remindSubLab.numberOfLines = 1
-        remindSubLab.textAlignment = NSTextAlignment.center
-        remindSubLab.textColor = UIColor.hexColor(hexadecimal: "#999999")
-        return remindSubLab
-    }()
-
-    lazy public var refreshBtn: UIButton = {
-        let refreshBtn = UIButton(type: .custom)
-        refreshBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#EE0051")
-        refreshBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
-        refreshBtn.setTitleColor(UIColor.white, for: .normal)
-        refreshBtn.setTitle("刷新", for: .normal)
-        refreshBtn.setTitle("重新连接网络", for: .selected)
-        refreshBtn.addCorner(corner: cDefaultMargin * 2)
-        refreshBtn.isHidden = true
-        refreshBtn.addTarget(self, action: #selector(fullRefresh), for: .touchUpInside)
-        return refreshBtn
-    }()
-
-    override public init(frame: CGRect) {
-        super.init(frame: frame)
-        addSubview(imageView)
-        addSubview(shimmeringView)
-        addSubview(remindSubLab)
-        addSubview(refreshBtn)
-        let ges = UITapGestureRecognizer(target: self, action: #selector(fullRefresh))
-        addGestureRecognizer(ges)
-        backgroundColor = PQBFConfig.shared.styleBackGroundColor
-    }
-
-    required public init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    @objc public var emptyData: PQEmptyModel? {
-        didSet {
-            addData()
-            addLayout()
-        }
-    }
-}
-
-extension PQEmptyRemindView {
-    public func addData() {
-        if !isNetConnected() {
-            remindLab.text = "网络连接失败,请检查网络后重试"
-            remindSubLab.isHidden = true
-            refreshBtn.isHidden = false
-            refreshBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#EE0051")
-            refreshBtn.setTitleColor(UIColor.white, for: .normal)
-            refreshBtn.setTitle("刷新", for: .normal)
-            imageView.image = UIImage.init().BF_Image(named:  "pic_network")
-        } else {
-            if emptyData?.emptyImage != nil, emptyData?.emptyImage?.count ?? 0 > 0 {
-                imageView.image = UIImage.init().BF_Image(named:  emptyData?.emptyImage ?? "")
-            } else {
-                imageView.image = nil
-            }
-            remindLab.text = emptyData?.title
-            remindSubLab.text = emptyData?.summary
-            refreshBtn.isHidden = emptyData?.isRefreshHidden ?? true
-            if emptyData?.refreshImage != nil, (emptyData?.refreshImage?.count ?? 0) > 0 {
-                refreshBtn.setImage(UIImage.init().BF_Image(named:  emptyData?.refreshImage ?? ""), for: .normal)
-            } else {
-                refreshBtn.setImage(nil, for: .normal)
-            }
-            refreshBtn.setAttributedTitle(emptyData?.refreshTitle, for: .normal)
-            if emptyData?.refreshBgColor != nil {
-                refreshBtn.backgroundColor = emptyData?.refreshBgColor
-            }
-        }
-    }
-
-    override public var isHidden: Bool {
-        didSet {
-            addData()
-            addLayout()
-        }
-    }
-
-    public func addLayout() {
-        var imageH: CGFloat = cDefaultMargin * 7
-        var contentH: CGFloat = 0
-
-        if (emptyData?.emptyImage != nil &&  emptyData?.emptyImage?.count ?? 0 > 0) || !isNetConnected() {
-            contentH = contentH + imageH + cDefaultMargin
-        } else {
-            imageH = 0
-        }
-        if emptyData?.title != nil, emptyData?.title?.count ?? 0 > 0 {
-            contentH = contentH + cDefaultMargin * 2 + cDefaultMargin
-        }
-        if emptyData?.summary != nil, emptyData?.summary?.count ?? 0 > 0 {
-            contentH = contentH + cDefaultMargin * 2 + cDefaultMargin
-        }
-        if !refreshBtn.isHidden {
-            contentH = contentH + cDefaultMargin + cDefaultMargin * 4
-        }
-        let topY = (frame.height - contentH) / 2
-        imageView.snp.remakeConstraints { make in
-            make.top.equalTo(topY)
-            make.centerX.equalTo(self)
-            make.height.equalTo(imageH)
-        }
-        shimmeringView.snp.makeConstraints { make in
-            make.left.right.equalTo(self)
-            make.top.equalTo(imageView.snp_bottom).offset(cDefaultMargin)
-        }
-        remindLab.snp.remakeConstraints { make in
-            make.size.equalToSuperview()
-        }
-        remindSubLab.snp.makeConstraints { make in
-            make.left.right.equalTo(self)
-            make.top.equalTo(remindLab.snp_bottom).offset(cDefaultMargin)
-        }
-        refreshBtn.snp.makeConstraints { make in
-            make.width.equalTo(cDefaultMargin * 13)
-            make.height.equalTo(cDefaultMargin * 4)
-            make.top.equalTo(remindSubLab.snp_bottom).offset(cDefaultMargin)
-            make.centerX.equalToSuperview()
-        }
-    }
-
-    @objc func fullRefresh() {
-        let isConnected: Bool = isNetConnected()
-        if !isConnected {
-            cShowHUB(superView: nil, msg: "网络不给力")
-        }
-        if fullRefreshBloc != nil {
-            fullRefreshBloc!(isConnected, emptyData)
-        }
-    }
-
-    func addShimmeringView() {}
-
-    func removeShimmeringView() {}
-}
-
-// MARK: - 上传提示框
-
-/// 上传提示框
-public class PQUploadRemindView: PQRemindView {
-    public var canMoreOpration: Bool = false // 是否还有更多操作
-    public var confirmTitle: String = "我知道了"
-    public var cancelTitle: String = "取消"
-    public var cacelColor: UIColor = UIColor.hexColor(hexadecimal: "#666666")
-    public var attributedTitle: NSAttributedString?
-
-    override public func addData() {
-        titleLab.textAlignment = .center
-        if attributedTitle != nil {
-            titleLab.attributedText = attributedTitle
-        } else {
-            titleLab.text = remindData?.title
-        }
-        if remindData?.attributedTitle != nil {
-            contentLab.attributedText = remindData?.attributedTitle
-        } else {
-            contentLab.text = remindData?.summary
-        }
-        cancelBtn.setTitleColor(cacelColor, for: .normal)
-        confirmBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#EE0051"), for: .normal)
-        confirmBtn.setTitle(confirmTitle, for: .normal)
-        cancelBtn.setTitle(cancelTitle, for: .normal)
-        let ges = UITapGestureRecognizer(target: self, action: #selector(removeView))
-        addGestureRecognizer(ges)
-    }
-
-    override public func addLayout() {
-        let titleH: CGFloat = ((remindData?.title != nil && (remindData?.title?.count ?? 0) > 0) || attributedTitle != nil) ? cDefaultMargin * 2 : 0
-
-        let summH: CGFloat = sizeTextFits(attributedText: remindData?.attributedTitle != nil ? remindData?.attributedTitle : NSMutableAttributedString(string: remindData?.summary ?? ""), text: nil, numberOfLines: 0, font: UIFont.systemFont(ofSize: 14), maxSize: CGSize(width: cScreenWidth - cDefaultMargin * 12, height: CGFloat.greatestFiniteMagnitude)).height + cDefaultMargin
-
-        let contentH: CGFloat = (titleH == 0 ? 0 : cDefaultMargin * 3) + cDefaultMargin * 2 + summH + cDefaultMargin + cDefaultMargin * 5
-
-        contentView.snp.makeConstraints { make in
-            make.left.equalTo(self).offset(cDefaultMargin * 3)
-            make.right.equalTo(self).offset(-cDefaultMargin * 3)
-            make.height.equalTo(contentH)
-            make.center.equalTo(self)
-        }
-        titleLab.snp.makeConstraints { make in
-            make.left.equalTo(contentView).offset(cDefaultMargin * 2)
-            make.right.equalTo(contentView).offset(-cDefaultMargin * 2)
-            make.height.equalTo(titleH)
-            make.top.equalTo(contentView).offset(titleH == 0 ? 0 : cDefaultMargin * 2)
-        }
-        contentLab.snp.makeConstraints { make in
-            make.top.equalTo(titleLab.snp_bottom).offset(cDefaultMargin)
-            make.left.right.equalTo(titleLab)
-            make.height.equalTo(summH)
-        }
-        if canMoreOpration {
-            let btnW: CGFloat = (cScreenWidth - 1 - cDefaultMargin * 8) / 2
-            verticalLine.snp.makeConstraints { make in
-                make.top.equalTo(contentLab.snp_bottom).offset(cDefaultMargin)
-                make.height.equalTo(1)
-                make.left.width.equalToSuperview()
-            }
-            cancelBtn.snp.makeConstraints { make in
-                make.left.equalToSuperview()
-                make.top.equalTo(verticalLine.snp_bottom)
-                make.width.equalTo(btnW)
-                make.bottom.equalTo(contentView)
-            }
-            horizonLine.snp.makeConstraints { make in
-                make.left.equalTo(cancelBtn.snp_right)
-                make.height.top.equalTo(cancelBtn)
-                make.width.equalTo(1)
-            }
-            confirmBtn.snp.makeConstraints { make in
-                make.right.equalToSuperview()
-                make.height.width.bottom.equalTo(cancelBtn)
-            }
-        } else {
-            verticalLine.snp.makeConstraints { make in
-                make.top.equalTo(contentLab.snp_bottom).offset(cDefaultMargin)
-                make.height.equalTo(1)
-                make.left.width.equalToSuperview()
-            }
-            confirmBtn.snp.makeConstraints { make in
-                make.right.left.equalTo(titleLab)
-                make.top.equalTo(verticalLine.snp_bottom)
-                make.bottom.equalTo(contentView)
-            }
-        }
-    }
-
-    @objc func removeView() {
-        removeFromSuperview()
-    }
-
-    @objc public override func btnClck(sender: UIButton) {
-        removeFromSuperview()
-        if remindBlock != nil {
-            remindBlock!(sender, remindData!)
-        }
-    }
-
-    /// 快速生成
-    /// - Parameters:
-    ///   - title: <#title description#>
-    ///   - summary: <#summary description#>
-    ///   - confirmTitle: <#confirmTitle description#>
-    ///   - remindHandle: <#remindHandle description#>
-    /// - Returns: <#description#>
-    class public func showUploadRemindView(title: String?, attributedTitle: NSAttributedString? = nil, summary: String, canMoreOpration: Bool = false, confirmTitle: String?, cancelTitle: String? = nil, cancelColor: UIColor? = nil, remindHandle: @escaping (_ sender: UIButton, _ baseModel: PQBaseModel?) -> Void) {
-        if UIApplication.shared.keyWindow?.viewWithTag(cUploadViewRemindTag) != nil {
-            UIApplication.shared.keyWindow?.viewWithTag(cUploadViewRemindTag)?.removeFromSuperview()
-        }
-        let remindData = PQBaseModel()
-        let paragraphStyle = NSMutableParagraphStyle()
-        paragraphStyle.lineSpacing = 3.0
-        paragraphStyle.alignment = .center
-        remindData.title = title
-        remindData.attributedTitle = NSMutableAttributedString(string: summary, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor.hexColor(hexadecimal: "#666666"), NSAttributedString.Key.paragraphStyle: paragraphStyle])
-        let remindView = PQUploadRemindView(frame: CGRect(x: 0, y: 0, width: cScreenWidth, height: cScreenHeigth))
-        remindView.canMoreOpration = canMoreOpration
-        if confirmTitle != nil {
-            remindView.confirmTitle = confirmTitle!
-        }
-        if cancelTitle != nil {
-            remindView.cancelTitle = cancelTitle!
-        }
-        if cancelColor != nil {
-            remindView.cacelColor = cancelColor!
-        }
-        if attributedTitle != nil {
-            remindView.attributedTitle = attributedTitle
-        }
-        remindView.remindBlock = { sender, baseModel in
-            remindHandle(sender, baseModel)
-        }
-        remindView.tag = cUploadViewRemindTag
-        UIApplication.shared.keyWindow?.addSubview(remindView)
-        remindView.remindData = remindData
-    }
-}

+ 0 - 27
BFFramework/Classes/Base/View/PQTabBar.swift

@@ -1,27 +0,0 @@
-//
-//  PQTabBar.swift
-//  PQSpeed
-//
-//  Created by SanW on 2021/1/18.
-//  Copyright © 2021 BytesFlow. All rights reserved.
-//
-
-import UIKit
-
-public class PQTabBar: UITabBar {
-    override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
-        if isHidden { // 如果隐藏的话不处理事件
-            return super.hitTest(point, with: event)
-        }
-        let view = super.hitTest(point, with: event)
-        if view == nil {
-            for subView in subviews {
-                let myPoint = subView.convert(point, from: self)
-                if subView.bounds.contains(myPoint) {
-                    return subView
-                }
-            }
-        }
-        return view
-    }
-}

+ 0 - 106
BFFramework/Classes/Base/View/PQTextView.swift

@@ -1,106 +0,0 @@
-//
-//  PQTextView.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/6/11.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-
-open class PQTextView: UITextView {
-    private let textValuesQueue = DispatchQueue(label: "com.BytesFlow.textValuesQueue", qos: .default)
-
-   public var textDidChangedHandle: ((_ textView: UITextView) -> Void)?
-    // 最多输入的个数
-    public  var maxTextLength : Int?
-    // 输入个数超过时提示
-    public  var maxTextLengthRemind : String?
-    // add by ak 默认字的起点位置
-    public  var placeHolderDefultPoint = CGPoint.init(x: 5, y: 7)
-    /// setNeedsDisplay调用drawRect
-    public  var placeHolder: String = "" {
-        didSet {
-            setNeedsDisplay()
-        }
-    }
-
-    /// placeHolder是否居中
-    public  var isCenter: Bool = false {
-        didSet {
-            setNeedsDisplay()
-        }
-    }
-
-    public var placeHolderColor: UIColor = UIColor.gray {
-        didSet {
-            setNeedsDisplay()
-        }
-    }
-
-    open override var font: UIFont? {
-        didSet {
-            setNeedsDisplay()
-        }
-    }
-
-    open override var text: String! {
-        didSet{
-           setNeedsLayout()
-        }
-    }
-
-    open override var attributedText: NSAttributedString! {
-        didSet {
-            setNeedsDisplay()
-        }
-    }
-
-    public override init(frame: CGRect, textContainer: NSTextContainer?) {
-        super.init(frame: frame, textContainer: textContainer)
-        /// default字号
-        PQNotification.addObserver(self, selector: #selector(textDidChanged(noti:)), name: UITextView.textDidChangeNotification, object: self)
-    }
-
-    required public init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    @objc func textDidChanged(noti _: NSNotification) {
-        if maxTextLength != nil && text.count > maxTextLength! {
-            text = String(text.prefix(maxTextLength!))
-            cShowHUB(superView: nil, msg: (maxTextLengthRemind != nil && (maxTextLengthRemind?.count ?? 0) > 0) ? maxTextLengthRemind : "最多输入\( maxTextLength!)个字符")
-        }
-        setNeedsDisplay()
-        if textDidChangedHandle != nil {
-            textDidChangedHandle!(self)
-        }
-    }
-
-    open override func draw(_ rect: CGRect) {
-        if hasText {
-            return
-        }
-        let size = sizeWithText(text: placeHolder, font: font ?? UIFont.systemFont(ofSize: 14), size: rect.size)
-        var newRect = CGRect()
-        newRect.size.width = size.width
-        newRect.size.height = size.height
-        if isCenter {
-            newRect.origin.x = (rect.width - size.width) / 2
-            newRect.origin.y = (rect.height - size.height) / 2
-        } else {
-            newRect.origin.x = placeHolder.contains("未识别到文字") ? 0 : placeHolderDefultPoint.x
-            newRect.origin.y = placeHolder.contains("未识别到文字") ? 0 : placeHolderDefultPoint.y
-        }
-        (placeHolder as NSString).draw(in: newRect, withAttributes: [NSAttributedString.Key.font: font ?? UIFont.systemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: placeHolderColor])
-    }
-
-    open override func layoutSubviews() {
-        super.layoutSubviews()
-        setNeedsDisplay()
-    }
-
-    deinit {
-        PQNotification.removeObserver(self, name: UITextView.textDidChangeNotification, object: self)
-    }
-}

+ 0 - 813
BFFramework/Classes/Enums/Enums.swift

@@ -1,813 +0,0 @@
-//
-//  public  enum s.swift
-//  PQSpeed
-//
-//  Created by lieyunye on 2020/5/29.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-
-// MARK: - 视频播放页面类型
-
-/// 视频播放页面类型
-public  enum  PQVIDEOPAGETYPE {
-    case PQVIDEOPAGETYPE_Normal // 默认-单个视频详情
-    case PQVIDEOPAGETYPE_RECOMM // 默认-推荐
-    case PQVIDEOPAGETYPE_ATTEN // 关注
-    case PQVIDEOPAGETYPE_DETAIL // 用户发布视频详情
-    case PQVIDEOPAGETYPE_LIKEDETAIL // 我的喜欢视频详情
-    case PQVIDEOPAGETYPE_ATTUSERDETAIL // 关注用户详情
-    case PQVIDEOPAGETYPE_SEARCHDETAIL // 搜索详情
-    case PQVIDEOPAGETYPE_HOTVIDEODETAIL // 热门视频详情
-    case PQVIDEOPAGETYPE_GUIDEVIDEODETAIL // 引导视频详情
-    case PQVIDEOPAGETYPE_SINGLEVIDEODETAIL // 单个视频详情
-    case PQVIDEOPAGETYPE_RECREATDETAIL // 再创作详情页
-}
-
-// MARK: - 视频播放状态
-
-/// 视频播放状态
-public  enum  PQVIDEO_PLAY_STATUS {
-    case PQVIDEO_PLAY_STATUS_LOADING // 加载中
-    case PQVIDEO_PLAY_STATUS_BEGIN // 开始播放
-    case PQVIDEO_PLAY_STATUS_END // 播放结束
-    case PQVIDEO_PLAY_STATUS_DISCONNECT // 重连失败
-    case PQVIDEO_PLAY_STATUS_NOT_FOUND // 播放文件不存在
-    case PQVIDEO_PLAY_STATUS_RECONNECT // 重连连接
-}
-
-// MARK: - 页面场景
-
-/// 页面场景
-public  enum  PAGESOURCE: String {
-    /*************** 视频相关pageSource ***************/
-    case sp_category = "shanyinApp-category" //   首页-单列
-    case sp_category_recommend = "shanyinApp-category_recommend" // 由首页单列右划
-    case sp_categoryDouble = "shanyinApp-categoryDouble" // 首页-双列
-    case sp_videoDetail = "shanyinApp-videoDetail" // 视频详情页
-    case sp_videoDetail_search = "shanyinApp-videoDetail_search" //    由搜索结果列表进入
-    case sp_videoDetail_search_recommend = "shanyinApp-videoDetail_search_recommend" // 由搜索结果列表进入
-    case sp_videoDetail_upload = "shanyinApp-videoDetail_upload" //     由我的tab中“作品”列表进入
-    case sp_videoDetail_upload_recommend = "shanyinApp-videoDetail_upload_recommend" // 、由我的tab中“作品”列表进入
-    case sp_videoDetail_favorite = "shanyinApp-videoDetail_favorite" // 由我的喜欢列表进入
-    case sp_videoDetail_share = "shanyinApp-videoDetail_share" // 由我的分享列表进入
-    case sp_videoDetail_favorite_recommend = "shanyinApp-videoDetail_favorite_recommend" // 由我的喜欢列表推荐
-    case sp_userHomePage = "shanyinApp-userHomePage" // 用户个人主页
-    case sp_videoDetail_userHomePage = "shanyinApp-videoDetail_userHomePage" // 由用户个人主页进入
-    case sp_videoDetail_userHomePage_recommend = "shanyinApp-videoDetail_userHomePage_recommend" // 由用户个人主页进入
-    case sp_recommendBottom = "shanyinApp-recommendBottom" //    底部展示的3个相关推荐视频
-    case sp_follow = "shanyinApp-follow" // 关注tab
-    case sp_follow_recommend = "shanyinApp-follow_recommend" // 由关注列表右划
-    case sp_followSingle = "shanyinApp-followSingle" // 关注tab点击顶部个人头像进入某个人的关注
-    case sp_followSingle_recommend = "shanyinApp-followSingle_recommend" // 关注tab点击顶部个人头像进入某个人的关注
-//    case sp_mine = "shanyinApp-mine" // 我的tab
-    case sp_search = "shanyinApp-search" // 搜索页
-    case sp_uploadVideo = "shanyinApp-uploadVideo" // 视频制作入口
-
-    /*************** 活动相关pageSource ***************/
-    case sp_activity_entranceButton = "shanyinApp_playActivity_entranceButton" // 活动活动入口按键
-    case sp_activity_invite = "shanyinApp_playActivity_invite" // H5页面内邀请好友按键
-    case sp_activity_threeDot = "shanyinApp_playActivity_threeDot" // APP右上角…按键
-    case sp_activity_shareFriend = "shanyinApp_playActivity_shareFriend" // 进一步点击分享好友
-    case sp_activity_shareMoment = "shanyinApp_playActivity_shareMoment" // 进一步点击分享朋友圈
-    case sp_activity_openH5 = "shanyinApp_playActivity_completeOpenH5" // 当天完成活动的弹窗->去查看
-    case sp_activity_openH5AndPayment = "shanyinApp_playActivity_completeOpenH5AndPayment" // 当天完成活动的弹窗->报名明日
-    case sp_activity_failOpenH5 = "shanyinApp_playActivity_missionFailWindowOpenH5" // 未成功弹窗->继续活动
-    case sp_activity_success_share = "shanyinApp_playActivity_missionSuccessWindow_share" // 成功弹窗->分享给好友炫耀下
-    case sp_activity_entrance_close = "shanyinApp_playActivity_entrance_close" // 活动入口弹窗->关闭按钮
-    case sp_activity_entranceWindow = "shanyinApp_playActivity_entranceWindow" // 活动入口弹窗
-    case sp_activity_successWindow = "shanyinApp_playActivity_missionSuccessWindow" // 成功弹窗
-    case sp_activity_failWindow = "shanyinApp_playActivity_missionFailWindow" // 未成功弹窗
-    case sp_activity_completeWindow = "shanyinApp_playActivity_missionCompleteWindow" //  当天完成活动的弹窗
-
-    /*************** 上传相关pageSource ***************/
-    case sp_upload_videoSelect = "shanyinApp-upload_videoSelect" //  选视频-进入页面事件
-    case sp_upload_coverSelect = "shanyinApp-upload_coverSelect" //  选封面-进入页面事件
-    case sp_upload_videoPublish = "shanyinApp-upload_videoPublish" //  发布-进入页面事件
-
-    /*************** tab点击相关pageSource ***************/
-    case sp_categoryTabButton = "shanyinApp-categoryTabButton" //  首页tab
-    case sp_followTabButton = "shanyinApp-followTabButton" //  关注tab
-    case sp_uploadTabButton = "shanyinApp-uploadTabButton" //  上传tab
-    case sp_mineTabButton = "shanyinApp-mineTabButton" //  我的tab
-    case sp_msg_tabBtn = "shanyinApp_msgTabButton" //  消息tab
-
-    /*************** 发布pageSource ***************/
-    case sp_videoMaking = "shanyinApp-videoMaking" // 视频创作
-    case sp_videoCompose_guid = "shanyinApp-videoCompose_guid" // 预览页面
-    case sp_videoCompose_edit = "shanyinApp-videoCompose_edit" // 编辑页面
-    case sp_videoCompose_overview = "shanyinApp-videoCompose_overview" // 总览页面
-    case sp_videoCompose_composition = "shanyinApp-videoCompose_composition" // 合成页面
-    case sp_material_search = "vlog-pages/user-videos-share" // 素材搜索上报
-
-    /*************** 消息pageSource ***************/
-    case sp_msg_shareSpace = "shanyinApp-message" // 分享空间
-    case sp_msg_shareSpace_detail = "shanyinApp-message_shareSpace" // 分享空间详情
-    case sp_msg_share = "shanyinApp-message_share" // 分享
-    case sp_msg_like = "shanyinApp-message_like" // 喜欢
-    case sp_msg_fans = "shanyinApp-message_fans" // 粉丝
-    case sp_msg_push = "shanyinApp-message_push" // 通知
-
-    /*************** 草稿箱相关pageSource ***************/
-    case sp_draft_projectList = "shanyinApp-projectList" // 草稿箱列表
-    case sp_reproduce_childList = "shanyinApp-reproduceCollection_child" // 再制作子列表页面
-    case sp_reproduce_fatherList = "shanyinApp-reproduceCollection_father" // 再制作父列表页面
-    case sp_reproduce_chilDetailList = "shanyinApp-videoDetail_reproduceCollection_child" // 再制作子列表页面
-    case sp_reproduce_fatherDetailList = "shanyinApp-videoDetail_reproduceCollection_father" // 再制作父列表页面
-    // add by ak
-    case sp_speedApp_upload2Compose = "shanyinApp-upload2Compose" // 上传转创作
-
-    /*************** 卡点视频相关pageSource ***************/
-    case sp_stuck_selectMaterial = "shanyinApp-selectSyncedUpMaterial" // 卡点视频素材选择页
-    case sp_stuck_selectSynceedUpMusic = "shanyinApp-selectSynceedUpMusic" // 卡点视频音乐选择页
-    case sp_stuck_previewSyncedUp = "shanyinApp_previewSyncedUp" // 预览页面曝光上报
-    case sp_stuck_searchSyncedUpMusic = "shanyinApp_searchSyncedUpMusic" // 音乐素材搜索页
-    case sp_stuck_publishSyncedUp = "shanyinApp_publishSyncedUp" // 合成发布页
-    
-    //点击上报:首页点击底部“我的”页面入口
-    case sp_shanyinApp_main = "shanyinApp-main"
-    //页面曝光上报:“我的”页面曝光
-    case sp_shanyinApp_mine = "shanyinApp-mine"
-  
-
-}
- 
-/// objectType
-public  enum  objectType: String {
-    /*************** tab点击相关pageSource ***************/
-
-    case ot_home_tabBtn = "shanyinApp-categoryTabButton" //  首页tab
-    case ot_follow_tabBtn = "shanyinApp-followTabButton" //  关注tab
-    case ot_up_tabBtn = "shanyinApp-uploadTabButton" //  上传tab
-    case ot_mine_tabBtn = "shanyinApp-mineTabButton" //  我的tab
-    case ot_public_tabBtn = "shanyinApp-publicTabButton" //  发布tab
-    case ot_msg_tabBtn = "shanyinApp_msgTabButton" //  消息tab
-
-    /*************** 上传相关objectType ***************/
-    case ot_up_backBtn = "shanyinApp-uploadBackButton" // 点击左下角叉子
-    case ot_up_nextBtn = "shanyinApp-uploadNextButton" // 点击右下角下一步
-    case ot_up_coverBtn = "shanyinApp-uploadCoverButton" // 点击上传封面
-    case ot_up_pickCoverBtn = "shanyinApp-pickCoverButton" // 点击截取封面
-    case ot_up_publishBtn = "shanyinApp-videoPublishButton" // 点击发布
-    case ot_up_changeCoverBtn = "shanyinApp-changeCoverButton" // 点击选封面返回
-    case ot_up_start = "shanyinApp-uploadStart" // 上传开始事件
-    case ot_up_fail = "shanyinApp-uploadFail" // 上传中断/失败事件
-    case ot_up_restart = "shanyinApp-uploadRestart" // 上传重试事件
-    case ot_up_success = "shanyinApp-uploadSuccess" // 上传完成
-    case ot_up_publishSuccess = "shanyinApp-videoPublishSuccess" // 发布完成
-    case ot_up_viewPopup_guideUsersToShare = "shanyinApp_viewPopup_guideUsersToShare_pubishVideo" // 发布成功弹出分享界面
-    case ot_up_clickWechatMoments_guideUsersToShare = "shanyinApp_clickWechatMoments_guideUsersToShare_pubishVideo" // 分享介面点击微信朋友圈
-    case ot_up_clickWechat_guideUsersToShare = "shanyinApp_clickWechat_guideUsersToShare_pubishVideo"
-    case ot_selectVideoProductionMode = "shanyinApp_viewWindow_selectVideoProductionMode"
-    // 分享界面点击微信好友
-    /*************** 创作工具相关objectType ***************/
-    case ot_makevideo_video = "video" // 视频
-    case ot_makevideo_gif = "gif" // 动态图
-    case ot_makevideo_jpg = "jpg" // 图片
-    case ot_enterComposeToolButton = "shanyinApp_enterComposeToolButton" // 点击上传tab后-点击发布视频 add by ak & 视频合成入口
-    case ot_enterVideoUploadButton = "shanyinApp_enterVideoUploadButton" // 点击上传tab后-点击上传视频
-    case ot_videoCompose_overviewButton = "shanyinApp_videoCompose_overviewButton" // 点击总览
-    case ot_videoCompose_videoCompositeButton = "shanyinApp_videoCompose_videoCompositeButton" // 点击去发布
-    case ot_videoCompose_videoPublish = "shanyinApp_videoPublishButton" // 发布视频
-    case ot_speedApp_searchButton = "shanyinApp_searchButton" // 发布视频
-    case ot_pageView = "pageView" // 页面访问
-    //
-    // 图文入口
-    case ot_speedApp_clickButton_imageAndTextGenerateVideo = "shanyinApp_clickButton_imageAndTextGenerateVideo"
-    // 电子相册
-    case ot_speedApp_clickButton_electronicAlbum = "shanyinApp_clickButton_electronicAlbum"
-    /*************** 消息相关objectType ***************/
-    case ot_msg_fansMsgButton = "shanyinApp_msgTab_fansMsgButton" //  粉丝消息入口
-    case ot_msg_likeMsgButton = "shanyinApp_msgTab_likeMsgButton" //  喜欢消息入口
-    case ot_msg_shareMsgButton = "shanyinApp_msgTab_shareMsgButton" //  分享消息入口
-    case ot_msg_commentMsgButton = "shanyinApp_msgTab_commentMsgButton" //  评论消息入口
-    case ot_msg_systemMsgButton = "shanyinApp_msgTab_systemMsgButton" //  通知消息入口
-
-    /*************** 消息详情相关objectType ***************/
-    case ot_msg_shareSpaceViewTab = "shanyinApp_message_shareSpace_viewTab" // 分享空间详情页观看
-    case ot_msg_shareSpaceLikeTab = "shanyinApp_message_shareSpace_likeTab" // 分享空间详情页喜欢
-    case ot_msg_shareSpaceCommentTab = "shanyinApp_message_shareSpace_commentTab" // 分享空间详情页评论
-    case ot_msg_shareSpaceShareTab = "shanyinApp_message_shareSpace_shareTab" // 分享空间详情页分享
-
-    /*************** 草稿箱相关objectType ***************/
-    case ot_draft_clicktButton = "shanyinApp_clickOpenProjectListButton" // 草稿箱点击入口
-    case ot_draft_editProject = "shanyinApp_editProject" // - 点击 Project Item(草稿箱中的每个项目)
-    case ot_draft_viewProject = "shanyinApp_viewProject" // - 看到 Project Item(草稿箱中的每个项目)
-    case ot_draft_clickEditProject = "shanyinApp_clickEditProject" // - 点击 Project Item 弹出菜单的「编辑」按钮
-    case ot_draft_clickPublishProject = "shanyinApp_clickPublishProject" // - 点击 Project Item 弹出菜单的「去发布」按钮
-    case ot_draft_clickRenameProject = "shanyinApp_clickRenameProject" // - 点击 Project Item 弹出菜单的「重命名」按钮
-    case ot_draft_clickCopyProject = "shanyinApp_clickCopyProject" // - 点击 Project Item 弹出菜单的「复制」按钮
-    case ot_draft_clickDeleteProject = "shanyinApp_clickDeleteProject" // - 点击 Project Item 弹出菜单的「删除」按钮
-    case ot_draft_uploadMaterial = "shanyinApp_uploadMaterial" // - 素材开始上传事件
-    case ot_draft_uploadMatrialSuccess = "shanyinApp_uploadMatrialSuccess" // - 素材上传成功事件
-    case ot_draft_downloadMaterial = "shanyinApp_downloadMaterial" // - 素材开始下载事件
-    case ot_draft_downloadMaterialSuccess = "shanyinApp_downloadMaterialSuccess" // - 素材下载成功事件
-    case ot_videoCompose_mux_complete = "shanyinApp_videoCompose_mux_complete" // 创作工具「合成成功」添加上报参数
-
-    case ot_reproduce_collectionClicButton = "shanyinApp_clickReproduceButton_collection" // - 再创作集合页的「再创作按钮」
-    case ot_reproduce_clickButton = "shanyinApp_clickReProduceButton" // 再创作按钮(右上角)点击上报
-    case ot_reproduce_collectionBar = "shanyinApp_clickReproduceCollectionBar" // 再创作按钮(左下角)点击上报
-    case ot_reproduce_collectionVideo = "shanyinApp_clickReproduceCollectionVideo" // 再创作集合页的「视频」点击上报
-    case ot_reproduce_sameSourceButton = "shanyinApp_viewSameSourceButton" // 再创作查看同款来源按钮
-    case ot_reproduce_saveProjectToDraftBox = "shanyinApp-saveProjectToDraftBox" // 创作工具「保存项目成功」添加上报参数
-    // add by ak
-    case speedApp_viewWindow_upload2Compose // 「上传转创作」:窗口曝光
-    case speedApp_clickButton_upload2Compose_addMusic // 「上传转创作」:加音乐 - 按钮点击
-    case speedApp_clickButton_upload2Compose_addText // 「上传转创作」:加语音 - 按钮点击
-    case speedApp_clickButton_upload2Compose_addVoice // 「上传转创作」:加语音 - 按钮点击
-    case speedApp_clickButton_upload2Compose_addCompose // 上传转创作」:加多段拼接 - 按钮点击
-    case speedApp_clickButton_upload2Compose_processingVideo // 「上传转创作」:加工视频 - 按钮点击
-    case speedApp_clickButton_upload2Compose_publish // 「上传转创作」:直接发布 - 按钮点击
-    case speedApp_viewButton_uploadCoverButton // 「发布页」:修改封面 - 按钮曝光
-    case speedApp_viewButton_uploadCoverTipButton // 修改封面提示 - 按钮曝光
-    case speedApp_clickButton_uploadCoverButton // 「发布页」:修改封面 - 按钮点击
-    case speedApp_clickButton_uploadCoverTipButton
-
-    case speedApp_viewButton_addMusic // 「创作工具页」:添加音乐 - 按钮曝光
-    case speedApp_clickButton_addMusic // 「创作工具页」:添加音乐 - 按钮点击
-    case speedApp_viewButton_addMusicTip // 创作工具页」:添加音乐提示 - 按钮曝光
-    case speedApp_clickButton_addMusicTip // 「创作工具页」:添加音乐提示 - 按钮点击
-
-    /*************** 卡点视频相关objectType ***************/
-    case ot_view_selectSyncedUpMaterial = "shanyinApp_viewWindow_selectSyncedUpMaterial" // 曝光上报:卡点视频素材选择页
-    case ot_click_confirmMaterial = "shanyinApp_clickButton_confirmSyncedUpMaterial" // 点击上报:卡点视频素材确认按钮
-    case ot_click_back = "shanyinApp_clickButton_back" // 点击上报:返回按钮
-    case ot_view_selectSyncedUpMusic = "shanyinApp_viewWindow_selectSyncedUpMusic" // 曝光上报:卡点视频音乐选择页
-    case ot_view_syncedUpMusic = "shanyinApp_viewButton_syncedUpMusic" // 曝光上报:音乐素材曝光
-    case ot_click_auditionMusic = "shanyinApp_clickButton_auditionMusic" // 点击上报:音乐素材试听
-    case ot_click_chooseMusic = "shanyinApp_clickButton_chooseMusic" // 点击上报:选择音乐素材
-    case ot_click_chooseMusicCategory = "shanyinApp_clickButton_chooseMusicCategory" // 点击上报:选择音乐分类
-    case ot_click_chooseMusicCategoryTag = "shanyinApp_clickButton_chooseMusicCategoryTag" // 点击上报:选择音乐分类下的 TAG
-    case ot_view_previewSyncedUp = "shanyinApp_viewWindow_previewSyncedUp" // 曝光上报:预览页面曝光上报
-    case ot_click_selectMusic = "shanyinApp_clickButton_selectMusic" // 点击上报:重新选择音乐
-    case ot_click_selectRhythm = "shanyinApp_clickButton_selectRhythm" // 点击上报:选择节奏
-    case ot_click_dragFront = "shanyinApp_clickButton_dragFront" // 点击上报:拖动拖拽条(左部分)
-    case ot_click_dragBehind = "shanyinApp_clickButton_dragBehind" // 点击上报:拖动拖拽条(右部分)
-    case ot_click_commit = "shanyinApp_clickButton_commit" // 点击上报:去合成
-    case ot_view_searchSyncedUpMusic = "shanyinApp_viewWindow_searchSyncedUpMusic" // 曝光上报:音乐素材搜索页
-    case ot_click_searchSyncedUpMusic = "shanyinApp_clickButton_searchSyncedUpMusic" // 点击上报:用户在搜索框输入文字然后按回车
-    case ot_view_searchMusic = "shanyinApp_viewButton_searchMusic" // 曝光上报:搜索结果音乐素材曝光
-    case ot_click_auditionSearchMusic = "shanyinApp_clickButton_auditionSearchMusic" // 点击上报:试听音乐素材
-    case ot_click_chooseSearchMusic = "shanyinApp_clickButton_chooseSearchMusic" // 点击上报:选择音乐素材
-    case ot_view_publishSyncedUp = "shanyinApp_viewWindow_publishSyncedUp" // 曝光上报:窗口曝光
-    case ot_click_shareWechat = "shanyinApp_clickButton_shareWechat" // 点击上报:分享微信
-    case ot_click_shareWechatMoment = "shanyinApp_clickButton_shareWechatMoment" // 点击上报:分享朋友圈
-    case ot_click_finished = "shanyinApp_clickButton_finished" // 点击上报:完成
-    
-    
-    //闪音点击上报:首页点击底部+
-    case ot_shanyinApp_clickButton_syncedUpMusic = "shanyinApp_clickButton_syncedUpMusic"
-
-    //视频播放点击
-    case ot_shanyinApp_clickButton_syncedUpMusicRecreate = "shanyinApp_clickButton_syncedUpMusicRecreate"
-    case ot_shanyinApp_viewButton_syncedUpMusicRecreate = "shanyinApp_viewButton_syncedUpMusicRecreate"
-    //点击上报:首页点击底部“我的”页面入口
-    case ot_shanyinApp_clickButton_mineTab = "shanyinApp_clickButton_mineTab"
-    //页面曝光上报:“我的”页面曝光
-    case ot_shanyinApp_viewPage_mineTab = "shanyinApp_viewPage_mineTab"
-    
-    //编辑标题和封面
-    case ot_shanyinApp_clickButton_changeTitle = "shanyinApp_clickButton_changeTitle"
-    case ot_shanyinApp_clickButton_changeCover = "shanyinApp_clickButton_changeCover"
-
-
-}
-
-// MARK: - 视频上报类型
-
-/// 视频上报类型
-public  enum  businessType: String {
-    /*************** 视频相关businessType ***************/
-    case bt_videoView = "videoView" //  视频展示到屏幕,在此APP中 首页中:视频展示但未播放时,用于后端算法相关逻辑 相关推荐:在播放中下部展示出相关推荐的3个视频时,上报这3个视频的videoView。同一次播放下不重复上报3个推荐视频的videoView
-    case bt_videoPreView = "videoPreView"
-    case bt_videoPlaySlow = "videoPlaySlow"
-    case bt_videoPlayError = "videoPlayError" // 播放失败
-    case bt_aliasBindingError = "aliasBindingError" // 绑定别名失败
-    case bt_videoPlaySuccessTime = "videoPlaySuccessTime" // 加载时长
-    case bt_videoPlayException = "videoPlayException"
-    case bt_videoPlay_normal = "videoPlay"
-    public  enum  bt_videoPlay: String {
-        case bt_videoPlay_userSlideSingle = "userSlideSingle" // 用户在沉浸态下滑动切换视频(极速版、爱电影)
-        case bt_videoPlay_userClickCover = "userClickCover" // 用户点击封面播放
-        case bt_videoPlay_userSlideList = "userSlideList" // 用户在列表中滑动停止导致的播放
-        case bt_videoPlay_autoNext = "autoNext" // 自动播放下一个视频
-        case bt_videoPlay_autoStart = "autoStart" // 1、启动后自动播第一个视频 2、播放器出问题导致重新播放 3、别的页面返回之前的页面播放
-    }
-
-    case bt_videoShareH5 = "videoShareH5" // 点击分享朋友圈按键
-    case bt_videoShareFriend = "videoShareFriend" // 点击分享好友按键
-    case bt_videoSemiRealPlay = "videoSemiRealPlay" // 视频播放到10s时上报
-    case bt_videoRealPlay = "videoRealPlay" // 视频播放到20s或播放到总时长30%,哪个先到为准
-    case bt_videoPlaySuccess = "videoPlaySuccess" // 视频缓冲完成开始播放
-    case bt_videoPlayEnd = "videoPlayEnd" // 视频播放到总时长100%
-    case bt_videoFavorite = "videoFavorite" // 视频喜欢的上报
-    case bt_videoEnterUser = "videoEnterUserHomepage" // 在视频页点击 Up 主头像进入个人主页
-    case bt_videoSwipeRight = "videoSwipeRight" // 右滑查看视频的相关推荐
-    case bt_videoEnterRecom = "videoEnterRecomendation" // 点击视频的相关推荐
-
-    /*************** 活动相关businessType ***************/
-    case bt_buttonClick = "buttonClick" // 按键点击
-    case bt_buttonView = "buttonView" // 按键曝光
-    case bt_windowView = "windowView" // 弹窗曝光
-    case bt_autoJump = "autoJump" // 自动跳转
-    case bt_pageView = "pageView" // 页面访问
-
-    /*************** 供给稳定性相关businessType ***************/
-    case bt_fetchSlow = "FetchSlow" // 拉取卡顿率
-    case bt_fetchFail = "FetchFail" // 拉取失败率
-    case bt_fetchDuration = "FetchDuration" // 拉取时长
-    case bt_dnsParseCostTime = "dnsParseCostTime" // DNS上报 "speed.piaoquantv.com", "rescdn.yishihui.com"
-
-    /*************** 上传相关businessType ***************/
-    case bt_up_process = "videoUploadProcess" // 上传开始事件
-    case bt_publish_error = "publishError" // 发布失败
-    case bt_publish_success = "publishSuccess" // 发布成功
-
-    /*************** 创作工具相关businessType ***************/
-    case bt_makeVideos = "makeVideos" // 创作视频
-    case bt_materialView = "materialView" // 素材曝光
-    case bt_materialUse = "materialUse" // 用户选取
-    case bt_materialCompose = "materialCompose" // 素材合成
-
-    /*************** 消息相关businessType ***************/
-    case bt_draft_downloadMaterialSuccess = "downloadMaterialSuccess" // 素材下载成功事件
-    case bt_draft_downloadMaterial = "downloadMaterial" // - 素材开始下载事件
-    case bt_draft_uploadMaterialSuccess = "uploadMaterialSuccess" // - 素材上传成功事件
-    case bt_draft_uploadMaterial = "uploadMaterial" // - 素材开始上传事件
-    case bt_videoCompose_muxAction = "muxAction" // 创作工具「合成成功」添加上报参数
-
-    /*************** 广告相关businessType ***************/
-    case bt_ad_request = "adRequest" // 客户端请求广告
-    case bt_ad_loaded = "adLoaded" // 客户端广告加载成功
-    case bt_ad_view = "adView" // 广告展示到屏幕
-    case bt_ad_click = "adClick" // 广告被点击
-    case bt_ad_loadedError = "adLoadedError" // 客户端广告加载失败-非需求
-    case bt_ad_close = "adClose" // 广告被关闭-非需求
-    case bt_ad_configRequest = "adConfigRequest" // 客户端请求广告配置
-    case bt_ad_configLoaded = "adConfigLoaded" // 客户端请求广告配置成功
-}
-
-// MARK: - autoType 自动动作的类型
-
-/// autoType 自动动作的类型
-public  enum  autoType: Int {
-    case AUTO_TYPE_SCROLL_VERTICAL_DOWN = 11 // 用户手动下划触发播放(播上一个视频)
-    case AUTO_TYPE_SCROLL_VERTICAL_UP = 12 // 用户手动上划触发播放(播下一个视频)
-    case AUTO_TYPE_SCROLL_HORIZON_RIGHT = 13 // 用户手动右划触发播放
-    case AUTO_TYPE_SCROLL_HORIZON_LEFT = 14 // 用户手动左划触发播放
-    case AUTO_TYPE_ENTER_DETAIL = 15 // 用户手动点击(进详情页)触发播放
-    case AUTO_TYPE_ENTER_APP = 21 // 打开APP自动播放的第一个
-    case AUTO_TYPE_NEXT_AFTER_COMPLETE = 22 // 用户播放完一个视频后自动触发播放相关推荐视频
-    case AUTO_TYPE_BACKEND_RESUME = 23 // 后台唤醒app,如果播放器挂了,重新播放、在别的页面播放过视频再回来之前的页面播放
-    case AUTO_TYPE_REFRESH_LIST = 24 // 首页下拉刷新,自动播的第一个
-    case AUTO_TYPE_CLICK_RECOMMEND = 25 // 点击推荐视频播放
-    case AUTO_TYPE_CLICK_DOUBLE = 26 // 双列点击视频进入单列播放
-}
-
-// MARK: - 消息动作:表示该条日志属于某条消息生命周期的哪个漏斗环节
-
-/// 消息动作:表示该条日志属于某条消息生命周期的哪个漏斗环节
-public  enum  actionType: String {
-    case at_msg_backendReturn = "backendReturn" // 后端将消息返回给客户端
-    case at_msg_frontendPull = "frontendPull" // 客户端获取到
-    case at_msg_view = "view" // 在客户端消息被滑动展示在屏幕上
-    case at_msg_click = "click" // 用户点击消息
-}
-
-// MARK: - 消息类型
-
-/// 消息类型
-public  enum  messageType: Int {
-    case mt_nomal = 0 // 未知消息
-    case mt_fans = 1 // 粉丝消息
-    case mt_like = 2 // 喜欢/赞
-    case mt_share = 3 // 分享消息
-    case mt_comment = 4 // 评论消息
-    case mt_notification = 5 // 通知消息
-    case mt_share_dynamics = 6 // 分享动态消息
-    /*** 自定义添加不涉及正式消息类型 ***/
-    case mt_badgeNumber = 1001 // 显示消息个数cell
-}
-
-/// 分享空间二级界面数据请求类型  1,观看 2,分享,3,喜欢 4, 评论
-public  enum  sharePageType: Int {
-    case share_page_play = 1 // 分享空间-播放列表
-    case share_page_share = 2 // 分享空间-分享列表
-    case share_page_favorite = 3 // 分享空间-收藏列表
-    case share_page_commnet = 4 // 分享空间-评论列表
-}
-
-// MARK: - 消息子类型
-
-/// 消息子类型
-public  enum  messageSubType: Int {
-    case mtsub_nomal = 0 // 未知消息
-    case mtsub_fansAtt = 101 // 粉丝-关注
-    case mtsub_fansSbs = 102 // 粉丝-订阅
-    case mtsub_likeColl = 201 // 喜欢-收藏视频
-    case mtsube_likePrai = 202 // 喜欢-评论点赞
-    case mtsub_shareWechat = 301 // 分享-微信会话
-    case mtsub_shareFriend = 302 // 分享-微信朋友圈
-    case mtsub_comment = 401 // 评论一级评论
-    case mtsub_commentSub = 402 // 评论二级评论
-    case mtsub_pushSucc = 501 // 通知-发布成功
-    case mtsub_pushNoPass = 502 // 通知-审核不通过
-    case mtsub_pushFixing = 503 // 通知-审核待修改
-    case mtsub_pushTransFail = 504 // 通知-转码失败
-    case mtsub_pushVideoRecom = 505 // 通知视频推荐
-    case mtsub_pushAccForbi = 506 // 通知-账号封禁
-    case mtsub_pushAccUnban = 507 // 通知-账号解封
-    case mtsub_pushIncStart = 508 // 通知-激励开始
-    case mtsub_pushIncEnd = 509 // 通知-激励结束
-    case mtsub_pushIncRupt = 510 // 通知-激励中断
-    case mtsub_shareSpace = 601 // 分享空间-分享
-    case mtsub_shareSpLike = 602 // 分享空间-喜欢
-    case mtsub_shareSpComm = 603 // 分享空间-评论
-    case mtsub_shareSpPlay = 604 // 分享空间-播放
-    case mtsub_shareSpMerge = 605 // 分享空间-外层合并消息(与业务逻辑无关,埋点上报使用)
-}
-
-// MARK: - 埋点上报消息类型(暂未统一)
-
-/// 埋点上报消息类型(暂未统一)
-public  enum  messagePointType: Int {
-    case mt_point_nomal = 0 // 未知消息
-    case mt_point_fans = 1 // 粉丝消息
-    case mt_point_praise = 2 // 赞
-    case mt_point_barrage = 3 // 弹幕消息
-    case mt_point_comment = 4 // 评论消息
-    case mt_point_share = 5 // 分享消息
-    case mt_point_collect = 6 // 收藏消息
-    case mt_point_notification = 7 // 通知消息
-    case mt_point_operative = 8 // 运营消息
-    case mt_point_dynamics = 1000 // 分享动态消息
-}
-
-// MARK: - 日志库类型
-
-/// 日志库类型
-public  enum  statisticsLogType: Int {
-    case st_log_type_abtestinfo = 10 // abtestinfo-Log ABTEST的 dlog Store
-    case st_log_type_operation = 20 // operation-Log 漏斗模型的相关上报
-    case st_log_type_simpleevent = 30 // simpleevent-Log 独立事件的相关上报
-    case st_log_type_frontend = 40 // frontend-Log 前端调试日志
-    case st_log_type_pLayaction = 50 // pLayaction-Log 播放行为日志上报
-    case st_log_type_useractive = 60 // useractive-Log 用户活跃日志上报
-    case st_log_type_videoPlayTracking = 70 // video-play-tracking 视频播放行为跟踪
-    case st_log_type_proauceSearch = 80 // proauce-search-log 素材搜索日志上报
-    case st_log_type_videoCompose = 90 // video-compose-log 创作工具素材搜索日志上报
-    case st_log_type_location = 100 // user-location-log 位置信息日志上报
-    case st_log_type_videoProduction = 110 // video-production-log 创作工具埋点日志上报
-    case st_log_type_adAction = 120 // ad-action-log 广告埋点日志上报
-}
-
-// MARK: - 冷启动方式
-
-/// coldLaunchType // 冷启动方式。若为热启动,则不用上报该字段
-public  enum  coldLaunchType: String {
-    case coldLaunchType_userActiveOpen = "userActiveOpen" // 用户主动打开
-    case coldLaunchType_appRecall = "appRecall" // 其它APP唤起,包括H5应用宝唤起
-    case coldLaunchType_pushRecall = "pushRecall" // 推送唤起
-}
-
-// MARK: - 上报日志类型
-
-/// 上报日志类型
-public  enum  reportLogType {
-    case reportLogType_view // 显示页面
-    case reportLogType_realPlay // 真实播放 视频播放到20s或播放到总时长30%,哪个先到为准
-    case reportLogType_play // 记录播放的视频
-    case reportLogType_Action // 上报视频动作记录
-    case reportLogType_Frontend // 通用上报
-}
-
-// MARK: - 底部tab
-
-/// 底部tab
-public  enum  TAB_PAGETYPE: String {
-    case TAB_PAGETYPE_NORMAL = "nomalTab" // 默认
-    case TAB_PAGETYPE_RECOMM = "categoryTab" // 推荐
-    case TAB_PAGETYPE_ATTEN = "followTab" // 关注
-    case TAB_PAGETYPE_PUBLISH = "publishTab" // 发布
-    case TAB_PAGETYPE_MESSAGE = "messageTab" // 消息
-    case TAB_PAGETYPE_MINE = "mineTab" // 我的
-}
-
-// MARK: - 刷新控件类型
-
-/// 刷新控件类型
-public  enum  REFRESH_TYPE {
-    case REFRESH_TYPE_ALL // 推荐
-    case REFRESH_TYPE_HEADER // 头部
-    case REFRESH_TYPE_FOOTER // 尾部
-}
-
-// MARK: - 刷新控件类型
-
-/// 刷新控件类型
-public  enum  moveDirection {
-    case moveDirectionNormal
-    case moveDirectionUp
-    case moveDirectionDown
-    case moveDirectionRight
-    case moveDirectionLeft
-}
-
-// MARK: - 关注跟粉丝cell类型
-
-/// 关注跟粉丝cell类型
-public  enum  atttendAndFansCellType {
-    case cellType_attend // 关注
-    case cellType_fans // 粉丝
-    case cellType_banned // 黑名单
-}
-
-// MARK: - 视频全屏播放操作类型
-
-/// 视频全屏播放操作类型
-public  enum  fullScreenActionType {
-    case volume // 声音
-    case brightness // 亮度
-    case progress // 进度
-}
-
-// MARK: - 活动提示页类型
-
-/// 活动提示页类型
-public  enum  activityRemindType {
-    case nomal //
-    case newUser // 新用户专享
-    case yesterDay_finish // 昨日已完成
-    case yesterDay_unfinish // 昨日未完成
-    case today_finish // 今日任务已完成
-}
-
-// MARK: - 制作工具素材搜索msgType
-
-/// 制作工具素材搜索msgType
-public  enum  material_msgType: String {
-    case all = "ALL_SEARCH_EVENT" // 搜索所有
-    case image = "IMAGE_SEARCH_EVENT" // 图片搜索
-    case video = "VIDEO_SEARCH_EVENT" // 视频搜索
-    case gif = "GIF_SEARCH_EVENT" // 动图搜索
-    case recommend_image = "IMAGE_RECOMMEND_EVENT" // 图片推荐搜索
-    case recommend_video = "VIDEO_RECOMMEND_EVENT" // 视频推荐搜索
-    case recommend_gif = "GIF_RECOMMEND_EVENT" // 动图推荐搜索
-}
-
-// 画布类型
-public  enum  videoCanvasType: Int {
-    case origin = 1 // 原始
-    case nineToSixteen = 2 // 9:16
-    case oneToOne = 3 // 1:1
-    case sixteenToNine = 4 // 16:9
-}
-
-/// 贴纸类型
-public  enum  StickerType: String {
-    case UNKONW = "unknow"
-    case IMAGE = "image" // 图片
-    case VIDEO = "video" // 视频
-    case GIF = "gif" // gif动图
-    case VOICE = "voice" // 声音
-    case FILE = "file" // 文件
-    case SUBTITLE = "subtitle" // 字幕
-    /// 获取index
-    /// - Returns: description
-    public func index() -> Int {
-        var fileType: Int = 0
-        switch self {
-        case .IMAGE:
-            fileType = 1
-        case .VIDEO:
-            fileType = 2
-        case .VOICE:
-            fileType = 3
-        case .FILE:
-            fileType = 4
-        case .GIF:
-            fileType = 5
-        case .SUBTITLE:
-            fileType = 6
-        default:
-            fileType = 0
-        }
-        return fileType
-    }
-
-    /// 媒体类型
-    /// - Returns: <#description#>
-   public func mimeType() -> String {
-        var mimeType: String = "application/octet-stream"
-        switch self {
-        case .IMAGE:
-            mimeType = "image/jpeg"
-        case .VIDEO:
-            mimeType = "video/mpeg"
-        case .VOICE:
-            mimeType = "audio/mpeg"
-        case .FILE:
-            mimeType = "application/octet-stream"
-        case .GIF:
-            mimeType = "image/gif"
-        default:
-            mimeType = "application/octet-stream"
-        }
-        return mimeType
-    }
-
-   public func pathExtension() -> String {
-        var pathExtension: String = ""
-        switch self {
-        case .IMAGE:
-            pathExtension = "png"
-        case .VIDEO:
-            pathExtension = "mp4"
-        case .VOICE:
-            pathExtension = "mp3"
-        case .FILE:
-            pathExtension = ""
-        case .GIF:
-            pathExtension = "gif"
-        default:
-            break
-        }
-        return pathExtension
-    }
-}
-
-// MARK: - 贴纸裁剪方式
-
-/// 贴纸裁剪方式
-public  enum  stickerContentModeDef: Int {
-    case aspectFit = 0 // 自适应
-    case aspectFill = 1 // 铺满
-}
-
-/// 贴纸裁剪方式 add by ak v2
-public  enum  stickerContentMode: String {
-    case aspectFitStr = "complete" // 完整显示(有黑边)
-    case aspectFillStr = "full" // 铺满
-}
-
-// MARK: - 适配模式
-
-/// 适配模式
-public  enum  adapterModeDef: Int {
-    case speedyAuto = 0 // 快速自适应
-    case loopAuto = 1 // 自动循环
-    case crop = 2 // 定帧/裁剪
-}
-
-/// 适配模式 add by ak  v2
-public  enum  adapterMode: String {
-    case multiple // 快速自适应
-    case loopAuto = "loop" // 自动循环
-    case staticFrame // 定帧/裁剪
-}
-
-// MARK: - 上传视频类型
-
-/// 上传视频类型
-public  enum  videoUploadSourceType: String {
-    case videoUpload // 上传
-    case videoCompose // 合成制作
-    case videoUploadToCompose // 上传转合成制作
-}
-
-// MARK: - 进入创作工具入口
-
-/// 素材上传、保存、收藏相关
-public  enum  videoMakeEntranceType: String {
-    case entranceMineTabDraft = "draft_metab" // 我的Tab -> 草稿箱列表 -> 创作工具
-    case entrancePublicTabDraft = "draft_uploadpopup" // 发布Tab -> 草稿箱列表 -> 创作工具
-    case entrancePublicTabCompose = "composeVideo" // 发布Tab -> 视频合成 -> 创作工具
-    case entrancePublicTabImageText = "imageTextGenerate" // 发布Tab -> 图文生成视频 -> 创作工具
-    case entrancePublicTabAlbum = "electronicAlbum" // 发布Tab -> 电子相册 -> 创作工具
-    case entranceReproduction = "reproduction" // 视频详情 -> 做同款 -> 创作工具
-    case entrancePublicTabUpload = "upload" // 发布Tab -> 上传视频 -> 直接发布
-    // add by ak
-    case entranceUpload2compose = "upload2compose" // 发布Tab -> 上传视频 -> 加工视频 -> 创作工具
-    case entranceStuckPointPublic = "syncedUpVideo" // 卡点视频发布
-
-    // * 新添加-自定义
-    case entrancePublicTabAddMusic = "addMusic" // 发布Tab -> 上传视频 -> 加音乐 -> 创作工具
-    case entrancePublicTabAddSubtitle = "addSubtitle" // 发布Tab -> 上传视频 -> 加字幕 -> 创作工具
-    case entrancePublicTabAddVoice = "addVoice" // 发布Tab -> 上传视频 -> 加语音 -> 创作工具
-    case entrancePublicTabAddSection = "addSection" // 发布Tab -> 上传视频 -> 多段拼接 -> 创作工具
-}
-
-// MARK: - 段落类型
-
-/// 段落类型
-public  enum  sectionType: String {
-    case normal // 普通段
-    case global // 全局段
-}
-
-// MARK: - 音乐类型
-
-/// 音乐类型
-public  enum  VOICETYPT: String {
-    case PRODUCE = "produce" // 合成语音
-    case BGM = "bgm" // 背景音乐
-    case SPEECH = "speech" // 录音
-    case LOCAL = "local" // 导入文件
-}
-
-// MARK: - 输入框状态B
-
-/// 输入框状态
-public  enum  inputStatus {
-    case normal // 写故事,可智能配音,自动生成字幕
-    case inputing // 输入中
-    case recording // 语音识别成文字中…
-    case recordEmpty // 录音未识别到文字,点此输入
-    case recordError // 获取录音文字失败,请重试
-    case recordSuccess // 获取录音文字成功
-}
-
-// MARK: - 画面比例
-
-/// 画面比例
-public  enum  aspectRatio {
-    case origin(width: CGFloat, height: CGFloat) // 原始
-    case oneToOne // 1:1
-    case sixteenToNine // 16:9
-    case nineToSixteen // 9:16
-}
-
-// MARK: - 卡点视频音乐页面类型
-
-/// 卡点视频音乐页面类型
-public  enum  stuckPointMusicContentType {
-    case catagery
-    case serach
-    case page
-}
-
-// 视频发布来源场景 1:普通上传 2:创作工具,3:普通上传转创作工具,4:后台转换加工,5:卡点视频制作
-public  enum  videoFromScene: Int {
-    case UploadNormal = 1 // 普通上传
-    case UploadMakeVideo = 2 // 创作工具
-    case UploadNormalToMakeVideo = 3 // 普通上传转创作工具
-    case server = 4 // 后台转换加工
-    case stuckPoint = 5 // 卡点视频制作
-}
-
-// MARK: - 广告来源渠道
-
-/// 广告来源渠道
-public  enum  adChannel: String {
-    case wechat // 微信广告
-    case byteDouce = "pangle" // 穿山甲广告(字节跳动)
-    case pdd // 多多进宝广告(拼多多)
-    case gdt = "qq" // 腾讯优量汇
-}
-
-// MARK: - 广告类型
-
-/// 广告类型
-public  enum  adType: Int {
-    case banner = 1 // Banner 广告(即:固定位展示广告)
-    case drawVideo = 2 // 信息流视频广告
-    case preMovie = 3 // 贴片广告(场景举例:暂停贴片广告)
-    case tableScreen = 4 // 插屏广告(场景举例:退出全屏,弹出的插屏广告)
-    case splash = 5 // 开屏广告
-}
-
-// MARK: - 广告投放人群
-
-/// 广告投放人群
-public  enum  adCrowd: Int {
-    case highCrowd = 1 // 高分享人群
-    case mediumCrowd = 2 // 中分享人群
-    case lowCrowd = 3 // 低分享人群
-}
-
-// MARK: - 广告内部位置值
-
-/// 广告内部位置值
-public  enum  adPosition: String {
-    case splashAd // 票圈视频 App 闪屏页广告位
-    case videoFlowAd // 票圈视频 App 视频流广告位
-}
-
-
-// MARK: - 风格
-
-/// 风格
-public  enum  styleColor: String {
-    case nomal = "#F1034D"
-    case green = "#3DC1C1"
-    case red = "#EE0051"
-}
-
-// MARK: - statusBar
-
-/// statusBar
-public enum  statusBarStyle {
-    case light
-    case dark
-}

+ 0 - 85
BFFramework/Classes/Utils/PQBFConfig.swift

@@ -1,85 +0,0 @@
-//
-//  PQBFConfig.swift
-//  BFFramework
-//
-//  Created by SanW on 2021/6/4.
-//  111
-
-import UIKit
-
-public class PQBFConfig: NSObject {
-    public static let shared = PQBFConfig()
-    /**
-     // 主题适配方案一
-     styleColor = nomal
-     statusBarStyle = .light
-     backgroundColor = UIColor.hexColor(hexadecimal: "#191919")
-     styleTitleColor: UIColor = UIColor.white
-     cutViewStyleColor: UIColor = UIColor.white
-     cutViewTintColor: UIColor = UIColor.black
-     materialDeleteImage = UIImage.init().BF_Image(named:"icon_search_delete")
-     cutDurationColor = UIColor.init(red: 238.0 / 255.0, green: 0 / 255.0, blue: 81.0 / 255.0, alpha: 0.1)
-     hiddenMusicMask = false
-     otherTintColor = UIColor.hexColor(hexadecimal: "#333333")
-     //主题适配方案二
-     styleColor = green
-     statusBarStyle = .dark
-     backgroundColor = UIColor.white
-     styleTitleColor: UIColor = UIColor.black
-     cutViewStyleColor: UIColor = UIColor.hexColor(hexadecimal: "#3DC1C1")
-     cutViewTintColor: UIColor = UIColor.white
-     materialDeleteImage = UIImage.init().BF_Image(named:"deleteAudio")
-     cutDurationColor = UIColor.init(red: 61.0 / 255.0, green: 193.0 / 255.0, blue: 193.0 / 255.0, alpha: 0.1)
-     hiddenMusicMask = true
-     otherTintColor = UIColor.hexColor(hexadecimal: "#F2F2F2")
-     */
-    // 主题色
-    public var styleColor: styleColor = .green
-    // statusBarStyle
-    public var statusBarStyle: statusBarStyle = .dark
-    // 背景色
-    public var styleBackGroundColor: UIColor = UIColor.white
-    // 主题标题色
-    public var styleTitleColor: UIColor = UIColor.black
-    // 裁剪主题色
-    public var cutViewStyleColor: UIColor = UIColor.hexColor(hexadecimal: "#3DC1C1")
-    // 素材删除图
-    public var materialDeleteImage: UIImage? = UIImage().BF_Image(named: "deleteAudio")
-    // 裁剪主题色61, 193, 193
-    public var cutDurationColor: UIColor = UIColor(red: 61.0 / 255.0, green: 193.0 / 255.0, blue: 193.0 / 255.0, alpha: 0.1)
-    // 裁剪主题色
-    public var cutViewTintColor: UIColor = UIColor.white
-    // 裁剪主题色
-    public var hiddenMusicMask: Bool = true
-    public var otherTintColor: UIColor = UIColor.hexColor(hexadecimal: "#F2F2F2")
-
-    // 微信登陆信息
-    public var appInfo: WXApiInfo?
-    // 渠道
-    public let channelID: String = "AppStore"
-    // 友盟账号 快乐星球:60b9fa644d0228352bbc8937 闪音:60b9f95b4d0228352bbc87e0
-    public var umAppkey: String = "60b9f95b4d0228352bbc87e0"
-    // bugly账号
-    // 闪音卡点:b8756b43fc
-    public var buglyAppkey: String = "b8756b43fc"
-    
-    //add by ak 公用参数使用
-    public var appType:String = "15"
-    //苹果后台创建的 APPID
-    public var appId:String = "1570572849"
-    
-    //是否可打印 LOG
-    public var enableBFLog:Bool = false
-
-    override private init() {
-        super.init()
-    }
-
-    override public func copy() -> Any {
-        return self
-    }
-
-    override public func mutableCopy() -> Any {
-        return self
-    }
-}

+ 0 - 804
BFFramework/Classes/Utils/PQCommonMethodUtil.swift

@@ -1,804 +0,0 @@
-//
-//  PQCommonMethodUtil.swift
-//  PQSpeed
-//
-//  Created by lieyunye on 2020/5/29.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import AdSupport
-import Alamofire
-import Foundation
-import KeychainAccess
-import Kingfisher
-import KingfisherWebP
-import Photos
-import RealmSwift
-import Toast_Swift
-/// Home文件地址
-public let homeDirectory = NSHomeDirectory()
-/// docdocumens文件地址
-public let documensDirectory = homeDirectory + "/Documents"
-/// library文件地址
-public let libraryDirectory = homeDirectory + "/Library"
-
-/// 本地存储资源地址
-public let resourceDirectory = documensDirectory + "/Resource"
-/// 播放视频缓冲本地沙河目录
-public let videoCacheDirectory = resourceDirectory + "/VideoCache"
-/// 相册视频导出到本地沙河目录
-public let photoLibraryDirectory = resourceDirectory + "/PhotoLibrary/"
-/// 背景音乐导出到本地沙河目录
-public let bgMusicDirectory = resourceDirectory + "/BGMusic/"
-/// 网络视频素材下载到本地沙河目录
-public let downloadDirectory = resourceDirectory + "/Download/"
-/// 网络图片、GIF 素材下载到本地沙河目录
-public let downloadImagesDirectory = resourceDirectory + "/DownloadImages/"
-/// 临时缓存本地沙河目录地址
-public let tempDirectory = resourceDirectory + "/Temp/"
-/// 导出声音的本地沙盒目录v
-public let exportAudiosDirectory = resourceDirectory + "/ExportAudios/"
-/// 导出合成视频的本地沙盒目录
-public let exportVideosDirectory = resourceDirectory + "/ExportVideos/"
-// 版本构建号
-public let versionCode = "\(Bundle.main.infoDictionary?["CFBundleVersion"] ?? "1")"
-// 版本号
-public let versionName = "\(Bundle.main.infoDictionary?["CFBundleShortVersionString"] ?? "1.0.0")"
-/// 创建目录文件
-/// - Returns: <#description#>
-public func createDirectory(path: String) {
-    let fileManager = FileManager.default
-    if !fileManager.fileExists(atPath: path) {
-        try? fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
-    }
-}
-
-/// 判断文件夹是否存在
-/// - Parameter dicPath:文件夹 目录
-public func directoryIsExists(dicPath: String) -> Bool {
-    BFLog(message: " dir path is: \(dicPath)")
-    var directoryExists = ObjCBool(false)
-    let fileExists = FileManager.default.fileExists(atPath: dicPath, isDirectory: &directoryExists)
-    return fileExists && directoryExists.boolValue
-}
-
-/// 判断文件是否存在
-/// - Parameter filepath: 文件目录
-public func fileIsExists(filePath: String) -> Bool {
-    BFLog(message: "file path is: \(filePath)")
-
-    let fileExists = FileManager.default.fileExists(atPath: filePath)
-    return fileExists
-}
-
-/// 创建沙河文件地址
-/// - Parameter url: 原地址
-/// - Returns: <#description#>
-public func createFilePath(url: String) -> Bool {
-    let fileManager = FileManager.default
-    if !fileManager.fileExists(atPath: url) {
-        let isFinished = fileManager.createFile(atPath: url, contents: nil, attributes: nil)
-        return isFinished
-    }
-    return true
-}
-
-public func cIPHONE_X() -> Bool {
-    guard #available(iOS 11.0, *) else {
-        return false
-    }
-    let isX = (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0) > 0
-    return isX
-}
-
-/// 给按钮/imageView加载网络图片
-///
-/// - Parameters:
-///   - url: 网络url
-///   - mainView: 需要加载的视图
-public func netImage(url: String, mainView: Any, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
-    if mainView is UIImageView {
-        (mainView as! UIImageView).kf.setImage(with: URL(string: url), placeholder: placeholder, options: url.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
-
-        }) { _ in
-        }
-    } else if mainView is UIButton {
-        (mainView as! UIButton).kf.setImage(with: URL(string: url), for: .normal, placeholder: placeholder, options: url.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
-
-        }) { _ in
-        }
-    }
-}
-
-/** 获取Kingfisher缓存的图片的data */
-public func kf_imageCacheData(originUrl: String) -> Data? {
-    let diskCachePath = ImageCache.default.cachePath(forKey: originUrl)
-    let data = try? Data(contentsOf: URL(fileURLWithPath: diskCachePath))
-    return data
-}
-
-/** 获取Kingfisher缓存的图片 */
-public func kf_imageCacheImage(originUrl: String, completeHandle: @escaping (_ image: UIImage?, _ error: Error?) -> Void) {
-   
-    ImageCache.default.retrieveImageInDiskCache(forKey: originUrl, options: [.cacheOriginalImage]) { result in
-        DispatchQueue.main.async {
-            switch result {
-            case let .success(image):
-                completeHandle(image, nil)
-            case let .failure(error):
-                completeHandle(nil, error)
-            }
-        }
-    }
-}
-
-/** 打印 */
-public func BFLog<T>(message: T) {
- 
-    if(PQBFConfig.shared.enableBFLog){
-        let logger = NXLogger.shared
-
-        logger.level = .info
-        logger.ouput = .debuggerConsole
-
-        logger.d(message as? String ?? "")
-    }else{
-        BuglyLog.level(.warn, logs: message as? String)
-    }
- 
-}
-
-// MARK: 获取公共参数
-
-public func commonParams() -> [String: Any] {
-    let model = UIDevice.current.model
-    let systemName = UIDevice.current.systemName
-    let systemVersion = UIDevice.current.systemVersion
-    let localizedModel = UIDevice.current.localizedModel
-    let machineInfo: [String: Any] = [
-        "model": model, "system": systemName + " " + systemVersion, "brand": localizedModel, "platform": "iOS", "networkType": networkStatus(), "clientIp": ipAddress(),
-    ]
-    var commParams: [String: Any] = [
-        "appVersionCode": versionCode,
-        "versionCode": versionCode,
-        "system": systemName + " " + systemVersion,
-        "systemVersion": systemName + " " + systemVersion,
-        "appType": PQBFConfig.shared.appType,
-        "appId":   PQBFConfig.shared.appId,
-        "machineCode": getMachineCode(),
-        "networkType": networkStatus(),
-        "ipAddress": ipAddress(),
-        "clientTimestamp": Int64(Date().timeIntervalSince1970 * 1000),
-        "platform": "iOS",
-        "versionName": versionName,
-        "sessionId": PQSingletoMemoryUtil.shared.sessionId,
-        "subSessionId": PQSingletoMemoryUtil.shared.subSessionid ?? PQSingletoMemoryUtil.shared.sessionId,
-        "mid": getMachineCode(),
-        "machineInfo": dictionaryToJsonString(machineInfo) ?? "",
-        "abInfoData": dictionaryToJsonString(PQSingletoMemoryUtil.shared.abInfoData) ?? "",
-        "requestId": getUniqueId(desc: "requestId"),
-        "idfa": ASIdentifierManager.shared().advertisingIdentifier.uuidString,
-        "idfv": UIDevice.current.identifierForVendor?.uuidString ?? "",
-        "deviceToken": PQSingletoMemoryUtil.shared.deviceToken,
-    ]
-    if BFLoginUserInfo.shared.accessToken.count > 0 {
-        commParams["token"] = BFLoginUserInfo.shared.accessToken
-    }
-    if BFLoginUserInfo.shared.uid.count > 0 {
-        commParams["loginUid"] = BFLoginUserInfo.shared.uid
-        commParams["uid"] = BFLoginUserInfo.shared.uid
-    }
-//    showAlertVc(title: "公参", message: dictionaryToJsonString(commParams))
-    return commParams
-}
-
-/// 获取网络状态
-/// - Returns: <#description#>
-public func networkStatus() -> String {
-    let status = NetworkReachabilityManager(host: "www.baidu.com")?.networkReachabilityStatus
-    var statusStr: String!
-
-    switch status {
-    case .unknown:
-        statusStr = "NETWORK_UNKNOWN"
-    case .notReachable:
-        statusStr = "NETWORK_NO"
-    case .reachable(.wwan):
-        statusStr = "4G"
-    case .reachable(.ethernetOrWiFi):
-        statusStr = "Wi-Fi"
-    default:
-        statusStr = "NETWORK_UNKNOWN"
-    }
-    return statusStr
-}
-
-/// 判断是否有网
-/// - Returns: <#description#>
-public func isNetConnected() -> Bool {
-    return NetworkReachabilityManager(host: "www.baidu.com")?.networkReachabilityStatus != .notReachable
-}
-
-/// 获取ip地址
-/// - Returns: <#description#>
-public func ipAddress() -> String {
-    var addresses = [String]()
-    var ifaddr: UnsafeMutablePointer<ifaddrs>?
-    if getifaddrs(&ifaddr) == 0 {
-        var ptr = ifaddr
-        while ptr != nil {
-            let flags = Int32(ptr!.pointee.ifa_flags)
-            var addr = ptr!.pointee.ifa_addr.pointee
-            if (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING) {
-                if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
-                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
-                    if getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
-                        if let address = String(validatingUTF8: hostname) {
-                            addresses.append(address)
-                        }
-                    }
-                }
-            }
-            ptr = ptr!.pointee.ifa_next
-        }
-        freeifaddrs(ifaddr)
-    }
-    return addresses.first ?? "0.0.0.0"
-}
-
-/// 生成唯一ID / 分享跟冷启动
-/// - Parameter desc: <#desc description#>
-/// - Returns: <#description#>
-public func getUniqueId(desc: String) -> String {
-    let timeStr: String = "\(Date().timeIntervalSince1970)"
-    let uuid: String = getMachineCode()
-    let code: String = "\(arc4random_uniform(1_000_000_000))"
-    let uniqueId = (timeStr + desc + uuid + code).md5.md5
-    BFLog(message: "生成唯一码:desc = \(desc),timeStr = \(timeStr),uuid = \(uuid),code = \(code),uniqueId = \(uniqueId)")
-    return uniqueId
-}
-
-// MARK: 字典转字符串
-
-public func dictionaryToJsonString(_ dic: [String: Any]) -> String? {
-    BFLog(message: "dictionaryToJsonString = \(dic)")
-    if !JSONSerialization.isValidJSONObject(dic) {
-        return ""
-    }
-    guard let data = try? JSONSerialization.data(withJSONObject: dic, options: []) else {
-        return ""
-    }
-    BFLog(message: "dictionaryToJsonString - data = \(data)")
-    let str = String(data: data, encoding: String.Encoding.utf8)
-    BFLog(message: "dictionaryToJsonString - str = \(String(describing: str))")
-    return str
-}
-
-// MARK: 字符串转字典
-
-public func jsonStringToDictionary(_ str: String) -> [String: Any]? {
-    let data = str.data(using: String.Encoding.utf8)
-    if data == nil {
-        return [:]
-    }
-    if let dict = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
-        return dict
-    }
-    return [:]
-}
-
-// MARK: 字符串转数组
-
-public func jsonStringToArray(_ str: String) -> [[String: String]]? {
-    let data = str.data(using: String.Encoding.utf8)
-    if let array = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [[String: String]] {
-        return array
-    }
-    return nil
-}
-
-/// 数组转为string
-/// - Parameter array: <#array description#>
-/// - Returns: <#description#>
-public func arrayToJsonString(_ array: [Any]) -> String {
-    if !JSONSerialization.isValidJSONObject(array) {
-        BFLog(message: "无法解析String")
-        return ""
-    }
-    let data: NSData! = try? JSONSerialization.data(withJSONObject: array, options: []) as NSData?
-    let JSONString = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue)
-    return JSONString! as String
-}
-
-/// jsonString转为数组
-/// - Parameter jsonString: <#jsonString description#>
-/// - Returns: <#description#>
-public func jsonStringToArray(jsonString: String) -> [Any]? {
-    let data = jsonString.data(using: String.Encoding.utf8)
-    if data == nil {
-        return nil
-    }
-    if let array = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [Any] {
-        return array
-    }
-    return nil
-}
-
-/// 计算字符串大小
-/// - Parameters:
-///   - text: <#text description#>
-///   - font: <#font description#>
-///   - size: <#size description#>
-/// - Returns: <#description#>
-public func sizeWithText(text: String, font: UIFont, size: CGSize) -> CGSize {
-    let attributes = [NSAttributedString.Key.font: font]
-    let option = NSStringDrawingOptions.usesLineFragmentOrigin
-    let rect: CGRect = text.boundingRect(with: size, options: option, attributes: attributes, context: nil)
-    return rect.size
-}
-
-/// 根据行数计算字符串大小
-/// - Parameters:
-///   - text: <#text description#>
-///   - numberOfLines: <#numberOfLines description#>
-///   - font: <#font description#>
-///   - maxSize: <#maxSize description#>
-/// - Returns: <#description#>
-public func sizeTextFits(attributedText: NSMutableAttributedString?, text: String?, numberOfLines: Int, font: UIFont, maxSize: CGSize) -> CGSize {
-    var newSize: CGSize = CGSize(width: 0, height: 0)
-    let label = UILabel(frame: CGRect.zero)
-    label.font = font
-    label.numberOfLines = numberOfLines
-    if attributedText != nil {
-        label.attributedText = attributedText
-    } else {
-        label.text = text
-    }
-    newSize = label.sizeThatFits(maxSize)
-
-    return newSize
-}
-
-public func textNumberOfLines(text: String, font: UIFont, maxSize _: CGSize) -> Int {
-    let label = UILabel(frame: CGRect.zero)
-    label.font = font
-    label.numberOfLines = 0
-    label.text = text
-    return label.numberOfLines
-}
- 
-/// 生成渐变色
-/// - Parameters:
-///   - size: <#size description#>
-///   - endPoint: <#endPoint description#>
-///   - startColor: <#startColor description#>
-///   - endColor: <#endColor description#>
-/// - Returns: <#description#>
-public func gradientColor(size: CGSize, endPoint: CGPoint, startColor: UIColor, endColor: UIColor) -> UIColor {
-    let gradientLayer = CAGradientLayer()
-    gradientLayer.frame = CGRect(origin: CGPoint(), size: size)
-    gradientLayer.startPoint = CGPoint.zero
-    gradientLayer.endPoint = endPoint
-    gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
-    UIGraphicsBeginImageContext(size)
-    gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
-    let image = UIGraphicsGetImageFromCurrentImageContext()!
-    return UIColor(patternImage: image)
-}
-
-/// 获取设备ID
-/// - Returns: <#description#>
-public func getMachineCode() -> String {
-    let userInfo: [String: Any]? = jsonStringToDictionary(UserDefaults.standard.string(forKey: cUserInfoStorageKey) ?? "")
-    if userInfo != nil && ((userInfo?.keys.contains("isVirtualUser") ?? false) && !(userInfo?["isVirtualUser"] is NSNull) && ((userInfo?["isVirtualUser"] as? Bool) ?? false)) && ((userInfo?.keys.contains("mid") ?? false) && !(userInfo?["mid"] is NSNull)) {
-        BFLog(message: "虚拟账号mid:\("\(userInfo?["mid"] ?? "")")")
-        return "\(userInfo?["mid"] ?? "")"
-    }
-    let keychain = Keychain(service: "com.piaoquan.pqspeed")
-    var uuid: String = keychain["machineCode"] ?? ""
-    if uuid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
-        uuid = NSUUID().uuidString
-        keychain["machineCode"] = uuid
-    }
-    BFLog(message: "正式账号mid:\(uuid)")
-    return uuid
-}
-
-/// 显示加载中视图
-/// - Parameters:
-///   - superView: <#superView description#>
-///   - msg: <#msg description#>
-/// - Returns: <#description#>
- public func cShowHUB(superView: UIView?, msg: String?) {
-    DispatchQueue.main.async {
-        if superView == nil {
-            if msg == nil {
-                UIApplication.shared.keyWindow?.makeToastActivity(.center)
-            } else {
-                UIApplication.shared.keyWindow?.makeToast(msg, duration: 3.0, position: .center)
-            }
-        } else {
-            if msg == nil {
-                superView!.makeToastActivity(.center)
-            } else {
-                superView!.makeToast(msg, duration: 3.0, position: .center)
-            }
-        }
-    }
-}
-
-/// 隐藏加载中视图
-/// - Parameter superView: <#superView description#>
-/// - Returns: <#description#>
-public func cHiddenHUB(superView: UIView?) {
-    DispatchQueue.main.async {
-        if superView == nil {
-            UIApplication.shared.keyWindow?.hideAllToasts()
-            UIApplication.shared.keyWindow?.hideToastActivity()
-        } else {
-            superView!.hideAllToasts()
-            superView?.hideToastActivity()
-        }
-    }
-}
-
-/// 获取存储值
-/// - Parameter key: key description
-/// - Returns: description
-public func getUserDefaults(key: String) -> Any? {
-    return UserDefaults.standard.object(forKey: key)
-}
-
-/// 存储数据
-/// - Parameters:
-///   - key: key description
-///   - value: value description
-/// - Returns: description
-public func saveUserDefaults(key: String, value: String) {
-    UserDefaults.standard.set(value, forKey: key)
-    UserDefaults.standard.synchronize()
-}
-
-/// 存储数据带版本号
-/// - Parameters:
-///   - key: <#key description#>
-///   - value: <#value description#>
-public func saveUserDefaultsToJson(key: String, value: Any) {
-    UserDefaults.standard.set(dictionaryToJsonString([key: value, "appVersionCode": versionCode, "versionName": versionName]), forKey: key)
-    UserDefaults.standard.synchronize()
-}
-
-/// 获取数据带版本号
-/// - Parameter key: <#key description#>
-/// - Returns: <#description#>
-public func getUserDefaultsForJson(key: String) -> Any? {
-    let jsonStr = UserDefaults.standard.object(forKey: key)
-    if jsonStr != nil {
-        return jsonStringToDictionary(jsonStr as! String)?[key]
-    }
-    return UserDefaults.standard.object(forKey: key)
-}
-
-/// 清空数据
-/// - Parameters:
-///   - key: key description
-///   - value: value description
-/// - Returns: description
-public func removeUserDefaults(key: String) {
-    UserDefaults.standard.removeObject(forKey: key)
-    UserDefaults.standard.synchronize()
-}
-
-/// 存储数据
-/// - Parameters:
-///   - key: key description
-///   - value: value description
-/// - Returns: description
-public func saveUserDefaults(key: String, value: Any) {
-    UserDefaults.standard.set(value, forKey: key)
-    UserDefaults.standard.synchronize()
-}
-
-/// 保存自定义model   as NSArray  当 OBJ 是数组时不能使用 Array 要使用 NSArray
-/// - Parameter object: <#object description#>
-/// - Parameter key: <#key description#>
-public func saveCustomObject(customObject object: NSCoding, key: String) {
-    let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object)
-    UserDefaults.standard.set(encodedObject, forKey: key)
-    UserDefaults.standard.synchronize()
-    BFLog(message: "保存自定义类成功 key is \(key) \(encodedObject.count)")
-}
-
-/// 取自定义model
-/// - Parameter key: <#key description#>
-public func getCustomObject(forKey key: String) -> AnyObject? {
-    let decodedObject = UserDefaults.standard.object(forKey: key) as? Data
-
-    if decodedObject == nil {
-        BFLog(message: "key is \(key)  decodedObject is nil")
-    }
-    if let decoded = decodedObject {
-        let object = NSKeyedUnarchiver.unarchiveObject(with: decoded as Data)
-
-        return object as AnyObject?
-    }
-
-    return nil
-}
-
-/// 添加通知
-/// - Parameters:
-///   - observer: <#observer description#>
-///   - aSelectorName: <#aSelectorName description#>
-///   - aName: <#aName description#>
-///   - anObject: <#anObject description#>
-/// - Returns: <#description#>
-public func addNotification(_ observer: Any, selector aSelectorName: Selector, name aName: String, object anObject: Any?) {
-    PQNotification.addObserver(observer, selector: aSelectorName, name: NSNotification.Name(rawValue: aName), object: anObject)
-}
-
-/// 发送通知
-/// - Parameter aName: <#aName description#>
-/// - Returns: <#description#>
-public func postNotification(name aName: String, userInfo: [AnyHashable: Any]? = nil) {
-    PQNotification.post(name: NSNotification.Name(aName), object: nil, userInfo: userInfo)
-}
-
-/// 获取是否打开推送
-/// - Parameter completeHander: <#completeHander description#>
-/// - Returns: <#description#>
-public func pushNotificationIsOpen(completeHander: ((_ isOpen: Bool) -> Void)?) {
-    if #available(iOS 10.0, *) {
-        UNUserNotificationCenter.current().getNotificationSettings { setttings in
-            completeHander!(setttings.authorizationStatus == .authorized)
-        }
-    } else {
-        completeHander!(UIApplication.shared.currentUserNotificationSettings?.types.contains(UIUserNotificationType.alert) ?? false)
-    }
-}
-
-/// 发送上传本地推送
-/// - Parameter isSuccess: 是否上传成功
-/// - Returns: <#description#>
-public func sendUploadNotification(isSuccess: Bool) {
-    let title: String = isSuccess ? "上传完成了!" : "上传失败了!"
-    let body: String = isSuccess ? "请点击发布,完成上传。否则,您的视频可能丢失" : "快来看看怎么了?"
-    sendLocalNotification(title: title, body: body)
-}
-
-/// 发送本地推送
-/// - Parameters:
-///   - title: 标题
-///   - body: 内容
-/// - Returns: <#description#>
-public func sendLocalNotification(title: String, body: String) {
-    // 设置推送内容
-    if #available(iOS 10.0, *) {
-        let content = UNMutableNotificationContent()
-        content.title = title
-        content.body = body
-        content.badge = 1
-        // 设置通知触发器
-        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
-        // 设置请求标识符
-        let requestIdentifier = getUniqueId(desc: "notification\(title)")
-        // 设置一个通知请求
-        let request = UNNotificationRequest(identifier: requestIdentifier,
-
-                                            content: content, trigger: trigger)
-        // 将通知请求添加到发送中心
-        UNUserNotificationCenter.current().add(request) { error in
-            if error == nil {
-                print("Time Interval Notification scheduled: \(requestIdentifier)")
-            }
-        }
-    } else {
-        // Fallback on earlier versions
-        let notification = UILocalNotification()
-        notification.alertBody = body
-        notification.alertTitle = title
-        notification.applicationIconBadgeNumber = 1
-        notification.fireDate = Date(timeIntervalSinceNow: 0)
-        UIApplication.shared.scheduledLocalNotifications = [notification]
-    }
-}
-
-/// 打开应用设置
-public func openAppSetting() {
-    if UIApplication.shared.canOpenURL(URL(string: UIApplication.openSettingsURLString)!) {
-        UIApplication.shared.openURL(URL(string: UIApplication.openSettingsURLString)!)
-    }
-}
-
-/// dns解析
-/// - Parameter hostUrl: speed.piaoquantv.com /
-/// - Returns: <#description#>
-public func parseDNS(hostUrl: String) -> [String: Any]? {
-    let host: CFHost? = CFHostCreateWithName(nil, hostUrl as CFString).takeRetainedValue()
-    let start = CFAbsoluteTimeGetCurrent()
-    var success: DarwinBoolean = false
-    var addressList: [String] = Array<String>.init()
-    var addresses: NSArray?
-    if CFHostStartInfoResolution(host!, .addresses, nil) {
-        addresses = (CFHostGetAddressing(host!, &success)?.takeUnretainedValue())
-    }
-    if success == true {
-        for case let theAddress as NSData in addresses! {
-            var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
-            if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
-                           &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0
-            {
-                let numAddress = String(cString: hostname)
-                addressList.append("\(hostUrl)/\(numAddress)")
-            }
-        }
-    }
-    let end = CFAbsoluteTimeGetCurrent()
-    let duration = end - start
-    BFLog(message: "duration = \(duration)")
-    BFLog(message: "addressList = \(addressList)")
-    if addressList.count > 0 {
-        return ["dnsResult": arrayToJsonString(addressList), "duration": duration * 1000, "hostName": hostUrl, "networkType": networkStatus()]
-    } else {
-        return nil
-    }
-}
-
-/// 获取当前日期
-/// - Returns: <#description#>
-public func systemCurrentDate() -> String {
-    let dateFormatter = DateFormatter()
-    dateFormatter.dateFormat = "YYYY-MM-dd"
-    return dateFormatter.string(from: Date())
-}
-
-/// 时间戳转日期
-/// - Parameter timeInterval: <#timeInterval description#>
-/// - Returns: <#description#>
-public func timeIntervalToDateString(timeInterval: TimeInterval) -> String {
-    let date = Date(timeIntervalSince1970: timeInterval)
-    let dateFormatter = DateFormatter()
-    dateFormatter.dateFormat = "MM月dd日 HH:mm"
-    return dateFormatter.string(from: date)
-}
-
-/// 判断字符串或者字典是否为空
-/// - Parameter object: <#object description#>
-/// - Returns: <#description#>
-public func isEmpty(object: Any?) -> Bool {
-    if object == nil {
-        return true
-    }
-    if object is String {
-        return (object as! String).count <= 0
-    }
-    if object is [String: Any] {
-        return (object as! [String: Any]).keys.count <= 0
-    }
-    return false
-}
-
-public func isEmptyObject(object: Any?) -> Bool {
-    if object == nil {
-        return true
-    }
-    if object is String {
-        return object == nil || ((object as? String)?.count ?? 0) <= 0
-    }
-    if object is [String: Any] {
-        return object == nil || ((object as? [String: Any])?.keys.count ?? 0) <= 0
-    }
-    if object is List<Object> {
-        return object == nil || ((object as? List<Object>)?.count ?? 0) <= 0
-    }
-    return false
-}
-
-/// <#Description#>
-/// - Parameter string: <#string description#>
-/// - Returns: <#description#>
-public func isIncludeChineseIn(string: String) -> Bool {
-    for (_, value) in string.enumerated() {
-        if value >= "\u{4E00}", value <= "\u{9FA5}" {
-            return true
-        }
-    }
-    return false
-}
-
-/// 获取文件内容的MD5
-/// - Parameters:
-///   - path: 地址
-///   - data: data
-/// - Returns: <#description#>
-public func contentMD5(path: String? = nil, data _: Data? = nil) -> String? {
-    if path == nil || (path?.count ?? 0) <= 0 || !FileManager.default.fileExists(atPath: path ?? "") {
-        BFLog(message: "生成内容md5值:地址错误或者不存在\(String(describing: path))")
-        return ""
-    }
-    let att = try? FileManager.default.attributesOfItem(atPath: path ?? "")
-    let size = Int64(att?[FileAttributeKey.size] as! UInt64)
-    if size <= 0 {
-        BFLog(message: "生成内容md5值:文件大小为0\(size)")
-        return ""
-    }
-    let hash: String = OSSUtil.base64Md5(forFilePath: path)
-    BFLog(message: "生成内容md5值:contentMD5 = \(hash)")
-    return hash
- 
-}
-
- 
-
-/// 自适应宽
-/// - Parameters:
-///   - width: <#width description#>
-///   - baseWidth: <#baseWidth description#>
-/// - Returns: <#description#>
-public func adapterWidth(width: CGFloat, baseWidth: CGFloat = 375) -> CGFloat {
-    return width / baseWidth * cScreenWidth
-}
-
-/// 自适应高
-/// - Parameters:
-///   - height: <#height description#>
-///   - baseHeight: <#baseHeight description#>
-/// - Returns: <#description#>
-public func adapterHeight(height: CGFloat, baseHeight: CGFloat = 812) -> CGFloat {
-    return height / baseHeight * cScreenHeigth
-}
-
-/// 检测URL
-/// - Parameter url: <#url description#>
-/// - Returns: <#description#>
-public func isValidURL(url: String?) -> Bool {
-    if url == nil || (url?.count ?? 0) <= 4 || (!(url?.hasPrefix("http") ?? false) && !(url?.hasPrefix("https") ?? false)) {
-        return false
-    }
-    return true
-}
-
-/// 相册数据按创建时间排序
-public var creaFetchOptions: PHFetchOptions = {
-    let fetchOptions = PHFetchOptions()
-    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
-    return fetchOptions
-}()
-
-/// 相册数据按修改时间排序
-public var modiFetchOptions: PHFetchOptions = {
-    let fetchOptions = PHFetchOptions()
-    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "modificationDate", ascending: false)]
-    return fetchOptions
-}()
-
-/// 获取本地素材
-public  var avAssertOptions: [String: Any]? = {
-    [AVURLAssetPreferPreciseDurationAndTimingKey: NSNumber(value: true)]
-}()
-
-/// 播放动画图
-public var playGifImages: [UIImage] = {
-    var gifImages = Array<UIImage>.init()
-    for i in 0 ... 44 {
-        gifImages.append(UIImage(named: "\(i).png")!)
-    }
-    
-    return gifImages
-}()
-
-/// 压缩图片
-/// - Parameter image: <#image description#>
-/// -
-/// - Returns: <#description#>
-public func zipImage(image: UIImage?, size: Int) -> Data? {
-    var data = image?.pngData()
-    var dataKBytes = Int(data?.count ?? 0) / 1000
-    var maxQuality = 0.9
-    while dataKBytes > size, maxQuality > 0.01 {
-        maxQuality = maxQuality - 0.01
-        data = image?.jpegData(compressionQuality: CGFloat(maxQuality))
-        dataKBytes = (data?.count ?? 0) / 1000
-    }
-    return data
-}

+ 0 - 273
BFFramework/Classes/Utils/PQConstant.swift

@@ -1,273 +0,0 @@
-//
-//  PQConstant.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/25.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import Foundation
-import Kingfisher
-import UIKit
-
-public let cScreenWidth: CGFloat = UIScreen.main.bounds.width
-public let cScreenHeigth: CGFloat = UIScreen.main.bounds.height
-
-// 屏幕适配系数  iponneX?
-public let cAdaptatWidth = cScreenWidth / 375
-public let cAdaptatHeigth = cScreenHeigth / 667
-/// 图库大小
-public let photoItemSize = CGSize(width: (cScreenWidth - cDefaultMargin) / 3, height: (cScreenWidth - cDefaultMargin) / 3) // cell 大小
-// add by ak 视频制作工具视频画布大小
-// 1:1
-public let cVideoCannvasSizeOneToOne = CGSize(width: 1080.0, height: 1080.0)
-// 16:9
-public let cVideoCannvasSizeSixteenToNine = CGSize(width: 1920.0, height: 1080.0)
-// 9:16
-public let cVideoCannvasSizeNineToSixteen = CGSize(width: 1080.0, height: 1920.0)
-
-// add by ak 声频 hz
-public let cEditAudioSampleRate = 44100
-
-// 获取安全区域大小
-public let cSafeAreaHeight: CGFloat = cIPHONE_X() == true ? 34.0 : 0.0
-
-// 获取安全区域大小
-public let cAKSafeAreaHeight: CGFloat = cIPHONE_X() == true ? 25.0 : 0.0
-
-public let cDevice_iPhoneStatusBarHei: CGFloat = cIPHONE_X() == true ? 44.0 : 20.0
-public let cDevice_iPhoneNavBarHei: CGFloat = 44.0
-public let cDevice_iPhoneNavBarAndStatusBarHei: CGFloat = cDevice_iPhoneStatusBarHei + cDevice_iPhoneNavBarHei
-public let cDevice_iPhoneTabBarHei: CGFloat = cSafeAreaHeight + 49.0
-// 遮罩颜色
-public let cShadowColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
-/// 通知
-public let PQNotification: NotificationCenter = NotificationCenter.default
-
-/** 默认间隔 */
-public let cDefaultMargin: CGFloat = 10
-// 时间精度
-public let playerTimescale: Float64 = 1000.0
-// 时间精度Ints
-public let playerTimescaleInt: Int32 = 1000
-// 最大上传大小 10G
-public let maxUploadSize: Float64 = 10.0 * 1024.0 * 1024.0 * 1024.0
-// 最大素材大小 500M
-public let maxMartialSize: Float64 = 500.0 * 1024.0 * 1024.0
-/// 音频频率范围值
-public let cFrequency: [CGFloat] = [9.0, 12.0, 16.5, 18, 24, 21, 18, 16.5, 12, 16.5, 18, 16.5, 12]
-/**************** tag *******************/
-
-public let cCellTag: Int = 100_001
-/** 引导 tag */
-public let cGuideTag: Int = 100_002
-/** 视频封面tag */
-public let cCoverInfoTag: Int = 100_003
-/** 协议tag */
-public let cProtocalViewTag: Int = 100_004
-/** 心形tag */
-public let cHeartTag: Int = 100_005
-/** 订阅提示tag */
-public let cSubcribeRemindTag: Int = 100_006
-/** 订阅提示tag */
-public let cPushRemindTag: Int = 100_007
-/** 活动提示tag */
-public let cActivityRemindTag: Int = 100_008
-/** pay提示tag */
-public let cPayInfoTag: Int = 100_009
-/** 绑定手机号提示tag */
-public let cBandinPhoneTag: Int = 100_010
-/// 上传最大viewTag
-public let cUploadMaxCountRemindTag: Int = 100_011
-/// 上传提示tag
-public let cUploadViewRemindTag: Int = 100_012
-/// 视频制作播放背景音乐的tag
-public let cVideoMKBGMPlayTag: Int = 100_013
-/// 上滑提示tag
-public let cUpSlideViewRemindTag: Int = 100_014
-/// 创作视频引导提示tag
-public let cVideoMakeRemindTag: Int = 100_015
-/// 操作弹出tag
-public let cOprationRemindTag: Int = 100_016
-/// 气泡提示视图tag
-public let cBubbleRemindViewTag: Int = 100_017
-/// 素材推荐提示tag
-public let cRecommendMaterialViewTag: Int = 100_018
-/// 气泡提示视图tag
-public let cPageMaterialGuidTag: Int = 100_019
-/// 信息流视频广告tag
-public let cAdDrawVideoViewTag: Int = 100_020
-/****************** 私有key ***************/
-
-// 创作工具-项目id前缀
-public let cProjectIdPrefix: String = "app_no_projectdata_"
-
-public let cPrimarykey: String = "@taiziliudong_2020"
-// ---
-public let cRedEnvoStorageKey: String = "redEnvo\(cPrimarykey)"
-public let cOriginStorageKey: String = "origin\(cPrimarykey)"
-public let cZhiFStorageKey: String = "zhiF\(cPrimarykey)"
-public let cCoinStorageKey: String = "coin\(cPrimarykey)"
-public let cMoneStorageKey: String = "mone\(cPrimarykey)"
-public let cAccouStorageKey: String = "accou\(cPrimarykey)"
-public let cTasStorageKey: String = "tas\(cPrimarykey)"
-public let cGameStorageKey: String = "game\(cPrimarykey)"
-public let cSepraStorageKey: String = "sepra\(cPrimarykey)"
-public let cFreeStorageKey: String = "free\(cPrimarykey)"
-
-public let cRedImageStorageKey: String = "ic_hbs_enter\(cPrimarykey)"
-public let cNewImageStorageKey: String = "icon_hbs_free\(cPrimarykey)"
-
-// 用户信息key
-public let cUserInfoStorageKey: String = "userInfo\(cPrimarykey)"
-// 是否加载过引导页
-public let cGuidedInfoStorageKey: String = "guidedInfo\(cPrimarykey)"
-// 是否第一次安装
-public let cFirstInstall: String = "firstInstall\(cPrimarykey)"
-// 第一次冷启动未上传参数
-public let cFirstParams: String = "firstParams\(cPrimarykey)"
-
-// 是否显示了协议
-public let cShowProtocal: String = "showProtocal\(cPrimarykey)"
-
-// 是否竖滑过
-public let cIsVerticalSlip: String = "isVerticalSlip\(cPrimarykey)"
-// 是否横滑过
-public let cIsSideslip: String = "isSideslip\(cPrimarykey)"
-// 是否在浏览态/操作态 单击过(不包含播放结束)
-public let cIsSingleClick: String = "isSingleClick\(cPrimarykey)"
-// 是否显示过竖滑提示
-public let cIsVerticalSlipTip: String = "isVerticalSlipTip\(cPrimarykey)"
-// 是否显示过竖滑提示
-public let cIsSideslipTip: String = "isSideslipTip\(cPrimarykey)"
-// 是否显示过单击提示
-public let cIsSingleClickTip: String = "isSingleClickTip\(cPrimarykey)"
-// 是否显示过单击提示
-public let cIsLikeTip: String = "isLikeTip\(cPrimarykey)"
-// 是否显示过横屏提示
-public let cIsLandscapeTip: String = "isLandscapeTip\(cPrimarykey)"
-// 是否点击过
-public let cIsUploadClick: String = "isUploadClick\(cPrimarykey)"
-// 当前选中的tab
-public let cSelectedTabIndex: String = "selectedTabIndex\(cPrimarykey)"
-// 登录用户当前视频数
-public let cMineVideos: String = "mineVideos\(cPrimarykey)"
-// 登录用户当前视频数
-public let cMineFans: String = "mineFans\(cPrimarykey)"
-// 别人订阅我的数量
-public let cOtherSubscribes: String = "otherSubscribes\(cPrimarykey)"
-/// 登录用户关注数
-public let cMineIdols: String = "mineIdols\(cPrimarykey)"
-// 登录用户头像
-public let cAvatarUrl: String = "avatarUrl\(cPrimarykey)"
-// 绑定手机号
-public let cUpdatePhone: String = "updatePhone\(cPrimarykey)"
-// 添加视频
-public let cInsertVideo: String = "InsertVideo\(cPrimarykey)"
-// 是否是新用户参加RedActivity
-public let cIsNewRedActivityUser: String = "isNewRedActivityUser\(cPrimarykey)"
-// 是否已经显示过昨天完成
-public let cIsYesdayFinishRedActivity: String = "isYesdayFinishRedActivity\(cPrimarykey)"
-// 是否已经显示过未完成昨天RedActivity
-public let cIsYesdayNoFinishRedActivity: String = "isYesdayNoFinishRedActivity\(cPrimarykey)"
-// 是否已经显示过今日已完成
-public let cIsTodayFinishRedActivity: String = "isTodayFinishRedActivity\(cPrimarykey)"
-// 是否已经显示过我的制作提示
-public let cIsShowDraftBoxEntranceRemind: String = "isShowDraftBoxEntranceRemind\(cPrimarykey)"
-// 是否展示过定位提醒
-public let cIsShoWedLocationView: String = "isShoWedLocationView\(cPrimarykey)"
-// 是否展示编辑封面提示
-public let cIsShoWedEditCoverRemindView: String = "isShoWedEditCoverRemindView\(cPrimarykey)"
-// 创作工具是否添加音乐去预览时提示
-public let cIsShoWedAddBGMPreRemindView: String = "isShoWedAddBGMPreRemindView\(cPrimarykey)"
-// 创作工具添加音乐提示
-public let cShoWedAddBGMRemindView: String = "shoWedAddBGMRemindView\(cPrimarykey)"
-// 刷新已读数
-public let cUpdateMsgNoReadCount: String = "updateMsgNoReadCount\(cPrimarykey)"
-
-// add by ak 是否显示过裁剪引导
-public let cIsShowImageCropGuid: String = "isShowImageCropGuid\(cPrimarykey)"
-// 编辑界面引导是否显示过 add by ak
-public let cEditPageGuidIsShow: String = "cEditPageGuidIsShow\(cPrimarykey)"
-// 画布引导
-public let cEditPageCanvasGuidIsShow: String = "cEditPageCanvasGuidIsShow\(cPrimarykey)"
-// 素材移动引导
-public let cEditPageMaterialGuidIsShow: String = "cEditPageMaterialGuidIsShow\(cPrimarykey)"
-// ******************* 通知key ******************* //
-
-// 关注
-public let cAttendtionNotiKey: String = "attendtionNoti\(cPrimarykey)"
-// 订阅
-public let cSubscribeNotiKey: String = "subscribeNoti\(cPrimarykey)"
-// 加入黑名单
-public let cBannedNotiKey: String = "bannedNoti\(cPrimarykey)"
-// 喜欢
-public let cFavoriteNotiKey: String = "favoriteNoti\(cPrimarykey)"
-// 退出登录
-public let cQuitSuccesssNotiKey: String = "quitSuccesssNoti\(cPrimarykey)"
-// 登录成功
-public let cLoginSuccesssNotiKey: String = "loginSuccesssNoti\(cPrimarykey)"
-// 更新用户数据
-public let cUpdateInfoNotiKey: String = "updateInfoNoti\(cPrimarykey)"
-// 是否显示手机登录 1-显示 0-不显示
-public let cNeedLoginKey: String = "needLogin\(cPrimarykey)"
-// 发布视频成功通知
-public let cPublishSuccessKey: String = "publishSuccess\(cPrimarykey)"
-// 发布卡点视频成功通知
-public let cPublishStuckPointSuccessKey: String = "publishStuckPointSuccess\(cPrimarykey)"
-public let cUploadSuccessKey: String = "uploadSuccess\(cPrimarykey)"
-/// 更新视频成功
-public let cUpdateVideoSuccessKey: String = "updateVideoSuccess\(cPrimarykey)"
-/// 绑定手机号成功的通知
-public let cBandingPhoneSuccessKey: String = "bandingPhoneSuccessKey\(cPrimarykey)"
-/// 图库添加图片的通知
-public let cSelectedImageSuccessKey: String = "selectedImageSuccess\(cPrimarykey)"
-/// 删除视频的通知
-public let cDeleteVideoSuccessKey: String = "deleteVideoSuccess\(cPrimarykey)"
-/// 导出背景音乐成功的通知
-public let cExportBGMAudioSuccessKey: String = "exportBGMxAudioSuccess\(cPrimarykey)"
-/// 下载资源成功/失败的key
-public let cDownloadMatrialSuccessKey: String = "downloadMatrialSuccess\(cPrimarykey)"
-/// 素材处理成功key
-public let cVideoDealWithSuccessKey: String = "videoDealWithSuccess\(cPrimarykey)"
-
-/// 批量下载资源成功/失败的key
-public let cBatchDownloadMatrialSuccessKey: String = "batchDownloadMatrialSuccess\(cPrimarykey)"
-/// 批量上传资源成功/失败的key
-public let cBatchUploadMatrialSuccessKey: String = "batchUploadMatrialSuccessKey\(cPrimarykey)"
-/// 再创作成功的key
-public let cReCreateVideoSuccessKey: String = "reCreateVideoSuccess\(cPrimarykey)"
-/// 收藏/取消背景音乐的通知
-public let cFavoriteBgmKey: String = "favoriteBgm\(cPrimarykey)"
-/// 保存素材成功通知
-public let cSaveMaterialSuccessKey: String = "saveMaterialSuccess\(cPrimarykey)"
-/// 音频素材转换成文字成功
-public let cAudioTransferSubTitleSuccessKey: String = "audioTransferSubTitleSuccess\(cPrimarykey)"
-/// 无网
-public let cLostNet: String = "lostNet\(cPrimarykey)"
-// 取消视频发布引导弹框
-public let cDismissVideoMakeGuideKey: String = "dismissVideoMakeGuide\(cPrimarykey)"
-// 点击完成或发布完成跳转
-public let cFinishedPublishedNotiKey: String = "finishedPublishedNotiKey\(cPrimarykey)"
- 
-// oss 上传文件进度 add by ak
-public let cOSSUploadFileProgress: String = "OSSUploadFileProgress\(cPrimarykey)"
-
-// 渠道
-public let channelID = "AppStore"
-// 推送渠道
-public let cPushChannel = "APPLE_TYPE"
-
-// MARK: 账号
-
-// 友盟账号
-public let cUMAppkey: String = "5ee4a806978eea081640dfe4"
-
-// 阿里反馈账号
-public let cAliFeedbackAppkey: String = "23591190"
-// 阿里反馈AppSecret
-public let cAliFeedbackAppSecret: String = "3b831b2068aef36607886a3912ef4fbb"
-// 百度定位key
-public let cBMKLocationAppkey: String = "buprQzBBojKbvDvED8Xix7xHA91ShAnL"
-// 分享小程序ID
-public let cShareWeappRawId: String = "gh_ecd1ea0b84cf"

+ 4 - 0
Example/BFFramework.xcodeproj/project.pbxproj

@@ -253,6 +253,8 @@
 				"${PODS_ROOT}/Target Support Files/Pods-BFFramework_Example/Pods-BFFramework_Example-frameworks.sh",
 				"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
 				"${BUILT_PRODUCTS_DIR}/AliyunOSSiOS/AliyunOSSiOS.framework",
+				"${BUILT_PRODUCTS_DIR}/BFCommonKit/BFCommonKit.framework",
+				"${BUILT_PRODUCTS_DIR}/BFNetRequestKit/BFNetRequestKit.framework",
 				"${BUILT_PRODUCTS_DIR}/FDFullscreenPopGesture/FDFullscreenPopGesture.framework",
 				"${BUILT_PRODUCTS_DIR}/KeychainAccess/KeychainAccess.framework",
 				"${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework",
@@ -270,6 +272,8 @@
 			outputPaths = (
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AliyunOSSiOS.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BFCommonKit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BFNetRequestKit.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FDFullscreenPopGesture.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KeychainAccess.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework",

+ 1 - 0
Example/BFFramework/ViewController.swift

@@ -7,6 +7,7 @@
 //
 
 import BFFramework
+import BFCommonKit
 import UIKit
 
 class ViewController: UIViewController {

+ 3 - 0
Example/Podfile

@@ -3,5 +3,8 @@ install!'cocoapods',:deterministic_uuids=>false
 platform :ios, '10.0'
 
 target 'BFFramework_Example' do
+  source 'https://git.yishihui.com/wenweiwei/BFSpecs.git'
+  source 'https://github.com/CocoaPods/Specs.git'
+#  pod 'BFCommonKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFCommonKit/'
   pod 'BFFramework', :path => '../'
 end

+ 57 - 27
Example/Podfile.lock

@@ -1,22 +1,47 @@
 PODS:
-  - Alamofire (4.9.1)
+  - Alamofire (5.4.3)
   - AliyunOSSiOS (2.10.8)
-  - BFFramework (0.1.1):
-    - Alamofire (= 4.9.1)
-    - AliyunOSSiOS (= 2.10.8)
-    - Bugly (= 2.5.90)
+  - BFCommonKit (1.1.8):
+    - BFCommonKit/BFBase (= 1.1.8)
+    - BFCommonKit/BFCategorys (= 1.1.8)
+    - BFCommonKit/BFConfig (= 1.1.8)
+    - BFCommonKit/BFDebug (= 1.1.8)
+    - BFCommonKit/BFEnums (= 1.1.8)
+    - BFCommonKit/BFUtility (= 1.1.8)
+  - BFCommonKit/BFBase (1.1.8):
+    - Alamofire (= 5.4.3)
+    - BFCommonKit/BFCategorys
+    - BFCommonKit/BFConfig
+    - BFCommonKit/BFUtility
     - FDFullscreenPopGesture (= 1.1)
+    - RealmSwift (= 10.7.6)
+    - SnapKit (= 5.0.1)
+  - BFCommonKit/BFCategorys (1.1.8):
+    - KingfisherWebP (= 1.3.0)
+  - BFCommonKit/BFConfig (1.1.8)
+  - BFCommonKit/BFDebug (1.1.8):
+    - BFCommonKit/BFCategorys
+  - BFCommonKit/BFEnums (1.1.8)
+  - BFCommonKit/BFUtility (1.1.8):
+    - Alamofire (= 5.4.3)
+    - BFCommonKit/BFCategorys
+    - BFCommonKit/BFConfig
     - KeychainAccess (= 4.2.2)
     - Kingfisher (= 6.3.0)
     - KingfisherWebP (= 1.3.0)
+    - Toast-Swift (= 5.0.1)
+  - BFFramework (1.0.0):
+    - AliyunOSSiOS (= 2.10.8)
+    - BFCommonKit
+    - BFNetRequestKit
+    - Bugly (= 2.5.90)
     - LMJHorizontalScrollText (= 2.0.2)
-    - MJRefresh (= 3.5.0)
+    - MJRefresh (= 3.6.1)
     - ObjectMapper (= 4.2.0)
-    - RealmSwift (= 10.7.2)
-    - SnapKit (= 4.2.0)
-    - Toast-Swift (= 5.0.1)
-    - TXLiteAVSDK_Player (= 8.4.9944)
+    - TXLiteAVSDK_Player (= 8.7.10102)
     - WechatOpenSDK-Swift (= 1.8.7.1)
+  - BFNetRequestKit (0.1.4):
+    - Alamofire (= 5.4.3)
   - Bugly (2.5.90)
   - FDFullscreenPopGesture (1.1)
   - KeychainAccess (4.2.2)
@@ -34,23 +59,26 @@ PODS:
     - libwebp/demux
   - libwebp/webp (1.2.0)
   - LMJHorizontalScrollText (2.0.2)
-  - MJRefresh (3.5.0)
+  - MJRefresh (3.6.1)
   - ObjectMapper (4.2.0)
-  - Realm (10.7.2):
-    - Realm/Headers (= 10.7.2)
-  - Realm/Headers (10.7.2)
-  - RealmSwift (10.7.2):
-    - Realm (= 10.7.2)
-  - SnapKit (4.2.0)
+  - Realm (10.7.6):
+    - Realm/Headers (= 10.7.6)
+  - Realm/Headers (10.7.6)
+  - RealmSwift (10.7.6):
+    - Realm (= 10.7.6)
+  - SnapKit (5.0.1)
   - Toast-Swift (5.0.1)
-  - TXLiteAVSDK_Player (8.4.9944)
+  - TXLiteAVSDK_Player (8.7.10102)
   - WechatOpenSDK-Swift (1.8.7.1)
 
 DEPENDENCIES:
   - BFFramework (from `../`)
 
 SPEC REPOS:
-  trunk:
+  https://git.yishihui.com/wenweiwei/BFSpecs.git:
+    - BFCommonKit
+    - BFNetRequestKit
+  https://github.com/CocoaPods/Specs.git:
     - Alamofire
     - AliyunOSSiOS
     - Bugly
@@ -74,9 +102,11 @@ EXTERNAL SOURCES:
     :path: "../"
 
 SPEC CHECKSUMS:
-  Alamofire: 85e8a02c69d6020a0d734f6054870d7ecb75cf18
+  Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9
   AliyunOSSiOS: 8db92936545593b9e5c66d680ef2ac0738946651
-  BFFramework: c111f401f256a6459f5ffa146cedad5f304f48a9
+  BFCommonKit: d7e5b2b13f34cf578e0f2dc6896618c0970fbae9
+  BFFramework: ad60184334d37fed96f4d9d0dd694bd933c4cab7
+  BFNetRequestKit: bec1d28012c7206cdf775fb31e394139d245d376
   Bugly: 88bc32c0acc6fef7b74d610f0319ee7560d6b9fe
   FDFullscreenPopGesture: a8a620179e3d9c40e8e00256dcee1c1a27c6d0f0
   KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
@@ -84,15 +114,15 @@ SPEC CHECKSUMS:
   KingfisherWebP: dec17a5eb1af2658791bde1f93ae9a853678f826
   libwebp: e90b9c01d99205d03b6bb8f2c8c415e5a4ef66f0
   LMJHorizontalScrollText: ebc9b908db297f603c5b98c9b4e5f4582f5a14b8
-  MJRefresh: 6afc955813966afb08305477dd7a0d9ad5e79a16
+  MJRefresh: d2c1970d1cf6e77fcfcdfe76c943dfab8dbfa5c1
   ObjectMapper: 1eb41f610210777375fa806bf161dc39fb832b81
-  Realm: e523da9ade306c5ae87e85dc09fdef148d3e1cc1
-  RealmSwift: 4f6758c3adbdcc87f7b7777107226532a077f61c
-  SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a
+  Realm: ed860452717c8db8f4bf832b6807f7f2ce708839
+  RealmSwift: e31c4ddbcc42ac879313d656b86f9ca539f6f4f4
+  SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
   Toast-Swift: 9b6a70f28b3bf0b96c40d46c0c4b9d6639846711
-  TXLiteAVSDK_Player: 3542b8d539779d57b3c870eac00321f8ab0f05f8
+  TXLiteAVSDK_Player: 84adacb818b70fa5a43dc268782c8fe54d3f26f6
   WechatOpenSDK-Swift: 18a8f7b12e745c30acc013f72a9f8a25aad6e216
 
-PODFILE CHECKSUM: c4df0050584ce2cb487016f3899dfb474d4fbccc
+PODFILE CHECKSUM: b2f788cdc3525929fa31592b4ea2730a6ad57e08
 
 COCOAPODS: 1.10.1