杨锴
2024-09-12 e15c976316feef72ff9bcabce38e0a078f9505db
fix API
40个文件已修改
11个文件已添加
1297 ■■■■ 已修改文件
XQMuse.xcodeproj/project.pbxproj 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/.DS_Store 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/.DS_Store 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Placeholder/.DS_Store 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/Enums/Enums.swift 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.xib 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/TCell/CourseDetail_1_TCell.swift 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/TCell/CourseDetail_1_TCell.xib 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.swift 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.xib 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/TCell/CourseDetail_2_TCell.swift 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/TCell/CourseDetail_3_TCell.swift 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseDetialVC.swift 77 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseDetialVideoVC.swift 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseMenuVC.swift 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/View/CourseDetailHeaderView.swift 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/View/CourseDetailHeaderView.xib 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/View/CourseSendGiftView.swift 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/HomeVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/BackgroundVoiceVC.swift 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/HomeItemDetailVC.swift 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/HomeItemDetailVC.xib 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/SearchContentVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/Models.swift 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/Services.swift 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Other/View/CommonBannerView.swift 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Other/View/VideoView.swift 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/CCell/PavilionItemCell.xib 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/PavilionVC.swift 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/PavilionVC.xib 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/VC/PavilionSearchVC.xib 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/PayMusicView/PayMusicVC.swift 226 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse.xcodeproj/project.pbxproj
@@ -162,6 +162,7 @@
        1385E0072C6C558200AADB1F /* HomeRelaxBanner_2_CCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1385E0052C6C558200AADB1F /* HomeRelaxBanner_2_CCell.xib */; };
        1385E00A2C6C57A900AADB1F /* HomeItemDetailVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1385E0082C6C57A900AADB1F /* HomeItemDetailVC.swift */; };
        1385E00B2C6C57A900AADB1F /* HomeItemDetailVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1385E0092C6C57A900AADB1F /* HomeItemDetailVC.xib */; };
        1388840E2C92B5E80043AAB4 /* CommonBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1388840D2C92B5E80043AAB4 /* CommonBannerView.swift */; };
        13897D892C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */; };
        138F0C322C7594BB0072A16C /* TreatyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 138F0C312C7594BB0072A16C /* TreatyVC.swift */; };
        138F0C352C7597CA0072A16C /* HelpCenterVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 138F0C332C7597CA0072A16C /* HelpCenterVC.swift */; };
@@ -445,6 +446,7 @@
        1385E0052C6C558200AADB1F /* HomeRelaxBanner_2_CCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeRelaxBanner_2_CCell.xib; sourceTree = "<group>"; };
        1385E0082C6C57A900AADB1F /* HomeItemDetailVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeItemDetailVC.swift; sourceTree = "<group>"; };
        1385E0092C6C57A900AADB1F /* HomeItemDetailVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeItemDetailVC.xib; sourceTree = "<group>"; };
        1388840D2C92B5E80043AAB4 /* CommonBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonBannerView.swift; sourceTree = "<group>"; };
        13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EqualCellSpaceFlowLayout.swift; sourceTree = "<group>"; };
        138F0C312C7594BB0072A16C /* TreatyVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatyVC.swift; sourceTree = "<group>"; };
        138F0C332C7597CA0072A16C /* HelpCenterVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpCenterVC.swift; sourceTree = "<group>"; };
@@ -1177,6 +1179,7 @@
        13D256B52C6C68EB006FC2D7 /* View */ = {
            isa = PBXGroup;
            children = (
                1388840D2C92B5E80043AAB4 /* CommonBannerView.swift */,
                136C7C7C2C7715C9004540CD /* BitrhdayPickerView.swift */,
                13F24E432C75901500D2BA90 /* CommonAlertView.swift */,
                13F24E442C75901600D2BA90 /* CommonAlertView.xib */,
@@ -1518,6 +1521,7 @@
                13985DAF2C69B7B00046B6DC /* BaseNav.swift in Sources */,
                134A45352C6E0E0000538D78 /* CourseVCTeacherSpecialVC.swift in Sources */,
                13E4ECEE2C80778A0095AD04 /* PlanGuide_2_VC.swift in Sources */,
                1388840E2C92B5E80043AAB4 /* CommonBannerView.swift in Sources */,
                134A45392C6E167D00538D78 /* CourseOfficalCommendTopCCell.swift in Sources */,
                1338A6DD2C76DD5E006CDD15 /* SpendingDetailInfoVC.swift in Sources */,
                138FE0E22C757DE900A964E8 /* BindPhone_2_VC.swift in Sources */,
@@ -1795,7 +1799,10 @@
                GENERATE_INFOPLIST_FILE = YES;
                INFOPLIST_FILE = XQMuse/Info.plist;
                INFOPLIST_KEY_CFBundleDisplayName = "心泉冥想";
                INFOPLIST_KEY_LSApplicationCategoryType = "";
                INFOPLIST_KEY_NSCameraUsageDescription = "相机";
                INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "定位";
                INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "定位";
                INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "相册";
                INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
                INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
@@ -1834,7 +1841,10 @@
                GENERATE_INFOPLIST_FILE = YES;
                INFOPLIST_FILE = XQMuse/Info.plist;
                INFOPLIST_KEY_CFBundleDisplayName = "心泉冥想";
                INFOPLIST_KEY_LSApplicationCategoryType = "";
                INFOPLIST_KEY_NSCameraUsageDescription = "相机";
                INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "定位";
                INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "定位";
                INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "相册";
                INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
                INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
XQMuse/Assets.xcassets/.DS_Store
Binary files differ
XQMuse/Assets.xcassets/Icons/.DS_Store
Binary files differ
XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "icon_play_close@2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "filename" : "icon_play_close@3x.png",
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}
XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@2x.png
XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@3x.png
XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "icon_play_small@2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "filename" : "icon_play_small@3x.png",
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}
XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@2x.png
XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@3x.png
XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "icon_use_small_s@2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "filename" : "icon_use_small_s@3x.png",
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}
XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@2x.png
XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@3x.png
XQMuse/Assets.xcassets/Placeholder/.DS_Store
Binary files differ
XQMuse/Config/Enums/Enums.swift
@@ -30,6 +30,11 @@
                case payment = 3 // 需支付
}
enum DeliverStudyType:Int,HandyJSONEnum{
                case online = 1 // 线上课程
                case offline = 2 //线下课程
}
enum ConditionType:Int,HandyJSONEnum{
                case yes = 1
                case no = 2
XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift
@@ -10,9 +10,11 @@
class CourseOfficalCommendTopCCell: UICollectionViewCell {
                @IBOutlet weak var view_bannerContentView: UIView!
                @IBOutlet weak var view_bannerContentView: CommonBannerView!
                @IBOutlet weak var collectionView: UICollectionView!
                @IBOutlet weak var cons_hei: NSLayoutConstraint!
                private var titleItems = [TitleItem]()
                private var bannerModels = [CommonBannerModel]()
                private var clouse:((Int)->Void)?
                override func awakeFromNib() {
        super.awakeFromNib()
@@ -25,9 +27,15 @@
                func setTitles(_ items:[TitleItem]){
                                titleItems = items
                                cons_hei.constant = ceil(Double(items.count) / 4) * 103.75
                                collectionView.reloadData()
                }
                func setBanners(_ items:[CommonBannerModel]){
                                bannerModels = items
                                view_bannerContentView.setItems(items: items)
                }
                func clickAtClouse(_ clouse:@escaping (Int)->Void){
                                self.clouse = clouse
                }
XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.xib
@@ -18,7 +18,7 @@
                <rect key="frame" x="0.0" y="0.0" width="328" height="408"/>
                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                <subviews>
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LpV-bY-BWS">
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LpV-bY-BWS" customClass="CommonBannerView" customModule="XQMuse" customModuleProvider="target">
                        <rect key="frame" x="0.0" y="0.0" width="328" height="171"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
@@ -54,6 +54,7 @@
            <size key="customSize" width="328" height="408"/>
            <connections>
                <outlet property="collectionView" destination="IAR-Fq-op8" id="B6V-Mt-S1J"/>
                <outlet property="cons_hei" destination="JM2-hK-TGn" id="ICv-Ho-iAa"/>
                <outlet property="view_bannerContentView" destination="LpV-bY-BWS" id="AyT-5Y-Vaq"/>
            </connections>
            <point key="canvasLocation" x="293.12977099236639" y="146.47887323943664"/>
XQMuse/Root/Course/TCell/CourseDetail_1_TCell.swift
@@ -7,11 +7,16 @@
import UIKit
import WebKit
import RxSwift
class CourseDetail_1_TCell: UITableViewCell {
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var webView: WKWebView!
                @IBOutlet weak var cons_webHei: NSLayoutConstraint!
                private var disposeBag = DisposeBag()
                override func awakeFromNib() {
        super.awakeFromNib()
                                backgroundColor = .clear
@@ -20,6 +25,17 @@
                                webView.scrollView.isScrollEnabled = false
                                webView.scrollView.backgroundColor = .clear
                                webView.isOpaque = false
                                self.webView.scrollView.rx.observe(CGSize.self, "contentSize").map { (size) -> CGFloat? in
                                                if let size = size{
                                                                return size.height
                                                }
                                                return nil
                                }.subscribe(onNext: { [unowned self](height) in
                                                if let height = height{
                                                                self.cons_webHei.constant = height
                                                }
                                }).disposed(by: disposeBag)
    }
                func setContent(title:String,content:String){
XQMuse/Root/Course/TCell/CourseDetail_1_TCell.xib
@@ -46,6 +46,7 @@
                </constraints>
            </tableViewCellContentView>
            <connections>
                <outlet property="cons_webHei" destination="hfa-qQ-TpS" id="y2I-NC-2Cu"/>
                <outlet property="label_title" destination="Lg9-70-w3n" id="NPf-Sa-PgL"/>
                <outlet property="webView" destination="WYV-JQ-E3S" id="wJi-nk-vgm"/>
            </connections>
XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.swift
@@ -10,15 +10,28 @@
class CourseDetail_2_Inner_TCell: UITableViewCell {
                @IBOutlet weak var label_index: UILabel!
                @IBOutlet weak var btn_study: UIButton!
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_time: UILabel!
                @IBOutlet weak var label_people: UILabel!
                override func awakeFromNib() {
        super.awakeFromNib()
                                selectionStyle = .none
                                btn_study.isUserInteractionEnabled = false
    }
                func setModel(_ item:CourseItemModel,index:IndexPath){
                                label_index.text = "\(index.row + 1)"
                                label_title.text = item.chapterTitle
                                label_time.text = Date.jq_formateToTime(item.duration)
                                label_people.text = "\(item.realLearnedNum + item.virtualLearnedNum)"
    }
                @IBAction func studyAction(_ sender: Any) {
                                let vc = CourseDetialVideoVC()
                                JQ_currentViewController().jq_push(vc: vc)
//                                let vc = CourseDetialVideoVC()
//                                JQ_currentViewController().jq_push(vc: vc)
                }
                
}
XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.xib
@@ -108,6 +108,10 @@
            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
            <connections>
                <outlet property="btn_study" destination="q5a-cH-u74" id="vg6-WV-mdc"/>
                <outlet property="label_index" destination="uL3-AT-OQF" id="4bx-wD-U6f"/>
                <outlet property="label_people" destination="c0R-vF-UBG" id="S53-bw-wc8"/>
                <outlet property="label_time" destination="bXU-MP-QyS" id="O7i-eB-GXV"/>
                <outlet property="label_title" destination="awd-gM-ZRD" id="Tpo-Bu-RQX"/>
            </connections>
            <point key="canvasLocation" x="148.85496183206106" y="41.549295774647888"/>
        </tableViewCell>
XQMuse/Root/Course/TCell/CourseDetail_2_TCell.swift
@@ -6,13 +6,14 @@
//
import UIKit
import JQTools
class CourseDetail_2_TCell: UITableViewCell {
                @IBOutlet weak var tableView: UITableView!
                @IBOutlet weak var cons_tableHei: NSLayoutConstraint!
//                private(set) var clouse:((IndexPath)->Void)?
                private var items = [CourseItemModel]()
                override func awakeFromNib() {
        super.awakeFromNib()
@@ -24,28 +25,31 @@
                                tableView.backgroundColor = UIColor(hexString: "f6f6f6")
                                tableView.separatorStyle = .none
                                tableView.register(UINib(nibName: "CourseDetail_2_Inner_TCell", bundle: nil), forCellReuseIdentifier: "_CourseDetail_2_Inner_TCell")
                                cons_tableHei.constant = 70.5 * 5
                                cons_tableHei.constant = 0
    }
//                func selectAt(_ clouse:@escaping (IndexPath)->Void){
//                                if self.clouse == nil{
//                                                self.clouse = clouse
//                                }
//                }
                func setItems(_ items:[CourseItemModel]){
                                self.items = items
                                cons_tableHei.constant = 70.5 * Double(items.count)
                                self.tableView.reloadData()
                }
}
extension CourseDetail_2_TCell:UITableViewDelegate & UITableViewDataSource{
                func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//                                clouse?(indexPath)
                                let vc = CourseDetialVideoVC(items: items, selectIndex: indexPath)
                                JQ_currentViewController().jq_push(vc: vc)
                }
                func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                                return 5
                                return items.count
                }
                
                func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                                let model = items[indexPath.row]
                                let cell = tableView.dequeueReusableCell(withIdentifier: "_CourseDetail_2_Inner_TCell", for: indexPath) as! CourseDetail_2_Inner_TCell
                                cell.setModel(model, index: indexPath)
                                cell.backgroundColor = .clear
                                return cell
                }
XQMuse/Root/Course/TCell/CourseDetail_3_TCell.swift
@@ -14,6 +14,8 @@
                private let CellW  = (JQ_ScreenW - 21.5 * 2 - 13.5) / 2
                private let CellH = ((JQ_ScreenW - 21.5 * 2 - 13.5) / 2) * 1.313
                var items = [CourseModel]()
                override func awakeFromNib() {
                                super.awakeFromNib()
                                backgroundColor = .clear
@@ -25,20 +27,33 @@
                                collectionView.contentInset = UIEdgeInsets(top: 0, left: 21.5, bottom: 0, right: 21.5)
                                collectionView.register(UINib(nibName: "HomeRelaxBanner_2_CCell", bundle: nil), forCellWithReuseIdentifier: "_HomeRelaxBanner_2_CCell")
                                cons_hei.constant = ceil(5.0 / 2.0) * CellH + floor(5.0 / 2.0) * 13.5
                                cons_hei.constant = 0
                }
                func setItems(_ items:[CourseModel]){
                                self.items = items
                                cons_hei.constant = ceil(Double(items.count) / 2.0) * CellH + floor(Double(items.count) / 2.0) * 13.5
                                collectionView.reloadData()
                }
}
extension CourseDetail_3_TCell:UICollectionViewDelegate & UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return 5
                                return items.count
                }
                
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_CCell", for: indexPath) as! HomeRelaxBanner_2_CCell
                                cell.setCourseModel(items[indexPath.row])
                                cell.backgroundColor = .jq_randomColor
                                return cell
                }
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let model = items[indexPath.row]
                                let vc = CourseDetialVC(courseId: model.id)
                                JQ_currentViewController().jq_push(vc: vc)
                }
}
extension CourseDetail_3_TCell:UICollectionViewDelegateFlowLayout{
XQMuse/Root/Course/VC/CourseDetialVC.swift
@@ -24,6 +24,13 @@
                private var currentShowIndex:IndexPath = IndexPath(row: 0, section: 0)
                var isAnimationing = false
                private var style:CourseDetialStyle = .style1
                private var courseId:Int!
                private var courseDetailModel:CourseModel?
                private var section0TCell:CourseDetail_1_TCell!
                private var section1TCell:CourseDetail_2_TCell!
                private var section2TCell:CourseDetail_3_TCell!
                private var section0Height:Double = 0
                private(set) var pageMenu:SPPageMenu = {
                                let pageMenu = SPPageMenu(frame: .zero, trackerStyle: .line)
@@ -61,9 +68,9 @@
                                navigationController?.navigationBar.standardAppearance.backgroundColor = .clear
                }
                init(courseSytle:CourseDetialStyle) {
                init(courseId:Int) {
                                super.init(nibName: nil, bundle: nil)
                                self.style = courseSytle
                                self.courseId = courseId
                }
                
                required init?(coder: NSCoder) {
@@ -74,11 +81,23 @@
        super.viewDidLoad()
                                title = "课程详情"
                                if style == .style1{
                                                pageMenu.setItems(["简介","章节","相关推荐"], selectedItemIndex: 0)
                                Services.getCourseDetail(courseId: courseId).subscribe(onNext: {data in
                                                if let m = data.data{
                                                                self.courseDetailModel = m
                                                                self.headerView.setCourseModel(m)
                                                                self.section1TCell.setItems(m.list)
                                                                self.section2TCell.setItems(m.list2)
                                                                if m.detailUrl.jq_isVideo{
                                                                                self.style = .style1
                                                                                self.pageMenu.setItems(["简介","章节","相关推荐"], selectedItemIndex: 0)
                                }else{
                                                pageMenu.setItems(["简介"], selectedItemIndex: 0)
                                                                                self.style = .style2
                                                                                self.pageMenu.setItems(["简介"], selectedItemIndex: 0)
                                }
                                                                self.tableView?.reloadData()
                                                }
                                }).disposed(by: disposeBag)
    }
                override func setUI() {
@@ -98,6 +117,10 @@
                                tableView!.register(UINib(nibName: "CourseDetail_1_TCell", bundle: nil), forCellReuseIdentifier: "_CourseDetail_1_TCell")
                                tableView!.register(UINib(nibName: "CourseDetail_2_TCell", bundle: nil), forCellReuseIdentifier: "_CourseDetail_2_TCell")
                                tableView!.register(UINib(nibName: "CourseDetail_3_TCell", bundle: nil), forCellReuseIdentifier: "_CourseDetail_3_TCell")
                                section0TCell = (tableView!.dequeueReusableCell(withIdentifier: "_CourseDetail_1_TCell") as! CourseDetail_1_TCell)
                                section1TCell = (tableView!.dequeueReusableCell(withIdentifier: "_CourseDetail_2_TCell") as! CourseDetail_2_TCell)
                                section2TCell = (tableView!.dequeueReusableCell(withIdentifier: "_CourseDetail_3_TCell") as! CourseDetail_3_TCell)
                                view.addSubview(tableView!)
                                tableView!.snp.makeConstraints { make in
@@ -150,14 +173,35 @@
                                }
                }
                @objc func handleAction(_ btn:QMUIButton){
                override func setRx() {
                                section0TCell.webView.scrollView.rx.observe(CGSize.self, "contentSize").map { (size) -> CGFloat? in
                                                if let size = size{
                                                                return size.height
                                                }
                                                return nil
                                }.subscribe(onNext: { [unowned self](height) in
                                                if let height = height{
                                                                if height > section0Height{
                                                                                self.section0Height = height
                                                                                self.tableView?.reloadData()
                                                                }
                                                }
                                }).disposed(by: disposeBag)
                }
                @objc func handleAction(_ btn:QMUIButton){
                                if let items = courseDetailModel?.list{
                                                let vc = CourseDetialVideoVC(items: items, selectIndex: IndexPath(row: 0, section: 0))
                                                push(vc: vc)
                                }
                }
                @objc func sendGift(_ btn:QMUIButton){
                                CourseSendGiftView.show {
                                if let price = courseDetailModel?.generalPrice{
                                                CourseSendGiftView.show(price:price) {
                                                let vc = PaymentOrderVC()
                                                self.push(vc: vc)
                                                }
                                }
                }
@@ -182,30 +226,25 @@
                }
                func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
                                if indexPath.row == 0 || indexPath.row == 1{
                                                return UITableView.automaticDimension
                                }
                                return 770.736
                }
                func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                                if indexPath.row == 0{
                                                let cell = tableView.dequeueReusableCell(withIdentifier: "_CourseDetail_1_TCell") as! CourseDetail_1_TCell
                                                cell.backgroundColor = UIColor(hexString: "#f6f6f6")
                                                return cell
                                                section0TCell.webView.loadHTMLString(courseDetailModel?.briefIntroduction.jq_wrapHtml() ?? "", baseURL: nil)
                                                section0TCell.backgroundColor = UIColor(hexString: "#f6f6f6")
                                                return section0TCell
                                }
                                if indexPath.row == 1{
                                                let cell = tableView.dequeueReusableCell(withIdentifier: "_CourseDetail_2_TCell") as! CourseDetail_2_TCell
                                                cell.backgroundColor = UIColor(hexString: "#f6f6f6")
                                                return cell
                                                section1TCell.backgroundColor = UIColor(hexString: "#f6f6f6")
                                                return section1TCell
                                }
                                if indexPath.row == 2{
                                                let cell = tableView.dequeueReusableCell(withIdentifier: "_CourseDetail_3_TCell") as! CourseDetail_3_TCell
                                                cell.backgroundColor = UIColor(hexString: "#f6f6f6")
                                                return cell
                                                section2TCell.backgroundColor = UIColor(hexString: "#f6f6f6")
                                                return section2TCell
                                }
                                var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
XQMuse/Root/Course/VC/CourseDetialVideoVC.swift
@@ -13,17 +13,29 @@
                @IBOutlet weak var tableView: UITableView!
                private var videoView:VideoView?
                private var items = [CourseItemModel]()
                private var selectIndex:IndexPath!
                override func viewWillAppear(_ animated: Bool) {
                                super.viewWillAppear(animated)
                                (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal)
                }
                required init(items:[CourseItemModel],selectIndex:IndexPath) {
                                super.init(nibName: nil, bundle: nil)
                                self.items = items
                                self.selectIndex = selectIndex
                }
                required init?(coder: NSCoder) {
                                fatalError("init(coder:) has not been implemented")
                }
    override func viewDidLoad() {
        super.viewDidLoad()
                                title = "课程详情"
                                 videoView = VideoView(url: "http://vfx.mtime.cn/Video/2021/07/10/mp4/210710094507540173.mp4")
                                videoView = VideoView(url: items[selectIndex.row].videoUrl)
                                view_bg_video.addSubview(videoView!)
                                videoView!.snp.makeConstraints { make in
                                                make.edges.equalToSuperview()
@@ -45,8 +57,9 @@
}
extension CourseDetialVideoVC:UITableViewDataSource{
                func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                            return 10
                                return items.count
                }
                func numberOfSections(in tableView: UITableView) -> Int {
@@ -60,11 +73,33 @@
                func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                                let cell = tableView.dequeueReusableCell(withIdentifier: "_CourseDetail_2_Inner_TCell") as! CourseDetail_2_Inner_TCell
                                cell.setModel(items[indexPath.row], index: indexPath)
                                if items[indexPath.row].isOver == .yes{
                                                cell.btn_study.setTitle("已学习", for: .normal)
                                                cell.btn_study.backgroundColor = UIColor(hexString: "#CDCDCD")
                                }else{
                                                cell.btn_study.setTitle("去学习", for: .normal)
                                                cell.btn_study.backgroundColor = UIColor(hexString: "#8AAE65")
                                }
                                if indexPath.row == selectIndex.row{
                                                cell.btn_study.setTitle("正在学习", for: .normal)
                                                cell.btn_study.backgroundColor = UIColor(hexString: "#E3B25C")
                                }
                                return cell
                }
}
extension CourseDetialVideoVC:UITableViewDelegate{
                func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                                if selectIndex == indexPath{return}
                                selectIndex = indexPath
                                videoView?.updateVideoUrl(items[indexPath.row].videoUrl)
                                tableView.reloadData()
                }
}
XQMuse/Root/Course/VC/CourseMenuVC.swift
@@ -14,16 +14,14 @@
                private var collectionView:UICollectionView!
                private var titleItems = [TitleItem]()
                private var selectIndex:Int = 0
                private var viewModel = CourseVCOfficalViewModel()
    override func viewDidLoad() {
        super.viewDidLoad()
                                title = "全部课程"
                                titleItems.append(TitleItem(title: "会员专区"))
                                titleItems.append(TitleItem(title: "免费专区"))
                                titleItems.append(TitleItem(title: "付费专区"))
                                titleItems.append(TitleItem(title: "线下课程"))
                                titleItems.append(TitleItem(title: "水晶疗愈"))
                                viewModel.cateId.accept(titleItems[selectIndex].id)
                                viewModel.configure(collectionView)
                                viewModel.beginRefresh()
    }
                override func setUI() {
@@ -49,14 +47,20 @@
                                collectionView.delegate = self
                                collectionView.dataSource = self
                                collectionView.showsVerticalScrollIndicator = false
                                collectionView.register(UINib(nibName: "HomeRelaxBanner_2_CCell", bundle: nil), forCellWithReuseIdentifier: "_HomeRelaxBanner_2_CCell")
                                collectionView.contentInset = UIEdgeInsets(top: 34, left: 21, bottom: 0, right: 21)
                                collectionView.register(UINib(nibName: "HomeRelaxBanner_2_1_CCell", bundle: nil), forCellWithReuseIdentifier: "_HomeRelaxBanner_2_1_CCell")
                                collectionView.contentInset = UIEdgeInsets(top: 0, left: 21, bottom: 0, right: 21)
                                view.addSubview(collectionView)
                                collectionView.snp.makeConstraints { make in
                                                make.left.equalTo(tableView.snp.right)
                                                make.right.equalToSuperview()
                                                make.top.bottom.equalTo(tableView)
                                                make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(18)
                                                make.bottom.equalTo(tableView)
                                }
                }
                func setTitleItem(_ items:[TitleItem],defaultSelectIndex:Int = 0){
                                self.selectIndex = defaultSelectIndex
                                self.titleItems = items
                }
}
@@ -64,6 +68,8 @@
                func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                                selectIndex = indexPath.row
                                viewModel.cateId.accept(titleItems[selectIndex].id)
                                viewModel.beginRefresh()
                                tableView.reloadData()
                }
@@ -88,23 +94,21 @@
extension CourseMenuVC:UICollectionViewDelegate & UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                if indexPath.row == 0{
                                                let vc = CourseDetialVC(courseSytle: .style1)
                                let model = viewModel.dataSource.value!.list[indexPath.row]
                                let vc = CourseDetialVC(courseId: model.id)
                                                push(vc: vc)
                                }else{
                                                let vc = CourseDetialVC(courseSytle: .style2)
                                                push(vc: vc)
                                }
                }
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_CCell", for: indexPath) as! HomeRelaxBanner_2_CCell
                                let model = viewModel.dataSource.value!.list[indexPath.row]
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_1_CCell", for: indexPath) as! HomeRelaxBanner_2_1_CCell
                                cell.backgroundColor = .jq_randomColor
                                cell.setCourseModel(model)
                                return cell
                }
                func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return 2
                                return viewModel.dataSource.value?.list.count ?? 0
                }
}
XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift
@@ -7,12 +7,23 @@
import UIKit
import JQTools
import RxRelay
import RxSwift
class CourseVCOfficalViewModel:RefreshInnerModel<CourseModel>{
                var cateId = BehaviorRelay<Int?>(value: nil)
                override func api() -> (Observable<BaseResponse<BaseResponseList<CourseModel>>>)? {
                                return Services.getCoursePageList(page: page)
                }
}
class CourseVCOfficalCommentVC: BaseVC {
                private var collectionView:UICollectionView!
                private var titleItems = [TitleItem]()
                private var subTitleItems = [TitleItem]()
                private var bannerModels = [CommonBannerModel]()
                private var viewModel = CourseVCOfficalViewModel()
                override func viewDidLoad() {
                                super.viewDidLoad()
@@ -20,14 +31,22 @@
                                titleItems.append(TitleItem(title: "新手冥想指南", subTitle: "Meditation guide"))
                                titleItems.append(TitleItem(title: "推荐课程", subTitle: "与内心的宁静与喜悦入睡"))
                                subTitleItems.append(TitleItem(title: "会员专区",coverImage: "course_1"))
                                subTitleItems.append(TitleItem(title: "免费专区",coverImage: "course_2"))
                                subTitleItems.append(TitleItem(title: "付费专区",coverImage: "course_3"))
                                subTitleItems.append(TitleItem(title: "线下课程",coverImage: "course_4"))
                                subTitleItems.append(TitleItem(title: "疗愈",coverImage: "course_5"))
                                subTitleItems.append(TitleItem(title: "关系",coverImage: "course_6"))
                                subTitleItems.append(TitleItem(title: "财富",coverImage: "course_7"))
                                subTitleItems.append(TitleItem(title: "分类",coverImage: "course_8"))
                                Services.getCourseCategory().subscribe(onNext: {data in
                                                for v in data.data ?? []{
                                                                self.subTitleItems.append(TitleItem(id:v.id,title: v.name,coverImage: v.imageUrl))
                                                }
                                                self.collectionView.reloadData()
                                }).disposed(by: disposeBag)
                                Services.getCourseBannerList().subscribe(onNext: {data in
                                                for (index,v) in (data.data ?? []).enumerated(){
                                                                self.bannerModels.append(CommonBannerModel(index: index, id: v.id, name: v.name, resource:v.imageUrl, mediaType: .imageUrl))
                                                }
                                                self.collectionView.reloadData()
                                }).disposed(by: disposeBag)
                                viewModel.configure(collectionView)
                                viewModel.beginRefresh()
                }
@@ -57,7 +76,8 @@
extension CourseVCOfficalCommentVC:UICollectionViewDelegate & UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let vc = CourseDetialVC(courseSytle: .style1)
                                let model = viewModel.dataSource.value!.list[indexPath.row]
                                let vc = CourseDetialVC(courseId: model.id)
                                JQ_currentViewController().jq_push(vc: vc)
                }
@@ -67,6 +87,7 @@
                                                let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as! HomeHeaderView_1
                                                let m = titleItems[indexPath.section]
                                                headerView.setTitle(m.title, subTitle: m.subTitle)
                                                headerView.btn_more.isHidden = true
                                                return headerView
                                }
                                return UICollectionReusableView()
@@ -77,16 +98,19 @@
                                if indexPath.section == 0{
                                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_CourseOfficalCommendTopCCell", for: indexPath) as! CourseOfficalCommendTopCCell
                                                cell.setTitles(subTitleItems)
                                                cell.setBanners(bannerModels)
                                                cell.clickAtClouse { index in
                                                                let vc = CourseMenuVC()
                                                                vc.setTitleItem(self.subTitleItems,defaultSelectIndex: index)
                                                                vc.hidesBottomBarWhenPushed = true
                                                                JQ_currentNavigationController().pushViewController(vc, animated: true)
                                                }
                                                return cell
                                }
                                let model = viewModel.dataSource.value!.list[indexPath.row]
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_CCell", for: indexPath) as! HomeRelaxBanner_2_CCell
                                cell.backgroundColor = .jq_randomColor
                                cell.setCourseModel(model)
                                return cell
                }
@@ -94,7 +118,7 @@
                                if section == 0{
                                                return 1
                                }
                                return 20
                                return viewModel.dataSource.value?.list.count ?? 0
                }
                func numberOfSections(in collectionView: UICollectionView) -> Int {
XQMuse/Root/Course/View/CourseDetailHeaderView.swift
@@ -10,8 +10,19 @@
class CourseDetailHeaderView: UIView,JQNibView{
                
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_teacher: UILabel!
                @IBOutlet weak var label_studyNum: UILabel!
                @IBOutlet weak var image_cover: UIImageView!
                @IBOutlet weak var icon: UIImageView!
                override func awakeFromNib() {
                                super.awakeFromNib()
                }
                func setCourseModel(_ model:CourseModel){
                                label_title.text = model.courseTitle
                                label_teacher.text = "导师 \(model.tutor)"
                                label_studyNum.text = "\(model.count)人已加入学习"
                                image_cover.sd_setImage(with: URL(string: model.coverUrl))
                }
}
XQMuse/Root/Course/View/CourseDetailHeaderView.xib
@@ -35,15 +35,15 @@
                            <color key="textColor" red="0.27058823529411763" green="0.27058823529411763" blue="0.27058823529411763" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <nil key="highlightedColor"/>
                        </label>
                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_use_small" translatesAutoresizingMaskIntoConstraints="NO" id="QZb-OD-zkm">
                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_user_1" translatesAutoresizingMaskIntoConstraints="NO" id="QZb-OD-zkm">
                            <rect key="frame" x="20.666666666666668" y="63.333333333333364" width="10" height="10.666666666666664"/>
                            <constraints>
                                <constraint firstAttribute="width" constant="10" id="Oim-LL-682"/>
                                <constraint firstAttribute="height" constant="10.5" id="UW0-AR-Xhg"/>
                            </constraints>
                        </imageView>
                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="101人已加入学习" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0I9-CV-ojJ">
                            <rect key="frame" x="35.666666666666664" y="62.666666666666686" width="78.666666666666686" height="12"/>
                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0人已加入学习" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0I9-CV-ojJ">
                            <rect key="frame" x="35.666666666666657" y="62.666666666666686" width="69" height="12"/>
                            <fontDescription key="fontDescription" type="system" pointSize="10"/>
                            <color key="textColor" red="0.80392156862745101" green="0.80392156862745101" blue="0.80392156862745101" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <nil key="highlightedColor"/>
@@ -76,13 +76,17 @@
            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
            <connections>
                <outlet property="icon" destination="QZb-OD-zkm" id="C8w-ga-BSc"/>
                <outlet property="image_cover" destination="3FR-3L-eGU" id="zat-PK-Mtx"/>
                <outlet property="label_studyNum" destination="0I9-CV-ojJ" id="Xu3-ID-OsO"/>
                <outlet property="label_teacher" destination="DbG-SW-sik" id="BfM-77-ZSS"/>
                <outlet property="label_title" destination="CgZ-Jh-uGm" id="zt0-Fw-MFu"/>
            </connections>
            <point key="canvasLocation" x="59.541984732824424" y="-98.239436619718319"/>
        </view>
    </objects>
    <resources>
        <image name="demo_bg" width="621" height="1064"/>
        <image name="icon_use_small" width="10" height="10.666666984558105"/>
        <image name="icon_user_1" width="10" height="10.666666984558105"/>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
XQMuse/Root/Course/View/CourseSendGiftView.swift
@@ -15,6 +15,8 @@
                @IBOutlet weak var label_price: UILabel!
                @IBOutlet weak var cons_bottom: NSLayoutConstraint!
                private var price:Double = 0
                private var clouse:(()->Void)?
                override func awakeFromNib() {
@@ -24,8 +26,9 @@
                                layoutIfNeeded()
                }
                static func show(_ clouse:@escaping()->Void){
                static func show(price:Double,clouse:@escaping()->Void){
                                let view = CourseSendGiftView.jq_loadNibView()
                                view.label_price.text = "¥\(price.jq_formatFloat)"
                                sceneDelegate?.window?.addSubview(view)
                                view.clouse = clouse
                                view.cons_bottom.constant = 0
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift
@@ -11,6 +11,11 @@
class HomeRelaxBanner_2_1_CCell: UICollectionViewCell {
                @IBOutlet weak var view_text_bg: UIView!
                @IBOutlet weak var img_cover: UIImageView!
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_subTitle: UILabel!
                @IBOutlet weak var label_num: UILabel!
                override func awakeFromNib() {
                                super.awakeFromNib()
                                // Initialization code
@@ -29,5 +34,13 @@
                                visualEffectView.layer.masksToBounds = true
                }
                func setCourseModel(_ model:CourseModel){
                                img_cover.sd_setImage(with: URL(string: model.coverUrl))
                                label_title.text = model.courseTitle
                                label_subTitle.text = model.briefIntroduction
                                label_num.text = "\(model.count)"
//                                img_vip.isHidden = model.chargeType != .vipFree
                }
}
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib
@@ -24,16 +24,16 @@
                        <rect key="frame" x="0.0" y="146" width="160" height="50"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6md-5M-Pce">
                                <rect key="frame" x="20" y="5.9999999999999991" width="13" height="10.666666666666664"/>
                                <rect key="frame" x="20" y="6" width="130" height="20"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="10.57" id="b4q-6z-Gno"/>
                                    <constraint firstAttribute="height" constant="20" id="b4q-6z-Gno"/>
                                </constraints>
                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="--" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EeQ-hi-VEz">
                                <rect key="frame" x="20" y="22" width="89" height="10.666666666666664"/>
                                <rect key="frame" x="20" y="31.666666666666654" width="89" height="10.333333333333332"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="10.57" id="ma3-Tn-T3O"/>
                                </constraints>
@@ -41,29 +41,31 @@
                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_use_small" translatesAutoresizingMaskIntoConstraints="NO" id="Y7f-aB-0R5">
                                <rect key="frame" x="119" y="22" width="10" height="10.666666666666664"/>
                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_use_small_s" translatesAutoresizingMaskIntoConstraints="NO" id="Y7f-aB-0R5">
                                <rect key="frame" x="119" y="32.333333333333343" width="9" height="9"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="10" id="3we-wk-eag"/>
                                    <constraint firstAttribute="height" constant="10.5" id="T4v-eM-jjx"/>
                                    <constraint firstAttribute="width" constant="9" id="3we-wk-eag"/>
                                    <constraint firstAttribute="height" constant="9" id="T4v-eM-jjx"/>
                                </constraints>
                            </imageView>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="1000" verticalHuggingPriority="251" text="0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wxc-EY-qwU">
                                <rect key="frame" x="131" y="22.666666666666657" width="6" height="9.6666666666666643"/>
                                <rect key="frame" x="130" y="32" width="28" height="9.6666666666666643"/>
                                <fontDescription key="fontDescription" type="system" pointSize="8"/>
                                <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="Wxc-EY-qwU" secondAttribute="trailing" constant="23" id="1lo-tj-hSD"/>
                            <constraint firstItem="Y7f-aB-0R5" firstAttribute="leading" secondItem="EeQ-hi-VEz" secondAttribute="trailing" constant="10" id="6Ta-sO-wtF"/>
                            <constraint firstItem="Wxc-EY-qwU" firstAttribute="leading" secondItem="Y7f-aB-0R5" secondAttribute="trailing" constant="2" id="HlL-mC-Zj3"/>
                            <constraint firstItem="6md-5M-Pce" firstAttribute="top" secondItem="nyj-tV-0t4" secondAttribute="top" constant="6" id="KXL-JH-Ymd"/>
                            <constraint firstAttribute="trailing" secondItem="Y7f-aB-0R5" secondAttribute="trailing" constant="32" id="M2f-Kb-UTr"/>
                            <constraint firstAttribute="trailing" secondItem="6md-5M-Pce" secondAttribute="trailing" constant="10" id="OYv-3V-kDP"/>
                            <constraint firstItem="Wxc-EY-qwU" firstAttribute="centerY" secondItem="EeQ-hi-VEz" secondAttribute="centerY" id="Pau-3T-hlR"/>
                            <constraint firstItem="Y7f-aB-0R5" firstAttribute="centerY" secondItem="EeQ-hi-VEz" secondAttribute="centerY" id="Te3-Aw-qID"/>
                            <constraint firstItem="EeQ-hi-VEz" firstAttribute="top" secondItem="6md-5M-Pce" secondAttribute="bottom" constant="5.5" id="TwN-Dx-nby"/>
                            <constraint firstItem="6md-5M-Pce" firstAttribute="leading" secondItem="nyj-tV-0t4" secondAttribute="leading" constant="20" id="UZ1-SQ-4vN"/>
                            <constraint firstAttribute="trailing" secondItem="Wxc-EY-qwU" secondAttribute="trailing" constant="2" id="Ys5-cn-zeq"/>
                            <constraint firstItem="Wxc-EY-qwU" firstAttribute="leading" secondItem="Y7f-aB-0R5" secondAttribute="trailing" constant="2" id="agG-lh-R3G"/>
                            <constraint firstItem="EeQ-hi-VEz" firstAttribute="leading" secondItem="6md-5M-Pce" secondAttribute="leading" id="qrg-fN-GGz"/>
                            <constraint firstAttribute="height" constant="50" id="tml-hU-Ojf"/>
                        </constraints>
@@ -87,6 +89,10 @@
            </constraints>
            <size key="customSize" width="160" height="196"/>
            <connections>
                <outlet property="img_cover" destination="VwD-36-ent" id="93Z-v8-bjM"/>
                <outlet property="label_num" destination="Wxc-EY-qwU" id="zxI-Y4-tTv"/>
                <outlet property="label_subTitle" destination="EeQ-hi-VEz" id="U39-7s-GGD"/>
                <outlet property="label_title" destination="6md-5M-Pce" id="j50-e3-otB"/>
                <outlet property="view_text_bg" destination="nyj-tV-0t4" id="Lef-w5-fi6"/>
            </connections>
            <point key="canvasLocation" x="164.8854961832061" y="71.83098591549296"/>
@@ -94,6 +100,6 @@
    </objects>
    <resources>
        <image name="icon_freee" width="50" height="18"/>
        <image name="icon_use_small" width="10" height="10.666666984558105"/>
        <image name="icon_use_small_s" width="9" height="9"/>
    </resources>
</document>
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift
@@ -11,12 +11,13 @@
class HomeRelaxBanner_2_CCell: UICollectionViewCell {
                @IBOutlet weak var view_text_bg: UIView!
                @IBOutlet weak var img_tipPeople: UIImageView!
                @IBOutlet weak var img_vip: UIImageView!
                @IBOutlet weak var img_cover: UIImageView!
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_subTitle: UILabel!
                @IBOutlet weak var label_num: UILabel!
                @IBOutlet weak var cons_maxSubTitle: NSLayoutConstraint!
                private var meditationModel:MeditationModel?
                override func awakeFromNib() {
@@ -43,4 +44,11 @@
                                label_num.text = "\(model.realLearnedNum)"
                                img_vip.isHidden = model.chargeType != .vipFree
                }
                func setCourseModel(_ model:CourseModel){
                                img_cover.sd_setImage(with: URL(string: model.coverUrl))
                                label_title.text = model.courseTitle
                                label_subTitle.text = model.briefIntroduction
                                label_num.text = "\(model.count)"
                }
}
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib
@@ -23,16 +23,13 @@
                        <rect key="frame" x="0.0" y="236" width="178" height="65"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="byc-Ar-sJL">
                                <rect key="frame" x="20" y="17" width="148" height="10.666666666666664"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="10.57" id="ZW4-0S-dSX"/>
                                </constraints>
                                <rect key="frame" x="20" y="17" width="148" height="12"/>
                                <fontDescription key="fontDescription" type="system" pointSize="10"/>
                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="z5u-My-91l">
                                <rect key="frame" x="20" y="33" width="10.666666666666664" height="10.666666666666664"/>
                                <rect key="frame" x="20" y="34.666666666666686" width="10.666666666666664" height="10.333333333333336"/>
                                <constraints>
                                    <constraint firstAttribute="width" relation="lessThanOrEqual" constant="100" id="Fam-ne-FM1"/>
                                    <constraint firstAttribute="height" constant="10.57" id="epJ-Xi-ukn"/>
@@ -42,14 +39,10 @@
                                <nil key="highlightedColor"/>
                            </label>
                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_use_small" translatesAutoresizingMaskIntoConstraints="NO" id="hE1-AV-t8f">
                                <rect key="frame" x="136" y="33" width="10" height="10.666666666666664"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="10.5" id="429-dC-RSu"/>
                                    <constraint firstAttribute="width" constant="10" id="AvO-zD-TXx"/>
                                </constraints>
                                <rect key="frame" x="136" y="34.666666666666686" width="10" height="10.333333333333336"/>
                            </imageView>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JaY-19-IAL">
                                <rect key="frame" x="148" y="31.666666666666682" width="7" height="13.333333333333332"/>
                                <rect key="frame" x="148" y="33" width="7" height="13.333333333333336"/>
                                <fontDescription key="fontDescription" type="system" pointSize="11"/>
                                <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                <nil key="highlightedColor"/>
@@ -86,7 +79,9 @@
            </constraints>
            <size key="customSize" width="178" height="301"/>
            <connections>
                <outlet property="cons_maxSubTitle" destination="Fam-ne-FM1" id="L5X-GP-uev"/>
                <outlet property="img_cover" destination="cCC-0f-GSV" id="85x-ue-edy"/>
                <outlet property="img_tipPeople" destination="hE1-AV-t8f" id="ObN-5h-jnl"/>
                <outlet property="img_vip" destination="yBF-fO-fwz" id="icq-m9-dx3"/>
                <outlet property="label_num" destination="JaY-19-IAL" id="2RU-X7-0wb"/>
                <outlet property="label_subTitle" destination="z5u-My-91l" id="j4L-bl-DhS"/>
XQMuse/Root/Home/HomeVC.swift
@@ -13,6 +13,7 @@
let SetBGMSuccess_Noti = Notification.Name.init("SetBGMSuccess_Noti")
struct TitleItem{
                var id = 0
                var title = ""
                var subTitle = ""
                var hasMore:Bool = false
@@ -43,7 +44,7 @@
                                if let setting = UserDefaultSettingViewModel.getSetting(){
                                                if let audioFile = setting.bgm?.audioFile{
                                                                AudioPlayer.getSharedInstance().playBGMAt(audioFile)
                                                                AudioPlayer.getSharedInstance().playSceneAt(audioFile)
                                                }
                                }
XQMuse/Root/Home/VC/BackgroundVoiceVC.swift
@@ -23,12 +23,12 @@
                override func viewDidDisappear(_ animated: Bool) {
                                super.viewDidDisappear(animated)
                                audioPlayer.playBGM()
                                audioPlayer.playScene()
                }
                override func viewDidAppear(_ animated: Bool) {
                                super.viewDidAppear(animated)
                                audioPlayer.pauseBGM()
                                audioPlayer.pauseScene()
                }
                override func viewDidLoad() {
@@ -94,7 +94,7 @@
                                                settingModel?.bgm = items[index.row]
                                                settingModel?.volume = Double(slider_voice.value)
                                                UserDefaultSettingViewModel.saveSetting(settingModel!)
                                                audioPlayer.playBGMAt(items[index.row].audioFile)
                                                audioPlayer.playSceneAt(items[index.row].audioFile)
                                                alertSuccess(msg: "设置成功")
                                                NotificationCenter.default.post(name: SetBGMSuccess_Noti, object: items[index.row])
                                }
XQMuse/Root/Home/VC/HomeItemDetailVC.swift
@@ -8,7 +8,7 @@
import UIKit
import JQTools
class HomeItemDetailVC: BaseVC {
class HomeItemDetailVC: BaseVC,PayMusicDelegate{
                @IBOutlet weak var slider_voice: UISlider!
                @IBOutlet weak var view_function: UIView!
@@ -22,9 +22,11 @@
                @IBOutlet weak var view_playState: UIView!
                @IBOutlet weak var label_playState: UILabel!
                @IBOutlet weak var btn_playMode: UIButton!
                @IBOutlet weak var label_currentTime: UILabel!
                @IBOutlet weak var label_totalTime: UILabel!
                
                private var collect_bitem:UIBarButtonItem!
                private var audioPlayer:AudioPlayer = AudioPlayer.getSharedInstance()
                private var id:Int!
                private var settingViewModel = UserDefaultSettingViewModel.getSetting()
                private var model:MeditationModel?{
@@ -52,16 +54,20 @@
                                btn_playMode.isSelected = settingViewModel?.playModel == .singleLoop
                                if AudioPlayer.getSharedInstance().times.value != nil{
                                if audioPlayer.times.value != nil{
                                                startMiniRunloop()
                                }else{
                                                endMiniRunloop()
                                }
                                Services.getMeditationDetail(id: id).subscribe(onNext: {data in
                                Services.getMeditationDetail(id: id).subscribe(onNext: {[unowned self] data in
                                                self.model = data.data
                                                self.collect_bitem.image = data.data?.favorite == .yes ? UIImage(named: "btn_collect_s"):UIImage(named: "btn_collect_1")
                                                self.collect_bitem.tintColor = data.data?.favorite == .yes ? UIColor(hexString: "fe5b60"):.white
                                                if audioPlayer.meditationModel?.id == data.data?.id{
                                                                audioPlayer.delegate = self
                                                }
                                }).disposed(by: disposeBag)
                }
@@ -104,7 +110,7 @@
                }
                override func setRx() {
                                AudioPlayer.getSharedInstance().times.subscribe {[weak self] t in
                                audioPlayer.times.subscribe {[weak self] t in
                                                guard let weakSelf = self else { return }
                                                guard let time = t,time > 0 else {weakSelf.endMiniRunloop();return}
                                                let turple = Date.jq_formateToTime_tuple(time)
@@ -122,7 +128,6 @@
                                super.viewWillAppear(animated)
                                (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal)
                }
                private func startMiniRunloop(){
                                // 创建旋转动画
@@ -142,12 +147,20 @@
                @IBAction func playAction(_ sender: UIButton) {
//                                showHUD("准备播放")
                                if var m = model{
                                                m.backgroundUrl = "https://downsc.chinaz.net/Files/DownLoad/sound1/201906/11582.mp3,https://www.cambridgeenglish.org/images/153149-movers-sample-listening-test-vol2.mp3"
                                                m.tutorAudioUrl = "https://downsc.chinaz.net/files/download/sound1/201206/1638.mp3"
                                                audioPlayer.playBGMAt(firstPlayIndex: 0, model: m, delegate: self)
                                }
                }
                @IBAction func timeAction(_ sender: UIButton) {
                                CountdownChooseListView.show {[weak self] times in
                                                guard let weakSelf = self else { return }
                                                AudioPlayer.getSharedInstance().setTimer(times: times * 60)
                                                weakSelf.audioPlayer.setTimer(times: times * 60)
                                                //                                                if times <= 0{
                                                //                                                                weakSelf.timer = nil
@@ -178,11 +191,6 @@
                                vc.modalPresentationStyle = .custom
                                present(vc, animated: true)
                }
                @IBAction func beLikeAction(_ sender: UIButton) {
                }
                @IBAction func playWayAction(_ sender: UIButton) {
                                UIView.animate(withDuration: 0.5) {
@@ -231,4 +239,36 @@
                override var preferredStatusBarStyle: UIStatusBarStyle{
                                return .lightContent
                }
                func playState(_ state:PlayMusicState){
                                print("music:当前状态:\(state)")
                                guard audioPlayer.meditationModel?.id == model?.id else {return}
                                switch state {
                                                case .playing:
                                                                PayMusicVC.show(model: model!)
                                                                if btn_play.isHidden == false {btn_play.isHidden = true}
                                                                hiddenHUD()
                                                case .paurse:
                                                                btn_play.isHidden = false
                                                case .end:break
                                                case .next:break
                                }
                }
                func playListen(currentInterval:TimeInterval,totalInterval:TimeInterval){
                                guard audioPlayer.meditationModel?.id == model?.id else {return}
                                guard !totalInterval.isNaN else {return}
                                guard !currentInterval.isNaN else {return}
                                let v = currentInterval / totalInterval * 100
                                print("music:当前时间:\(currentInterval) ---- \(totalInterval) -- \(v)%")
                                self.slider_voice.value = Float(v)
                                let current = Date.jq_formateToTime_tuple(Int(currentInterval))
                                label_currentTime.text = String(format: "%02ld:%02ld", current.hour * 60 + current.minute,current.second)
                                let total = Date.jq_formateToTime_tuple(Int(totalInterval))
                                label_totalTime.text = String(format: "%02ld:%02ld", total.hour * 60 + total.minute,total.second)
                }
}
XQMuse/Root/Home/VC/HomeItemDetailVC.xib
@@ -15,9 +15,11 @@
                <outlet property="img_countdonw" destination="gxd-0O-eUD" id="rzB-8i-qOk"/>
                <outlet property="label_commentNum" destination="IkS-qR-riK" id="9zO-Xt-6XC"/>
                <outlet property="label_countdown" destination="akf-L4-aPE" id="goO-Gd-TLu"/>
                <outlet property="label_currentTime" destination="zwK-yd-ILF" id="3gm-3s-4eF"/>
                <outlet property="label_playState" destination="4zW-Bq-V7P" id="vSm-Rr-gtL"/>
                <outlet property="label_subtitle" destination="xYv-9B-0fk" id="6WT-eV-ZES"/>
                <outlet property="label_title" destination="0CQ-Qn-OOa" id="3vY-s9-wNj"/>
                <outlet property="label_totalTime" destination="rML-fW-BqA" id="ibD-S5-fds"/>
                <outlet property="slider_voice" destination="P8W-2A-zOo" id="hiF-Hr-YQ0"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="view_coutdown" destination="V28-7K-Bfm" id="pqU-2r-w5U"/>
XQMuse/Root/Home/VC/SearchContentVC.swift
@@ -92,7 +92,8 @@
extension SearchContentVC:UICollectionViewDelegate & UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let vc = CourseDetialVC(courseSytle: .style1)
                                let m = viewModel.dataSource.value!.list[indexPath.row]
                                let vc = CourseDetialVC(courseId: m.id)
                                JQ_currentViewController().jq_push(vc: vc)
                }
XQMuse/Root/Network/Models.swift
@@ -127,5 +127,84 @@
                var replyTime: String = ""
}
struct PavilionDetailModel:HandyJSON{
                var address: String = ""
                var addressDetail: String = ""
                var briefIntroduction: String = ""
                var businessHours: String = ""
                var contactNumber: String = ""
                var coverUrl: String = ""
                var createBy: String = ""
                var createTime: String = ""
                var delFlag: Int = 0
                var detailBannerUrl: String = ""
                var distance: Double = 0
                var hallName: String = ""
                var id: Int = 0
                var latitude: Int = 0
                var listingStatus: Int = 0
                var longitude: Int = 0
                var sortNum: Int = 0
                var updateBy: String = ""
                var updateTime: String = ""
}
struct CategoryModel:HandyJSON{
                var id = 0
                var imageUrl = ""
                var name = ""
}
struct CourseModel:HandyJSON{
                var address:String = ""
                var addressDetail:String = ""
                var briefIntroduction:String = ""
                var cateId: Int = 0
                var chargeType: ChargeType = .free
                var count: Int = 0
                var courseTitle:String = ""
                var courseType: DeliverStudyType = .online
                var coverUrl:String = ""
                var description:String = ""
                var detailUrl:String = ""
                var generalPrice: Double = 0
                var headers = [String]()
                var id: Int = 0
                var iosPrice: Int = 0
                var isBuy: Int = 0
                var isVip: Int = 0
                var latitude: Int = 0
                var listingStatus: Int = 0
                var longitude: Int = 0
                var recommend: Int = 0
                var sortNum: Int = 0
                var tutor:String = ""
                var wxQrCode:String = ""
                var list2 = [CourseModel]()
                var list = [CourseItemModel]()
}
struct CourseItemModel:HandyJSON{
                var chapterTitle:String = ""
                var courseId: Int = 0
                var createBy:String = ""
                var createTime:String = ""
                var delFlag: Int = 0
                var duration: Int = 0
                var id: Int = 0
                var isOver: ConditionType = .yes
                var minuteLook: Int = 0
                var realLearnedNum: Int = 0
                var secondLook: Int = 0
                var sortNum: Int = 0
                var updateBy:String = ""
                var updateTime:String = ""
                var videoUrl:String = ""
                var virtualLearnedNum: Int = 0
}
XQMuse/Root/Network/Services.swift
@@ -10,6 +10,7 @@
import RxSwift
import Alamofire
import JQTools
import CoreLocation
#if DEBUG
let All_Url = "https://mock.apipost.net/mock/31b303c60464000"
@@ -188,7 +189,7 @@
                                return NetworkRequest.request(params: params, method: .get, progress: false)
                }
                ///
                /// 搜索
                class func search(text:String,page:Int,pageSize:Int = 20)->Observable<BaseResponse<BaseResponseList<MeditationModel>>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/meditation/client/meditation/home/getHotWordList")
@@ -200,6 +201,71 @@
                }
}
/// 课程
extension Services{
                //课程分类
                class func getCourseCategory()->Observable<BaseResponse<[CategoryModel]>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/course/client/course/course/getCourseCategoryList")
                                                .append(key: "apipost_id", value: "2d2eb9d1f993bb")
                                return NetworkRequest.request(params: params, method: .get, progress: false)
                }
                /// 获取banner
                class func getCourseBannerList()->Observable<BaseResponse<[CategoryModel]>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/course/client/course/course/getBannerList")
                                                .append(key: "apipost_id", value: "2d2eb9d1f993ba")
                                return NetworkRequest.request(params: params, method: .get, progress: false)
                }
                /// 获取课程列表
                class func getCoursePageList(page:Int,pageSize:Int = 20,cateId:String? = nil,courseTitle:String? = nil)->Observable<BaseResponse<BaseResponseList<CourseModel>>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/course/client/course/course/getCoursePageList")
                                                .append(key: "pageCurr", value: page)
                                                .append(key: "pageSize", value: pageSize)
                                                .append(key: "cateId", value: cateId)
                                                .append(key: "courseTitle", value: courseTitle)
                                                .append(key: "apipost_id", value: "2d6f7f04f99813")
                                return NetworkRequest.request(params: params, method: .post, progress: false)
                }
                class func getCourseDetail(courseId:Int)->Observable<BaseResponse<CourseModel>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/course/client/course/course/getPayCourseInfoById")
                                                .append(key: "id", value: courseId)
                                                .append(key: "apipost_id", value: "2d2eb9d23993bd")
                                return NetworkRequest.request(params: params, method: .post, progress: true)
                }
}
/// 疗愈馆
extension Services{
                /// 疗愈馆
                class func getPavlilonPage(location:CLLocationCoordinate2D?,search:String? = nil,page:Int,pageSize:Int = 20)->Observable<BaseResponse<BaseResponseList<PavilionDetailModel>>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/meditation/client/meditation/meditation/getMeditationPage")
                                                .append(key: "name", value: search)
                                                .append(key: "lat", value: location?.latitude)
                                                .append(key: "lon", value: location?.longitude)
                                                .append(key: "pageCurr", value: page)
                                                .append(key: "pageSize", value: pageSize)
                                                .append(key: "apipost_id", value: "2d2eb5e7f991ab")
                                return NetworkRequest.request(params: params, method: .get, progress: false)
                }
                /// 疗愈馆
                class func getPavlilonDetail(id:Int)->Observable<BaseResponse<PavilionDetailModel>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/meditation/client/meditation/meditation/getMeditationInfo")
                                                .append(key: "id", value: id)
                                                .append(key: "apipost_id", value: "2d2eb5e7b991aa")
                                return NetworkRequest.request(params: params, method: .get, progress: true)
                }
}
extension Services{
                /// 获取协议
                class func agreementBy(_ type:AgreementType)->Observable<BaseResponse<HtmlModel>>{
XQMuse/Root/Other/View/CommonBannerView.swift
New file
@@ -0,0 +1,209 @@
//
//  CommonBannerView.swift
//  WanPai
//
//  Created by 无故事王国 on 2023/6/30.
//
import UIKit
import SDWebImage
struct CommonBannerModel {
                var index = 0 //自定义索引
                var id:Int? //ID
                var name:String? //名称
                var resource:String? //数据源:URL等
                var mediaType:CommonBannerView.MediaType?
}
class CommonBannerView: UIView, UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
                enum MediaType {
                                case videoUrl,imageUrl,imageLocal,videoLocal
                }
                private(set) lazy var collectionView:UICollectionView = {
                                var layout = UICollectionViewFlowLayout()
                                layout.minimumLineSpacing = 0
                                layout.minimumInteritemSpacing = 0
                                layout.scrollDirection = .horizontal
                                layout.sectionInset = .zero
                                layout.headerReferenceSize = .zero
                                layout.footerReferenceSize = .zero
                                layout.itemSize = CGSize(width: self.width, height: self.height)
                                let collectionView = UICollectionView(frame:CGRect(x: 0, y: 0, width: self.width, height: self.height), collectionViewLayout: layout)
                                collectionView.delegate = self
                                collectionView.dataSource = self
                                collectionView.isPagingEnabled = true
                                collectionView.showsHorizontalScrollIndicator = false
                                collectionView.register(CommonBannerViewCell.self, forCellWithReuseIdentifier: "BannerView")
                                collectionView.decelerationRate = .normal
                                collectionView.contentInsetAdjustmentBehavior = .never
                                collectionView.backgroundColor = .white
                                collectionView.bounces = false
                                return collectionView
                }()
                private lazy var pageControl:UIPageControl = {
                                let control = UIPageControl()
                                control.currentPageIndicatorTintColor = .white
                                control.pageIndicatorTintColor = .gray.withAlphaComponent(0.6)
                                return control
                }()
                private var timer:Timer?
                private var items = [CommonBannerModel]()
                private var selectClouse:((CommonBannerModel)->Void)?
                private var autoRoll:Bool = true
                private var currentPage:Int = 0
                private var timeInterval:Int = 5
                override func awakeFromNib() {
                                super.awakeFromNib()
                                setUI()
                }
                public func setItems(items:[CommonBannerModel],autoRoll:Bool = true,selectClouse:((CommonBannerModel)->Void)? = nil){
                                self.items = items
                                if items.count > 1{
                                                self.items.append(items.first!)
                                }
                                self.autoRoll = autoRoll
                                self.selectClouse = selectClouse
                                if items.count <= 1{self.autoRoll = false}
                                setUI()
                                collectionView.reloadData()
                                if self.autoRoll{
                                                DispatchQueue.main.asyncAfter(deadline: .now()+5) {
                                                                self.startTimer()
                                                }
                                }
                }
                private func setUI(){
                                addSubview(collectionView)
                                collectionView.snp.makeConstraints { make in
                                                make.edges.equalToSuperview()
                                }
                                if items.count > 1{
                                                pageControl.numberOfPages = items.count - 1
                                                addSubview(pageControl)
                                                pageControl.snp.makeConstraints { make in
                                                                make.centerX.equalToSuperview()
                                                                make.bottom.equalToSuperview().offset(-10)
                                                                make.height.equalTo(8)
                                                }
                                }
                }
                private func startTimer(){
                                guard timer == nil else {return}
                                timer = Timer(timeInterval: TimeInterval(timeInterval), repeats: true, block: {[weak self] t in
                                                guard let weakSelf = self else { return }
                                                let page = weakSelf.collectionView.contentOffset.x / weakSelf.collectionView.width
                                                weakSelf.currentPage = Int(page + 1)
                                                if weakSelf.currentPage >= weakSelf.pageControl.numberOfPages{
                                                                weakSelf.currentPage = 0
                                                                weakSelf.collectionView.setContentOffset(.zero, animated: false)
                                                                weakSelf.pageControl.currentPage = 0
                                                }
                                                weakSelf.collectionView.setContentOffset(CGPoint(x: weakSelf.currentPage * Int(weakSelf.width), y: 0), animated: true)
                                })
                                timer?.fire()
                                RunLoop.current.add(timer!, forMode: .common)
                }
                func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return items.count
                }
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let item = items[indexPath.row]
                                selectClouse?(item)
                }
                func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
                                return CGSize(width:collectionView.bounds.size.width,height:ceil(collectionView.bounds.size.height))
                }
                func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
                                print("--开始滑动")
                                timer?.fireDate = Date.distantFuture
                }
                func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
                                let page = scrollView.contentOffset.x / scrollView.width
                                if page.int >= pageControl.numberOfPages{
                                                pageControl.currentPage = 0
                                }else{
                                                pageControl.currentPage = page.int
                                }
                                print("--结束滑动")
                                timer?.fireDate = Date.init(timeIntervalSinceNow: 3.0) //3秒后开启
                }
                func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
                                let page = scrollView.contentOffset.x / scrollView.width
                                if page.int >= pageControl.numberOfPages{
                                                pageControl.currentPage = 0
                                }else{
                                                pageControl.currentPage = page.int
                                }
                }
                func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
                                let page = scrollView.contentOffset.x / scrollView.width
                                if page.int >= pageControl.numberOfPages{
                                                pageControl.currentPage = 0
                                                collectionView.setContentOffset(.zero, animated: false)
                                }else{
                                                pageControl.currentPage = page.int
                                }
                }
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerView", for: indexPath) as! CommonBannerViewCell
                                let item = items[indexPath.row]
                                switch item.mediaType {
                                                case .imageUrl:
                                                                if let i = item.resource{
                                                                                cell.imgView.sd_setImage(with: URL(string: i))
                                                                }
                                                case .imageLocal:
                                                                if let i = item.resource{
                                                                                cell.imgView.image = UIImage(named: i)
                                                                }
                                                default:break
                                }
                                return cell
                }
}
class CommonBannerViewCell: UICollectionViewCell {
                lazy var imgView:UIImageView = {
                                let img = UIImageView()
                                img.contentMode = .scaleToFill
                                return img
                }()
                override init(frame: CGRect) {
                                super.init(frame: frame)
                                contentView.addSubview(imgView)
                                imgView.snp.makeConstraints { make in
                                                make.edges.equalToSuperview()
                                }
                }
                required init?(coder aDecoder: NSCoder) {
                                fatalError("init(coder:) has not been implemented")
                }
}
XQMuse/Root/Other/View/VideoView.swift
@@ -45,6 +45,14 @@
                                }
                }
                func updateVideoUrl(_ url:String){
                                if let Url = URL(string: url){
                                                player.url = Url
                                                player.play()
                                }
                }
                required init?(coder: NSCoder) {
                                fatalError("init(coder:) has not been implemented")
                }
XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift
@@ -6,12 +6,36 @@
//
import UIKit
import JQTools
class PavilionItemCell: UICollectionViewCell {
                var pavilionDetailModel:PavilionDetailModel?
                @IBOutlet weak var image_cover: UIImageView!
                @IBOutlet weak var view_distance: UIView!
                @IBOutlet weak var label_distance: UILabel!
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_address: UILabel!
                @IBOutlet weak var label_phone: UILabel!
    override func awakeFromNib() {
        super.awakeFromNib()
        
    }
                func setPavilionDetailModel(_ model:PavilionDetailModel){
                                image_cover.sd_setImage(with: URL(string: model.coverUrl))
                                label_title.text = model.hallName
                                view_distance.isHidden = model.distance < 0
                                if model.distance >= 1000{
                                                label_distance.text = String(format: "距你%@km", (model.distance / 1000).jq_formatFloat)
                                }else{
                                                label_distance.text = String(format: "距你%@m", model.distance.jq_formatFloat)
                                }
                                label_address.text = model.address
                                label_phone.text = model.contactNumber
                }
}
XQMuse/Root/Pavilion/CCell/PavilionItemCell.xib
@@ -4,7 +4,6 @@
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
@@ -88,7 +87,6 @@
                    </label>
                </subviews>
            </view>
            <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
            <constraints>
                <constraint firstItem="Yck-TZ-33e" firstAttribute="leading" secondItem="Mdg-Ka-kmF" secondAttribute="trailing" constant="5" id="03Z-wu-01o"/>
                <constraint firstAttribute="trailing" secondItem="xE9-lZ-06u" secondAttribute="trailing" constant="15" id="1kY-DQ-Phl"/>
@@ -109,6 +107,14 @@
                <constraint firstItem="xE9-lZ-06u" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="15" id="yl4-HG-eHc"/>
            </constraints>
            <size key="customSize" width="233" height="337"/>
            <connections>
                <outlet property="image_cover" destination="LoX-Q1-cyl" id="hAf-Zb-M0x"/>
                <outlet property="label_address" destination="Yck-TZ-33e" id="uz7-5G-xdo"/>
                <outlet property="label_distance" destination="XAi-il-afI" id="8zs-Rr-5oD"/>
                <outlet property="label_phone" destination="Ig6-yP-XKK" id="RJm-oJ-O9e"/>
                <outlet property="label_title" destination="xE9-lZ-06u" id="XJZ-8L-KE9"/>
                <outlet property="view_distance" destination="BbC-q1-W3U" id="mp1-nu-ZuA"/>
            </connections>
            <point key="canvasLocation" x="156.4885496183206" y="120.77464788732395"/>
        </collectionViewCell>
    </objects>
XQMuse/Root/Pavilion/PavilionVC.swift
@@ -7,13 +7,36 @@
import UIKit
import JQTools
import RxSwift
import RxRelay
import CoreLocation
class PavilionViewModel:RefreshInnerModel<PavilionDetailModel>{
                var location = BehaviorRelay<CLLocationCoordinate2D?>(value: nil)
                var search = BehaviorRelay<String?>(value: nil)
                override func api() -> (Observable<BaseResponse<BaseResponseList<PavilionDetailModel>>>)? {
                                return Services.getPavlilonPage(location: location.value, search: search.value, page: page)
                }
}
class PavilionVC: BaseVC {
                @IBOutlet weak var collectionView: UICollectionView!
                
                private var viewModel = PavilionViewModel()
                private var locationTool = JQ_LocationTool.instance()
    override func viewDidLoad() {
        super.viewDidLoad()
                                viewModel.configure(collectionView)
                                viewModel.beginRefresh()
                                locationTool.startLocation { location in
                                                self.viewModel.location.accept(location.coordinate)
                                                self.viewModel.beginRefresh()
                                } errorClouse: { error in
                                }
    }
                override func setUI() {
@@ -24,13 +47,14 @@
                                collectionView.backgroundColor = .clear
                                collectionView.showsVerticalScrollIndicator = false
                                collectionView.backgroundColor = .clear
                                collectionView.contentInset = UIEdgeInsets(top: 52.5, left: 28.5, bottom: 0, right: 28.5)
                                collectionView.contentInset = UIEdgeInsets(top: 0, left: 28.5, bottom: 0, right: 28.5)
                                collectionView.register(UINib(nibName: "PavilionItemCell", bundle: nil), forCellWithReuseIdentifier: "_PavilionItemCell")
                }
                @IBAction func searchAction(_ sender: Any) {
                                let searchVC = PavilionSearchVC()
                                searchVC.viewModel = viewModel
                                push(vc: searchVC)
                }
                
@@ -38,24 +62,24 @@
extension PavilionVC:UICollectionViewDelegate{
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let detailVC = PavilionDetailVC()
                                let model = viewModel.dataSource.value!.list[indexPath.row]
                                let detailVC = PavilionDetailVC(id: model.id)
                                push(vc: detailVC)
                }
}
extension PavilionVC:UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let model = viewModel.dataSource.value!.list[indexPath.row]
                                 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_PavilionItemCell", for: indexPath) as! PavilionItemCell
                                cell.backgroundColor = .jq_randomColor
                                cell.jq_cornerRadius = 16
                                cell.setPavilionDetailModel(model)
                                return cell
                }
                
                func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return 10
                                return viewModel.dataSource.value?.list.count ?? 0
                }
}
XQMuse/Root/Pavilion/PavilionVC.xib
@@ -75,7 +75,7 @@
                    </constraints>
                </view>
                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="cjl-Fc-U1i">
                    <rect key="frame" x="0.0" y="246.33333333333331" width="393" height="571.66666666666674"/>
                    <rect key="frame" x="0.0" y="298.66666666666669" width="393" height="519.33333333333326"/>
                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                    <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="b8V-X4-f6k">
                        <size key="itemSize" width="128" height="128"/>
@@ -93,7 +93,7 @@
                <constraint firstItem="X4g-Ky-JIp" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="PZU-6m-kVv"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="cjl-Fc-U1i" secondAttribute="bottom" id="TDO-TE-7xi"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="cjl-Fc-U1i" secondAttribute="trailing" id="TNn-sQ-vVu"/>
                <constraint firstItem="cjl-Fc-U1i" firstAttribute="top" secondItem="X4g-Ky-JIp" secondAttribute="bottom" constant="-107.5" id="lcy-0i-Wi9"/>
                <constraint firstItem="cjl-Fc-U1i" firstAttribute="top" secondItem="X4g-Ky-JIp" secondAttribute="bottom" constant="-55" id="lcy-0i-Wi9"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="X4g-Ky-JIp" secondAttribute="trailing" id="xr8-4F-iZy"/>
            </constraints>
            <point key="canvasLocation" x="14.503816793893129" y="19.718309859154932"/>
XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift
@@ -13,11 +13,27 @@
                @IBOutlet weak var scrollView: UIScrollView!
                @IBOutlet weak var webView: WKWebView!
                @IBOutlet weak var view_bannerBg: UIView!
                @IBOutlet weak var view_bannerBg: CommonBannerView!
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_phone: UILabel!
                @IBOutlet weak var label_address: UILabel!
                @IBOutlet weak var label_openTime: UILabel!
                @IBOutlet weak var cons_webHei: NSLayoutConstraint!
                private var id:Int!
                override func viewWillAppear(_ animated: Bool) {
                                super.viewWillAppear(animated)
                                (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal)
                }
                required init(id:Int) {
                                super.init(nibName: nil, bundle: nil)
                                self.id = id
                }
                required init?(coder: NSCoder) {
                                fatalError("init(coder:) has not been implemented")
                }
                override func viewDidLoad() {
@@ -26,6 +42,41 @@
                                scrollView.contentInsetAdjustmentBehavior = .never
                                view_bannerBg.backgroundColor = .jq_randomColor
                                webView.scrollView.isScrollEnabled = false
                                Services.getPavlilonDetail(id: id).subscribe(onNext: {data in
                                                if let m = data.data{
                                                                self.label_title.text = m.hallName
                                                                self.label_phone.text = m.contactNumber
                                                                self.label_address.text = m.addressDetail
                                                                self.label_openTime.text = "营业时间:\(m.businessHours)"
                                                                let bannerUrl = m.detailBannerUrl.components(separatedBy: ",").filter({$0.jq_isURL})
                                                                if bannerUrl.count > 0{
                                                                                var items = [CommonBannerModel]()
                                                                                for (index,v) in bannerUrl.enumerated(){
                                                                                                items.append(CommonBannerModel(index: index, id: index, name: nil, resource: v, mediaType: .imageUrl))
                                                                                }
                                                                                self.view_bannerBg.setItems(items: items)
                                                                                self.view_bannerBg.collectionView.backgroundColor = .clear
                                                                }
                                                                self.webView.loadHTMLString(m.briefIntroduction.jq_wrapHtml(), baseURL: nil)
                                                }
                                }).disposed(by: disposeBag)
    }
                override func setRx() {
                                webView.scrollView.rx.observe(CGSize.self, "contentSize").map { (size) -> CGFloat? in
                                                if let size = size{
                                                                return size.height
                                                }
                                                return nil
                                }.subscribe(onNext: { [unowned self](height) in
                                                if let height = height{
                                                                self.cons_webHei.constant = height
                                                }
                                }).disposed(by: disposeBag)
    }
XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib
@@ -10,6 +10,11 @@
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PavilionDetailVC" customModule="XQMuse" customModuleProvider="target">
            <connections>
                <outlet property="cons_webHei" destination="rWr-aC-9mh" id="YMb-gq-BbT"/>
                <outlet property="label_address" destination="28i-aJ-cBs" id="7x5-fD-eb1"/>
                <outlet property="label_openTime" destination="49g-Ie-o9H" id="hC8-Km-Oux"/>
                <outlet property="label_phone" destination="fDf-4X-hUI" id="kKe-Cn-2Bg"/>
                <outlet property="label_title" destination="ej2-gY-nmo" id="WZH-nb-YiM"/>
                <outlet property="scrollView" destination="yya-lM-LKe" id="3Mj-Nj-oHg"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="view_bannerBg" destination="bRv-iS-Gxa" id="Crd-Q4-llL"/>
@@ -27,7 +32,7 @@
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SvO-06-u0I">
                            <rect key="frame" x="0.0" y="0.0" width="393" height="758.33333333333337"/>
                            <subviews>
                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bRv-iS-Gxa">
                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bRv-iS-Gxa" customClass="CommonBannerView" customModule="XQMuse" customModuleProvider="target">
                                    <rect key="frame" x="0.0" y="0.0" width="393" height="314.33333333333331"/>
                                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                    <constraints>
XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift
@@ -7,17 +7,23 @@
import UIKit
import JQTools
import RxSwift
import RxRelay
import CoreLocation
class PavilionSearchVC: BaseVC {
                @IBOutlet weak var tf_search: UITextField!
                @IBOutlet weak var collectionView: UICollectionView!
                var viewModel:PavilionViewModel?
                override func viewDidLoad() {
        super.viewDidLoad()
                                title = "疗愈馆"
                                tf_search.delegate = self
                                tf_search.returnKeyType = .search
                                viewModel?.configure(collectionView)
    }
                override func setUI() {
@@ -32,10 +38,17 @@
                                collectionView.contentInset = UIEdgeInsets(top: 0, left: 28.5, bottom: 0, right: 28.5)
                                collectionView.register(UINib(nibName: "PavilionItemCell", bundle: nil), forCellWithReuseIdentifier: "_PavilionItemCell")
                }
                @IBAction func cancelAction(_ sender: UIButton) {
                                self.navigationController?.popViewController()
                }
}
extension PavilionSearchVC:UITextFieldDelegate{
                func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                                textField.resignFirstResponder()
                                viewModel?.search.accept(textField.text!)
                                viewModel?.beginRefresh()
                                return true
                }
}
@@ -43,21 +56,21 @@
extension PavilionSearchVC:UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let detailVC = PavilionDetailVC()
                                let model = viewModel!.dataSource.value!.list[indexPath.row]
                                let detailVC = PavilionDetailVC(id: model.id)
                                push(vc: detailVC)
                }
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let model = viewModel!.dataSource.value!.list[indexPath.row]
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_PavilionItemCell", for: indexPath) as! PavilionItemCell
                                cell.backgroundColor = .jq_randomColor
                                cell.jq_cornerRadius = 16
                                cell.setPavilionDetailModel(model)
                                return cell
                }
                func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return 10
                                return viewModel?.dataSource.value?.list.count ?? 0
                }
}
XQMuse/Root/Pavilion/VC/PavilionSearchVC.xib
@@ -61,6 +61,9 @@
                    <state key="normal" title="取消">
                        <color key="titleColor" red="0.039215686274509803" green="0.25882352941176467" blue="0.074509803921568626" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    </state>
                    <connections>
                        <action selector="cancelAction:" destination="-1" eventType="touchUpInside" id="7Y6-am-0Dj"/>
                    </connections>
                </button>
                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="GII-EZ-ldn">
                    <rect key="frame" x="0.0" y="149" width="393" height="669"/>
XQMuse/Root/PayMusicView/PayMusicVC.swift
@@ -11,12 +11,34 @@
import MediaPlayer
import RxRelay
@objc enum PlayMusicState:Int{
                case playing = 1
                case paurse = 2
                case end = 3
                case next = 4
}
@objc protocol PayMusicDelegate{
                func playState(_ state:PlayMusicState)
                @objc optional     func playListen(currentInterval:TimeInterval,totalInterval:TimeInterval)
}
class PayMusicVC: BaseVC {
                private var coverImage:UIImageView!
                private var label_name:UILabel!
                private var btn_handle:UIButton!
                private var btn_handleClose:UIButton!
                private var audioPlayer:AudioPlayer!
                private var isAniLoop:Bool = false
                private var meditationModel:MeditationModel?{
                                didSet{
                                                if let m = meditationModel{
                                                                coverImage.sd_setImage(with: URL(string: m.coverUrl),placeholderImage: UIImage(named: "login_top_bg"))
                                                                label_name.text = m.meditationTitle
                                                }
                                }
                }
                private init() {
                                super.init(nibName: nil, bundle: nil)
@@ -29,6 +51,10 @@
    override func viewDidLoad() {
        super.viewDidLoad()
                                audioPlayer = AudioPlayer.getSharedInstance()
                                let tap = UITapGestureRecognizer(target: self, action: #selector(showDetailAction))
                                coverImage.isUserInteractionEnabled = true
                                coverImage.addGestureRecognizer(tap)
    }
                override func setUI() {
@@ -58,17 +84,32 @@
                                btn_handle = UIButton(type: .custom)
                                btn_handle.setImage(UIImage(named: "icon_play_purse"), for: .normal)
                                btn_handle.setImage(UIImage(named: "icon_play_small"), for: .selected)
                                btn_handle.addTarget(self, action: #selector(tapHandleAction), for: .touchUpInside)
                                view.addSubview(btn_handle)
                                btn_handle.snp.makeConstraints { make in
                                btn_handleClose = UIButton(type: .custom)
                                btn_handleClose.setImage(UIImage(named: "icon_play_close"), for: .normal)
                                btn_handleClose.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
                                view.addSubview(btn_handleClose)
                                let statckView = UIStackView(arrangedSubviews: [btn_handle,btn_handleClose])
                                statckView.axis = .horizontal
                                statckView.distribution = .equalSpacing
                                statckView.spacing = 18
                                view.addSubview(statckView)
                                statckView.snp.makeConstraints { make in
                                                make.right.equalToSuperview().offset(-24.5)
                                                make.centerY.equalToSuperview()
                                                make.width.height.equalTo(28)
                                }
                }
                static func show(){
                static func show(model:MeditationModel){
                                if let tabBarVC = JQ_currentViewController().navigationController?.tabBarController as? BaseTabBarVC{
                                                if !tabBarVC.children.contains(where: {$0 is PayMusicVC}){
                                 let vc = PayMusicVC()
                                                                vc.view.isHidden = true
                                                                vc.meditationModel = model
                                 let tabBarHeight = JQ_currentViewController().navigationController?.tabBarController?.tabBar.height ?? 0
                                JQ_currentViewController().navigationController?.tabBarController?.addChild(vc)
                                JQ_currentViewController().navigationController?.tabBarController?.view.addSubview(vc.view)
@@ -79,17 +120,21 @@
                                                make.bottom.equalToSuperview().offset(-(tabBarHeight))
                                }
                                vc.startRunloopAni()
                                                }
                                }
                }
                                var testURL = [URL]()
                                testURL.append(URL(string: "https://downsc.chinaz.net/files/download/sound1/201206/1638.mp3")!)
                                testURL.append(URL(string: "https://downsc.chinaz.net/Files/DownLoad/sound1/201906/11582.mp3")!)
                                testURL.append(URL(string: "https://www.cambridgeenglish.org/images/153149-movers-sample-listening-test-vol2.mp3")!)
                                vc.audioPlayer.playAt(firstPlayIndex: 2, urls: testURL)
                @objc func showDetailAction(){
                                if let id = meditationModel?.id{
                                                let vc = HomeItemDetailVC(id: id)
                                                vc.hidesBottomBarWhenPushed = true
                                                JQ_currentNavigationController().pushViewController(vc)
                                }
                }
                private func startRunloopAni(){
                                isAniLoop = true
                                // 创建旋转动画
                                let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
                                rotationAnimation.fromValue = 0
@@ -97,25 +142,51 @@
                                rotationAnimation.duration = 5 // 动画持续时间
                                rotationAnimation.repeatCount = .greatestFiniteMagnitude // 无限重复
                                coverImage.layer.add(rotationAnimation, forKey: nil)
                }
                private func stopRunloopAni(){
                                isAniLoop = false
                                coverImage.layer.removeAllAnimations()
                }
                @objc func tapHandleAction(_ btn:UIButton){
                                btn.isSelected = !btn.isSelected
                                if btn.isSelected{
                                                self.audioPlayer.bgmPlayer?.pause()
                                                self.audioPlayer.masterPlayer?.pause()
                                                self.stopRunloopAni()
                                }else{
                                                self.audioPlayer.bgmPlayer?.play()
                                                self.audioPlayer.masterPlayer?.play()
                                                self.startRunloopAni()
                                }
                }
                @objc func closeAction(_ btn:UIButton){
                                CommonAlertView.show(title: "提示", content: "是否关闭当前播放音频?") { state in
                                                if state{
                                                                self.audioPlayer.clean()
                                                                self.view.removeFromSuperview()
                                                                self.removeFromParent()
                                                }
                                }
                }
}
class AudioPlayer {
                private var player:AVPlayer?
                private var BGMplayer:AVPlayer?
                private var playIndex:Int = 0 //播放的角标
                private(set) var bgmPlayer:AVPlayer? // 背景音
                private(set) var scenePlayer:AVPlayer? //场景音
                private(set) var masterPlayer:AVPlayer? //大师音
                private(set) var playIndex:Int = 0 //播放的角标
                private var cacheDirectory:URL!
                private let session = URLSession.shared
                private var urls = [URL]()
                private var timer:Timer?
                private(set) var times = BehaviorRelay<Int?>(value: nil)
                private(set) var times = BehaviorRelay<Int?>(value: nil) //倒计时定时器
                private static var _sharedInstance: AudioPlayer?
                private(set) var meditationModel:MeditationModel?
                weak var delegate:PayMusicDelegate?
                class func getSharedInstance() -> AudioPlayer {
                                guard let instance = _sharedInstance else {
@@ -138,43 +209,81 @@
                                _sharedInstance = nil
                }
                func playAt(firstPlayIndex:Int,urls:[URL]){
                                self.playIndex = firstPlayIndex
                func clean(){
                                self.bgmPlayer?.pause()
                                self.masterPlayer?.pause()
                                self.meditationModel = nil
                                self.timer = nil
                                AudioPlayer.destroy()
                }
                                autoreleasepool{
                func playBGMAt(firstPlayIndex:Int,model:MeditationModel,delegate:PayMusicDelegate?){
                                self.delegate = delegate
                                self.playIndex = firstPlayIndex
                                self.meditationModel = model
                                let urls = model.backgroundUrl.components(separatedBy: ",").map { str in
                                                return URL(string: str)!
                                }
                                let masterUrl = URL(string: model.tutorAudioUrl)
                                autoreleasepool{[unowned self] () in
                                                for url in urls {
                                                                checkCacheAudio(from: url) { _, url in
                                                                self.checkCacheAudio(from: url) {[unowned self] _, url in
                                                                                self.urls.append(url)
                                                                }
                                                }
                                                player = AVPlayer(url: self.urls[firstPlayIndex])
                                                player?.play()
                                                self.bgmPlayer = AVPlayer(url: self.urls[firstPlayIndex])
                                                self.bgmPlayer?.play()
                                                if masterUrl != nil{
                                                                self.masterPlayer = AVPlayer(url: masterUrl!)
                                                                self.masterPlayer?.play()
                                                }
                                }
                                self.player!.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: DispatchQueue.main) { [unowned self](time) in
                                self.bgmPlayer!.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: DispatchQueue.main) { [weak self](time) in
                                                guard let weakSelf = self else { return }
                                                weakSelf.delegate?.playState(.playing)
                                                //当前正在播放的时间
                                                let loadTime = CMTimeGetSeconds(time)
                                                //视频总时间
                                                let totalTime = CMTimeGetSeconds((self.player?.currentItem?.duration)!)
                                                let totalTime = CMTimeGetSeconds((weakSelf.bgmPlayer?.currentItem?.duration)!)
                                                if loadTime >= totalTime{
                                                                if weakSelf.playIndex <= urls.count - 1{
                                                                                weakSelf.next()
                                                                                weakSelf.delegate?.playState(.next)
                                                                }else{
                                                                                weakSelf.delegate?.playState(.end)
                                                                }
                                                }
                                                weakSelf.delegate?.playListen?(currentInterval: loadTime, totalInterval: totalTime)
                                                if let m = weakSelf.meditationModel{
                                                var dic = [String:Any]()
                                                dic[MPMediaItemPropertyTitle] = "测试"
                                                                dic[MPMediaItemPropertyTitle] = m
                                                dic[MPMediaItemPropertyArtist] = "心泉·疗愈"
                                                dic[MPMediaItemPropertyDiscNumber] = 1
                                                dic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = loadTime
                                                dic[MPNowPlayingInfoPropertyPlaybackRate] = 1
                                                // 获取时长。item.duration.seconds 不凑效
                                                let asset = self.player?.currentItem?.asset
                                                                let asset = weakSelf.bgmPlayer?.currentItem?.asset
                                                dic[MPMediaItemPropertyPlaybackDuration] = CMTimeGetSeconds(asset!.duration)
                                                                                dic[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: CGSize(width: 50, height: 50), requestHandler: { s in
                                                                                                return UIImage(named: "home_top_bg")!
                                                                                })
                                                MPNowPlayingInfoCenter.default().nowPlayingInfo = dic
                                }
                                }
                                //播放完成
                                NotificationCenter.default.addObserver(self, selector: #selector(playbackEnd), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
//                                NotificationCenter.default.addObserver(self, selector: #selector(playbackEnd), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
                                setLockScreen()
@@ -188,60 +297,69 @@
                                }
                }
                func playBGMAt(_ url:String){
                /// 播放场景音乐
                func playSceneAt(_ url:String){
                                guard let URL = URL(string: url) else { return }
                                BGMplayer?.pause()
                                scenePlayer?.pause()
                                if BGMplayer == nil{
                                                BGMplayer = AVPlayer(url: URL)
                                if scenePlayer == nil{
                                                scenePlayer = AVPlayer(url: URL)
                                }else{
                                                BGMplayer?.replaceCurrentItem(with: AVPlayerItem(url: URL))
                                                scenePlayer?.replaceCurrentItem(with: AVPlayerItem(url: URL))
                                }
                                DispatchQueue.main.asyncAfter(delay: 3.0) {
                                                self.BGMplayer?.play()
                                                self.BGMplayer?.volume = Float(UserDefaultSettingViewModel.getSetting()?.volume ?? 0.5)
                                                self.scenePlayer?.play()
                                                self.scenePlayer?.volume = Float(UserDefaultSettingViewModel.getSetting()?.volume ?? 0.5)
                                }
                                //播放完成
                                NotificationCenter.default.addObserver(self, selector: #selector(playBGMbackEnd), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
//                                NotificationCenter.default.addObserver(self, selector: #selector(playBGMbackEnd), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
                }
                func dellocBGM(){
                                BGMplayer?.pause()
                                BGMplayer = nil
                func dellocScene(){
                                scenePlayer?.pause()
                                scenePlayer = nil
                }
                func pauseBGM(){
                                BGMplayer?.pause()
                func pauseScene(){
                                scenePlayer?.pause()
                }
                func playBGM(){
                                BGMplayer?.play()
                func playScene(){
                                scenePlayer?.play()
                }
                func next(){
                                playIndex += 1
                                let index = min((urls.count - 1), playIndex)
                                player?.replaceCurrentItem(with: AVPlayerItem(url: urls[index]))
                                player?.play()
                                bgmPlayer?.replaceCurrentItem(with: AVPlayerItem(url: urls[index]))
                                bgmPlayer?.play()
                }
                @objc private func playbackEnd(){
                }
//                @objc private func playbackEnd(){
//                                if bgmPlayer?.actionAtItemEnd == AVPlayer.ActionAtItemEnd.pause && playIndex <= urls.count - 1{
//                                                next()
//                                                self.delegate?.playState(.next)
//                                }else{
//                                                print("背景音乐播放完毕")
//                                                self.delegate?.playState(.end)
//                                }
//
//                                if masterPlayer?.actionAtItemEnd == AVPlayer.ActionAtItemEnd.pause{
//                                                print("导师播放完毕")
//                                }
//                }
                @objc private func playBGMbackEnd(){
                                self.BGMplayer?.seek(to: CMTimeMake(value: 0, timescale: 1))
                                self.BGMplayer?.play()
                                self.scenePlayer?.seek(to: CMTimeMake(value: 0, timescale: 1))
                                self.scenePlayer?.play()
                }
                func previous(){
                                playIndex -= 1
                                let index = max(0, playIndex)
                                player?.replaceCurrentItem(with: AVPlayerItem(url: urls[index]))
                                player?.play()
                                bgmPlayer?.replaceCurrentItem(with: AVPlayerItem(url: urls[index]))
                                bgmPlayer?.play()
                }
                func setLockScreen(){
@@ -255,7 +373,7 @@
                                                                return .commandFailed
                                                }
                                                self.player?.seek(to: CMTime(seconds: event.positionTime, preferredTimescale: 1),
                                                self.bgmPlayer?.seek(to: CMTime(seconds: event.positionTime, preferredTimescale: 1),
                                                                                                        toleranceBefore: CMTime(seconds: 0, preferredTimescale: 1),
                                                                                                        toleranceAfter: CMTime(seconds: 0, preferredTimescale: 1))
@@ -265,13 +383,13 @@
                                // 播放
                                center.playCommand.addTarget {[unowned self] event in
                                                self.player?.play()
                                                self.bgmPlayer?.play()
                                                return .success
                                }
                                // 暂停
                                center.pauseCommand.addTarget {[unowned self] event in
                                                self.player?.pause()
                                                self.bgmPlayer?.pause()
                                                return .success
                                }