From e15c976316feef72ff9bcabce38e0a078f9505db Mon Sep 17 00:00:00 2001 From: 杨锴 <841720330@qq.com> Date: 星期四, 12 九月 2024 18:18:03 +0800 Subject: [PATCH] fix API --- XQMuse/Root/Course/VC/CourseDetialVC.swift | 87 ++- XQMuse/Root/Pavilion/PavilionVC.swift | 48 + XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib | 17 XQMuse.xcodeproj/project.pbxproj | 10 XQMuse/Root/Home/VC/BackgroundVoiceVC.swift | 6 XQMuse/Root/Pavilion/CCell/PavilionItemCell.xib | 10 XQMuse/Root/Pavilion/PavilionVC.xib | 4 XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/Contents.json | 22 XQMuse/Root/Course/TCell/CourseDetail_1_TCell.xib | 1 XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift | 13 XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift | 12 XQMuse/Assets.xcassets/Placeholder/.DS_Store | 0 XQMuse/Root/Home/VC/HomeItemDetailVC.swift | 64 ++ XQMuse/Root/Home/HomeVC.swift | 3 XQMuse/Config/Enums/Enums.swift | 5 XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@3x.png | 0 XQMuse/Root/Course/VC/CourseDetialVideoVC.swift | 39 + XQMuse/Root/Network/Services.swift | 68 ++ XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib | 28 XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@2x.png | 0 XQMuse/Root/Course/View/CourseDetailHeaderView.xib | 12 XQMuse/Root/Course/VC/CourseMenuVC.swift | 40 XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@3x.png | 0 XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib | 7 XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/Contents.json | 22 XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@2x.png | 0 XQMuse/Root/Home/VC/SearchContentVC.swift | 3 XQMuse/Assets.xcassets/Icons/.DS_Store | 0 XQMuse/Root/Network/Models.swift | 79 +++ XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift | 10 XQMuse/Root/Course/View/CourseSendGiftView.swift | 5 XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/Contents.json | 22 XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@2x.png | 0 XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.xib | 4 XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift | 26 + XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift | 23 XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.swift | 17 XQMuse/Root/PayMusicView/PayMusicVC.swift | 272 ++++++++--- XQMuse/Root/Pavilion/VC/PavilionSearchVC.xib | 3 XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@3x.png | 0 XQMuse/Root/Course/TCell/CourseDetail_3_TCell.swift | 19 XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift | 46 + XQMuse/Root/Other/View/VideoView.swift | 8 XQMuse/Root/Course/TCell/CourseDetail_2_TCell.swift | 22 XQMuse/Root/Course/View/CourseDetailHeaderView.swift | 11 XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift | 53 ++ XQMuse/Root/Home/VC/HomeItemDetailVC.xib | 2 XQMuse/Root/Other/View/CommonBannerView.swift | 209 +++++++++ XQMuse/Assets.xcassets/.DS_Store | 0 XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.xib | 3 XQMuse/Root/Course/TCell/CourseDetail_1_TCell.swift | 16 51 files changed, 1,153 insertions(+), 218 deletions(-) diff --git a/XQMuse.xcodeproj/project.pbxproj b/XQMuse.xcodeproj/project.pbxproj index 750a350..aff3e2f 100644 --- a/XQMuse.xcodeproj/project.pbxproj +++ b/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; diff --git a/XQMuse/Assets.xcassets/.DS_Store b/XQMuse/Assets.xcassets/.DS_Store index 854b18c..8c18d87 100644 --- a/XQMuse/Assets.xcassets/.DS_Store +++ b/XQMuse/Assets.xcassets/.DS_Store Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/.DS_Store b/XQMuse/Assets.xcassets/Icons/.DS_Store new file mode 100644 index 0000000..e2d3f79 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/.DS_Store Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/Contents.json b/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/Contents.json new file mode 100644 index 0000000..16461a8 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/Contents.json @@ -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 + } +} diff --git a/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@2x.png b/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@2x.png new file mode 100644 index 0000000..c134f91 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@2x.png Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@3x.png b/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@3x.png new file mode 100644 index 0000000..49e18d2 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_play_close.imageset/icon_play_close@3x.png Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/Contents.json b/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/Contents.json new file mode 100644 index 0000000..afed910 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/Contents.json @@ -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 + } +} diff --git a/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@2x.png b/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@2x.png new file mode 100644 index 0000000..eef8d21 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@2x.png Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@3x.png b/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@3x.png new file mode 100644 index 0000000..ac6d65c --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_play_small.imageset/icon_play_small@3x.png Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/Contents.json b/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/Contents.json new file mode 100644 index 0000000..3098301 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/Contents.json @@ -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 + } +} diff --git a/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@2x.png b/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@2x.png new file mode 100644 index 0000000..99c9981 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@2x.png Binary files differ diff --git a/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@3x.png b/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@3x.png new file mode 100644 index 0000000..118cd91 --- /dev/null +++ b/XQMuse/Assets.xcassets/Icons/icon_use_small_s.imageset/icon_use_small_s@3x.png Binary files differ diff --git a/XQMuse/Assets.xcassets/Placeholder/.DS_Store b/XQMuse/Assets.xcassets/Placeholder/.DS_Store index 9f3856d..90137ef 100644 --- a/XQMuse/Assets.xcassets/Placeholder/.DS_Store +++ b/XQMuse/Assets.xcassets/Placeholder/.DS_Store Binary files differ diff --git a/XQMuse/Config/Enums/Enums.swift b/XQMuse/Config/Enums/Enums.swift index 4996c9a..bdf9198 100644 --- a/XQMuse/Config/Enums/Enums.swift +++ b/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 diff --git a/XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift b/XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift index c55f467..d427d0e 100644 --- a/XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift +++ b/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 } diff --git a/XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.xib b/XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.xib index ef9ac9e..45931c9 100644 --- a/XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.xib +++ b/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"/> diff --git a/XQMuse/Root/Course/TCell/CourseDetail_1_TCell.swift b/XQMuse/Root/Course/TCell/CourseDetail_1_TCell.swift index 6174889..5e4b714 100644 --- a/XQMuse/Root/Course/TCell/CourseDetail_1_TCell.swift +++ b/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){ diff --git a/XQMuse/Root/Course/TCell/CourseDetail_1_TCell.xib b/XQMuse/Root/Course/TCell/CourseDetail_1_TCell.xib index 1d4190a..fd0731e 100644 --- a/XQMuse/Root/Course/TCell/CourseDetail_1_TCell.xib +++ b/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> diff --git a/XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.swift b/XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.swift index ad7cb97..cf16393 100644 --- a/XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.swift +++ b/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) } } diff --git a/XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.xib b/XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.xib index 4c550c1..fa87099 100644 --- a/XQMuse/Root/Course/TCell/CourseDetail_2_Inner_TCell.xib +++ b/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> diff --git a/XQMuse/Root/Course/TCell/CourseDetail_2_TCell.swift b/XQMuse/Root/Course/TCell/CourseDetail_2_TCell.swift index 9a30226..ddda173 100644 --- a/XQMuse/Root/Course/TCell/CourseDetail_2_TCell.swift +++ b/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 } diff --git a/XQMuse/Root/Course/TCell/CourseDetail_3_TCell.swift b/XQMuse/Root/Course/TCell/CourseDetail_3_TCell.swift index 4ad3240..7c04393 100644 --- a/XQMuse/Root/Course/TCell/CourseDetail_3_TCell.swift +++ b/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{ diff --git a/XQMuse/Root/Course/VC/CourseDetialVC.swift b/XQMuse/Root/Course/VC/CourseDetialVC.swift index dd0d97e..4165914 100644 --- a/XQMuse/Root/Course/VC/CourseDetialVC.swift +++ b/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) - }else{ - 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{ + 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 { - let vc = PaymentOrderVC() - self.push(vc: vc) + 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 + return UITableView.automaticDimension } 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") diff --git a/XQMuse/Root/Course/VC/CourseDetialVideoVC.swift b/XQMuse/Root/Course/VC/CourseDetialVideoVC.swift index 427dd57..17b5ef8 100644 --- a/XQMuse/Root/Course/VC/CourseDetialVideoVC.swift +++ b/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() + } } diff --git a/XQMuse/Root/Course/VC/CourseMenuVC.swift b/XQMuse/Root/Course/VC/CourseMenuVC.swift index c3ad658..3d992ff 100644 --- a/XQMuse/Root/Course/VC/CourseMenuVC.swift +++ b/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) - push(vc: vc) - }else{ - let vc = CourseDetialVC(courseSytle: .style2) - push(vc: vc) - } + let model = viewModel.dataSource.value!.list[indexPath.row] + let vc = CourseDetialVC(courseId: model.id) + 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 } } diff --git a/XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift b/XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift index 627777c..af899b8 100644 --- a/XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift +++ b/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 { diff --git a/XQMuse/Root/Course/View/CourseDetailHeaderView.swift b/XQMuse/Root/Course/View/CourseDetailHeaderView.swift index cfc13c3..d50a3db 100644 --- a/XQMuse/Root/Course/View/CourseDetailHeaderView.swift +++ b/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)) + } } diff --git a/XQMuse/Root/Course/View/CourseDetailHeaderView.xib b/XQMuse/Root/Course/View/CourseDetailHeaderView.xib index e8b97cb..e58cb6f 100644 --- a/XQMuse/Root/Course/View/CourseDetailHeaderView.xib +++ b/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> diff --git a/XQMuse/Root/Course/View/CourseSendGiftView.swift b/XQMuse/Root/Course/View/CourseSendGiftView.swift index c1b9fc4..af9075f 100644 --- a/XQMuse/Root/Course/View/CourseSendGiftView.swift +++ b/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 diff --git a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift b/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift index 1ed8503..93a8fff 100644 --- a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift +++ b/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 + } + } diff --git a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib b/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib index 6ba81d1..0a0c40f 100644 --- a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib +++ b/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> diff --git a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift b/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift index 3ed6025..59a67be 100644 --- a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift +++ b/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift @@ -11,13 +11,14 @@ 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() { super.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)" + } } diff --git a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib b/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib index 2716505..de03781 100644 --- a/XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib +++ b/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"/> diff --git a/XQMuse/Root/Home/HomeVC.swift b/XQMuse/Root/Home/HomeVC.swift index 4cb581f..3af08cb 100644 --- a/XQMuse/Root/Home/HomeVC.swift +++ b/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) } } diff --git a/XQMuse/Root/Home/VC/BackgroundVoiceVC.swift b/XQMuse/Root/Home/VC/BackgroundVoiceVC.swift index 44adf7a..37b0d42 100644 --- a/XQMuse/Root/Home/VC/BackgroundVoiceVC.swift +++ b/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]) } diff --git a/XQMuse/Root/Home/VC/HomeItemDetailVC.swift b/XQMuse/Root/Home/VC/HomeItemDetailVC.swift index fb3e88f..3a5a744 100644 --- a/XQMuse/Root/Home/VC/HomeItemDetailVC.swift +++ b/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) + } } diff --git a/XQMuse/Root/Home/VC/HomeItemDetailVC.xib b/XQMuse/Root/Home/VC/HomeItemDetailVC.xib index 69692ea..5d83e74 100644 --- a/XQMuse/Root/Home/VC/HomeItemDetailVC.xib +++ b/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"/> diff --git a/XQMuse/Root/Home/VC/SearchContentVC.swift b/XQMuse/Root/Home/VC/SearchContentVC.swift index 7d048a8..7441048 100644 --- a/XQMuse/Root/Home/VC/SearchContentVC.swift +++ b/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) } diff --git a/XQMuse/Root/Network/Models.swift b/XQMuse/Root/Network/Models.swift index 9ed3bc3..1bf6b35 100644 --- a/XQMuse/Root/Network/Models.swift +++ b/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 +} + + + diff --git a/XQMuse/Root/Network/Services.swift b/XQMuse/Root/Network/Services.swift index 193092c..30cd640 100644 --- a/XQMuse/Root/Network/Services.swift +++ b/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>>{ diff --git a/XQMuse/Root/Other/View/CommonBannerView.swift b/XQMuse/Root/Other/View/CommonBannerView.swift new file mode 100644 index 0000000..fad18d3 --- /dev/null +++ b/XQMuse/Root/Other/View/CommonBannerView.swift @@ -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") + } +} diff --git a/XQMuse/Root/Other/View/VideoView.swift b/XQMuse/Root/Other/View/VideoView.swift index 8966643..6ad8734 100644 --- a/XQMuse/Root/Other/View/VideoView.swift +++ b/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") } diff --git a/XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift b/XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift index 4d36f15..d8a0cb2 100644 --- a/XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift +++ b/XQMuse/Root/Pavilion/CCell/PavilionItemCell.swift @@ -6,12 +6,36 @@ // import UIKit +import JQTools class PavilionItemCell: UICollectionViewCell { - override func awakeFromNib() { + 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 + } + } diff --git a/XQMuse/Root/Pavilion/CCell/PavilionItemCell.xib b/XQMuse/Root/Pavilion/CCell/PavilionItemCell.xib index 35ab45a..3c3250c 100644 --- a/XQMuse/Root/Pavilion/CCell/PavilionItemCell.xib +++ b/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> diff --git a/XQMuse/Root/Pavilion/PavilionVC.swift b/XQMuse/Root/Pavilion/PavilionVC.swift index a326dd1..e10327f 100644 --- a/XQMuse/Root/Pavilion/PavilionVC.swift +++ b/XQMuse/Root/Pavilion/PavilionVC.swift @@ -7,14 +7,37 @@ 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! - - override func viewDidLoad() { - super.viewDidLoad() - } + 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() { super.setUI() @@ -24,38 +47,39 @@ 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) } - + } 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 cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_PavilionItemCell", for: indexPath) as! PavilionItemCell + 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 } } diff --git a/XQMuse/Root/Pavilion/PavilionVC.xib b/XQMuse/Root/Pavilion/PavilionVC.xib index 571c901..80531d7 100644 --- a/XQMuse/Root/Pavilion/PavilionVC.xib +++ b/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"/> diff --git a/XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift b/XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift index 707b0d0..d7ae81c 100644 --- a/XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift +++ b/XQMuse/Root/Pavilion/VC/PavilionDetailVC.swift @@ -13,21 +13,72 @@ @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() { super.viewDidLoad() title = "疗愈馆详情" 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) + + } + override var preferredStatusBarStyle: UIStatusBarStyle{ return .lightContent diff --git a/XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib b/XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib index 3234385..07509f6 100644 --- a/XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib +++ b/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> diff --git a/XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift b/XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift index 42c9e3f..32f3d82 100644 --- a/XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift +++ b/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 } } diff --git a/XQMuse/Root/Pavilion/VC/PavilionSearchVC.xib b/XQMuse/Root/Pavilion/VC/PavilionSearchVC.xib index 43ec988..937b9e2 100644 --- a/XQMuse/Root/Pavilion/VC/PavilionSearchVC.xib +++ b/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"/> diff --git a/XQMuse/Root/PayMusicView/PayMusicVC.swift b/XQMuse/Root/PayMusicView/PayMusicVC.swift index b403aeb..687e2c5 100644 --- a/XQMuse/Root/PayMusicView/PayMusicVC.swift +++ b/XQMuse/Root/PayMusicView/PayMusicVC.swift @@ -11,12 +11,34 @@ import MediaPlayer import RxRelay -class PayMusicVC: BaseVC { +@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,38 +84,57 @@ 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(){ - let vc = PayMusicVC() - let tabBarHeight = JQ_currentViewController().navigationController?.tabBarController?.tabBar.height ?? 0 - JQ_currentViewController().navigationController?.tabBarController?.addChild(vc) - JQ_currentViewController().navigationController?.tabBarController?.view.addSubview(vc.view) - vc.view.snp.makeConstraints { make in - make.left.equalTo(18.5) - make.right.equalTo(-18.5) - make.height.equalTo(46.5) - make.bottom.equalToSuperview().offset(-(tabBarHeight)) + 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) + vc.view.snp.makeConstraints { make in + make.left.equalTo(18.5) + make.right.equalTo(-18.5) + make.height.equalTo(46.5) + make.bottom.equalToSuperview().offset(-(tabBarHeight)) + } + vc.startRunloopAni() + } } - 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)!) - var dic = [String:Any]() - dic[MPMediaItemPropertyTitle] = "测试" - dic[MPMediaItemPropertyArtist] = "心泉·疗愈" - dic[MPMediaItemPropertyDiscNumber] = 1 - dic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = loadTime - dic[MPNowPlayingInfoPropertyPlaybackRate] = 1 - // 获取时长。item.duration.seconds 不凑效 - let asset = self.player?.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 + + 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] = m + dic[MPMediaItemPropertyArtist] = "心泉·疗愈" + dic[MPMediaItemPropertyDiscNumber] = 1 + dic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = loadTime + dic[MPNowPlayingInfoPropertyPlaybackRate] = 1 + // 获取时长。item.duration.seconds 不凑效 + 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 } -- Gitblit v1.7.1