2 文件已重命名
5个文件已删除
28个文件已修改
1个文件已添加
New file |
| | |
| | | // |
| | | // EqualCellSpaceFlowLayout.swift |
| | | // XQMuse |
| | | // |
| | | // Created by 无故事王国 on 2024/8/27. |
| | | // |
| | | |
| | | import UIKit |
| | | enum AlignType : NSInteger { |
| | | case left = 0 |
| | | case center = 1 |
| | | case right = 2 |
| | | } |
| | | |
| | | |
| | | class EqualCellSpaceFlowLayout: UICollectionViewFlowLayout { |
| | | //两个Cell之间的距离 |
| | | private var horizontalSpace : CGFloat{ |
| | | didSet{ |
| | | self.minimumInteritemSpacing = horizontalSpace |
| | | } |
| | | } |
| | | //cell对齐方式 |
| | | private var alignType : AlignType = AlignType.center |
| | | //在居中对齐的时候需要知道这行所有cell的宽度总和 |
| | | var cellWidthInLine : CGFloat = 0.0 |
| | | |
| | | override init() { |
| | | horizontalSpace = 5.0 |
| | | super.init() |
| | | scrollDirection = UICollectionView.ScrollDirection.vertical |
| | | minimumLineSpacing = 5 |
| | | sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) |
| | | } |
| | | convenience init(_ cellType:AlignType){ |
| | | self.init() |
| | | self.alignType = cellType |
| | | } |
| | | convenience init(_ cellType: AlignType, _ horizontalSpace: CGFloat){ |
| | | self.init() |
| | | self.alignType = cellType |
| | | self.horizontalSpace = horizontalSpace |
| | | } |
| | | |
| | | required init?(coder aDecoder: NSCoder) { |
| | | horizontalSpace = 5.0 |
| | | super.init(coder: aDecoder) |
| | | scrollDirection = UICollectionView.ScrollDirection.vertical |
| | | minimumLineSpacing = 5 |
| | | sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) |
| | | } |
| | | |
| | | override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { |
| | | |
| | | let layoutAttributes_super : [UICollectionViewLayoutAttributes] = super.layoutAttributesForElements(in: rect) ?? [UICollectionViewLayoutAttributes]() |
| | | let layoutAttributes:[UICollectionViewLayoutAttributes] = NSArray(array: layoutAttributes_super, copyItems:true)as! [UICollectionViewLayoutAttributes] |
| | | var layoutAttributes_t : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]() |
| | | for index in 0..<layoutAttributes.count{ |
| | | |
| | | print("index in 0..<layoutAttributes.count ==============") |
| | | |
| | | let currentAttr = layoutAttributes[index] |
| | | let previousAttr = index == 0 ? nil : layoutAttributes[index-1] |
| | | let nextAttr = index + 1 == layoutAttributes.count ? |
| | | nil : layoutAttributes[index+1] |
| | | |
| | | layoutAttributes_t.append(currentAttr) |
| | | cellWidthInLine += currentAttr.frame.size.width |
| | | |
| | | let previousY :CGFloat = previousAttr == nil ? 0 : previousAttr!.frame.maxY |
| | | let currentY :CGFloat = currentAttr.frame.maxY |
| | | let nextY:CGFloat = nextAttr == nil ? 0 : nextAttr!.frame.maxY |
| | | |
| | | if currentY != previousY && currentY != nextY{ |
| | | if currentAttr.representedElementKind == UICollectionView.elementKindSectionHeader{ |
| | | layoutAttributes_t.removeAll() |
| | | cellWidthInLine = 0.0 |
| | | print("currentAttr.representedElementKind == UICollectionView.elementKindSectionHeader =========== Header") |
| | | }else if currentAttr.representedElementKind == UICollectionView.elementKindSectionFooter{ |
| | | layoutAttributes_t.removeAll() |
| | | cellWidthInLine = 0.0 |
| | | print("currentAttr.representedElementKind == UICollectionView.elementKindSectionFooter ============ Footer") |
| | | }else{ |
| | | self.setCellFrame(with: layoutAttributes_t) |
| | | layoutAttributes_t.removeAll() |
| | | cellWidthInLine = 0.0 |
| | | print("currentY != previousY && currentY != nextY ============== Item") |
| | | } |
| | | } else if currentY != nextY { //这里currentY == previousY 说明和上一个项目在同一行,currentY != nextY说明下一个项目要换行了,这种情况直接计算本行的对齐方式 |
| | | self.setCellFrame(with: layoutAttributes_t) |
| | | layoutAttributes_t.removeAll() |
| | | cellWidthInLine = 0.0 |
| | | print("currentY != nextY ======== Else") |
| | | } |
| | | } |
| | | return layoutAttributes |
| | | } |
| | | |
| | | /// 调整Cell的Frame |
| | | /// |
| | | /// - Parameter layoutAttributes: layoutAttribute 数组 |
| | | func setCellFrame(with layoutAttributes : [UICollectionViewLayoutAttributes]){ |
| | | var nowWidth : CGFloat = 0.0 |
| | | switch alignType { |
| | | case AlignType.left: |
| | | nowWidth = self.sectionInset.left |
| | | for attributes in layoutAttributes { |
| | | var nowFrame = attributes.frame |
| | | nowFrame.origin.x = nowWidth |
| | | attributes.frame = nowFrame |
| | | nowWidth += nowFrame.size.width + self.horizontalSpace |
| | | } |
| | | break; |
| | | case AlignType.center: |
| | | nowWidth = (self.collectionView!.frame.size.width - cellWidthInLine - (CGFloat(layoutAttributes.count - 1) * horizontalSpace)) / 2 |
| | | for attributes in layoutAttributes{ |
| | | var nowFrame = attributes.frame |
| | | nowFrame.origin.x = nowWidth |
| | | attributes.frame = nowFrame |
| | | nowWidth += nowFrame.size.width + self.horizontalSpace |
| | | } |
| | | break; |
| | | case AlignType.right: |
| | | nowWidth = self.collectionView!.frame.size.width - self.sectionInset.right |
| | | for var index in 0 ..< layoutAttributes.count{ |
| | | index = layoutAttributes.count - 1 - index |
| | | let attributes = layoutAttributes[index] |
| | | var nowFrame = attributes.frame |
| | | nowFrame.origin.x = nowWidth - nowFrame.size.width |
| | | attributes.frame = nowFrame |
| | | nowWidth = nowWidth - nowFrame.size.width - horizontalSpace |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | private var tableView:UITableView? |
| | | private var collect_bitem:UIBarButtonItem! |
| | | private var share_bitem:UIBarButtonItem! |
| | | private let studyBtn = QMUIButton(type: .custom) |
| | | private var headerView = CourseDetailHeaderView.jq_loadNibView() |
| | | private var barStyle:UIStatusBarStyle = .lightContent |
| | |
| | | |
| | | collect_bitem = UIBarButtonItem(image: UIImage(named: "btn_collect"), style: .plain, target: self, action: #selector(collectionAction)) |
| | | collect_bitem.tintColor = .white |
| | | let share_bitem = UIBarButtonItem(image: UIImage(named: "btn_share"), style: .plain, target: self, action: #selector(shareAction)) |
| | | share_bitem = UIBarButtonItem(image: UIImage(named: "btn_share"), style: .plain, target: self, action: #selector(shareAction)) |
| | | share_bitem.tintColor = .white |
| | | share_bitem.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15) |
| | | navigationItem.rightBarButtonItems = [share_bitem,collect_bitem] |
| | |
| | | |
| | | if v > 0{ |
| | | (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.black.withAlphaComponent(v)), for: .normal) |
| | | |
| | | (navigationItem.rightBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.black.withAlphaComponent(v)), for: .normal) |
| | | |
| | | |
| | | collect_bitem.tintColor = .black |
| | | share_bitem.tintColor = .black |
| | | |
| | | |
| | | self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor:Def_NavFontColor.withAlphaComponent(v),.font:Def_NavFont] |
| | | barStyle = .darkContent |
| | | |
| | | }else{ |
| | | collect_bitem.tintColor = .white |
| | | share_bitem.tintColor = .white |
| | | |
| | | (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal) |
| | | self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor:UIColor.white,.font:Def_NavFont] |
| | | } |
| | |
| | | private var videoView:VideoView? |
| | | private var items = [CourseItemModel]() |
| | | private var selectIndex:IndexPath! |
| | | private var secondLook:Int = 0 |
| | | private var isOver:Bool = false |
| | | |
| | | override func viewWillAppear(_ animated: Bool) { |
| | | super.viewWillAppear(animated) |
| | |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidDisappear(_ animated: Bool) { |
| | | super.viewDidDisappear(animated) |
| | | let item = items[selectIndex.row] |
| | | |
| | | guard secondLook > 0 else {return} |
| | | |
| | | Services.watchClouse(chapterId: item.id, isOver: isOver, minuteLook: 0, secondLook: secondLook).subscribe(onNext: { _ in |
| | | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | title = "课程详情" |
| | | |
| | | videoView = VideoView(url: items[selectIndex.row].videoUrl) |
| | | videoView = VideoView(url: items[selectIndex.row].videoUrl,delegate: self) |
| | | videoView?.player.play() |
| | | view_bg_video.addSubview(videoView!) |
| | | videoView!.snp.makeConstraints { make in |
| | |
| | | tableView.reloadData() |
| | | } |
| | | } |
| | | |
| | | extension CourseDetialVideoVC:CLPlayerDelegate{ |
| | | func player(_ player: CLPlayer, playProgressChanged value: CGFloat) { |
| | | secondLook = player.currentDuration.int |
| | | print("视频播放进度:\(player.currentDuration.int)") |
| | | } |
| | | |
| | | func didPlayToEnd(in player: CLPlayer) { |
| | | isOver = true |
| | | print("视频播放进度:【完成】") |
| | | } |
| | | } |
| | | |
| | |
| | | NotificationCenter.default.rx.notification(PlantGuideQuit_Noti).take(until: self.rx.deallocated).subscribe(onNext: {data in |
| | | self.getData() |
| | | }).disposed(by: disposeBag) |
| | | |
| | | NotificationCenter.default.rx.notification(LoginSuccess_Noti).take(until: self.rx.deallocated).subscribe(onNext: {data in |
| | | self.getData() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | private func getData(){ |
| | |
| | | @objc func jumpMoreAction(_ sender:UIButton){ |
| | | switch sender.tag { |
| | | case 201: |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | //跳转计划引导 |
| | | let nav = BaseNav(rootViewController: PlanGuideVC()) |
| | | nav.modalPresentationStyle = .fullScreen |
| | |
| | | private var collect_bitem:UIBarButtonItem! |
| | | private var audioPlayer:AudioPlayer = AudioPlayer.getSharedInstance() |
| | | private var id:Int! |
| | | private var timeLook:Int = 0 //观看时间记录 |
| | | private var settingViewModel = UserDefaultSettingViewModel.getSetting() |
| | | private var model:MeditationModel?{ |
| | | didSet{ |
| | |
| | | super.viewWillAppear(animated) |
| | | (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal) |
| | | navigationController?.navigationBar.scrollEdgeAppearance?.backgroundColor = .clear |
| | | } |
| | | |
| | | override func viewDidDisappear(_ animated: Bool) { |
| | | super.viewDidDisappear(animated) |
| | | |
| | | if let m = model,timeLook > 0{ |
| | | Services.watchMuse(id: m.id, timeLook: timeLook).subscribe(onNext: {_ in |
| | | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | PayMusicVC.show(model: model!) |
| | | if btn_play.isHidden == false {btn_play.isHidden = true} |
| | | hiddenHUD() |
| | | case .paurse: |
| | | btn_play.isHidden = false |
| | | case .paurse:btn_play.isHidden = false |
| | | case .end:break |
| | | case .next:break |
| | | } |
| | |
| | | guard !totalInterval.isNaN else {return} |
| | | guard !currentInterval.isNaN else {return} |
| | | |
| | | timeLook += 1 |
| | | |
| | | let v = currentInterval / totalInterval * 100 |
| | | print("music:当前时间:\(currentInterval) ---- \(totalInterval) -- \(v)%") |
| | | self.slider_voice.value = Float(v) |
| | |
| | | import AuthenticationServices |
| | | |
| | | |
| | | let LoginSuccess_Noti = Notification.Name.init("LoginSuccess_Noti") |
| | | |
| | | class LoginViewModel{ |
| | | var loginType = BehaviorRelay<LoginType>(value:.pwd) |
| | | var loginPhone = BehaviorRelay<String>(value:"") |
| | |
| | | if let credential = authorization.credential as? ASAuthorizationAppleIDCredential{ |
| | | |
| | | Services.loginByApple(appleId: credential.user).subscribe(onNext: {data in |
| | | if var m = data.data,m.bindStatus == 2{ |
| | | if var m = data.data{ |
| | | if m.bindStatus == 2{ |
| | | sceneDelegate?.loginSuccess() |
| | | m.loginByAppleToken = String(data: credential.identityToken!, encoding: .utf8) |
| | | m.appleId = credential.user |
| | |
| | | } |
| | | }).disposed(by: self.disposeBag) |
| | | }else{ |
| | | let vc = UpdatePhoneVC(credential: credential) |
| | | let vc = UpdatePhoneVC(credential: credential,firstAccessToken: m.accessToken) |
| | | self.jq_push(vc: vc) |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | |
| | | |
| | | |
| | | // print(credential.user) |
| | | // print(credential.state) |
| | | // print(credential.email) |
| | | // print(credential.fullName?.familyName) |
| | | // print(credential.fullName?.givenName) |
| | | // print(credential.fullName?.middleName) |
| | | // print(String(data: credential.identityToken!, encoding: .utf8)) |
| | | |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | guard tf_input.text!.jq_isComplexPassword else {alertError(msg: "密码至少8个字符,不能全是字母或数字");return} |
| | | |
| | | Services.updatePwd(cellPhone: phone, password: tf_input.text!, secretCode: secretCode).subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | if data.code == 200{ |
| | | Popup_1_View.show(state: .success, title: "修改成功", subtitle: "您的密码已修改成功,快去登录账户吧") { |
| | | self.navigationController?.popToRootViewController(animated: true) |
| | | } |
| | |
| | | times = 60 |
| | | btn_retry.isEnabled = false |
| | | btn_retry.alpha = 0.5 |
| | | timer = Timer(timeInterval: 1.0, repeats: true) {[unowned self] t in |
| | | self.times -= 1 |
| | | self.label_retryCode.text = "\(self.times)s后可重新发送验证码" |
| | | if self.times == 0{ |
| | | self.label_retryCode.text = "" |
| | | self.btn_retry.isEnabled = true |
| | | self.btn_retry.alpha = 1.0 |
| | | timer = Timer(timeInterval: 1.0, repeats: true) {[weak self] t in |
| | | self?.times -= 1 |
| | | self?.label_retryCode.text = "\(self?.times ?? 0)s后可重新发送验证码" |
| | | if self?.times == 0{ |
| | | self?.label_retryCode.text = "" |
| | | self?.btn_retry.isEnabled = true |
| | | self?.btn_retry.alpha = 1.0 |
| | | t.invalidate() |
| | | } |
| | | } |
| | |
| | | |
| | | class UpdatePhoneVC: BaseVC { |
| | | private var credential:ASAuthorizationAppleIDCredential? |
| | | private var firstAccessToken:String? //后端问题,要把上次的token带过来 |
| | | @IBOutlet weak var tf_phone: QMUITextField! |
| | | @IBOutlet weak var tf_code: QMUITextField! |
| | | @IBOutlet weak var btn_code: UIButton! |
| | | @IBOutlet weak var btn_isRead: UIButton! |
| | | |
| | | init(credential:ASAuthorizationAppleIDCredential? = nil) { |
| | | |
| | | init(credential:ASAuthorizationAppleIDCredential? = nil,firstAccessToken:String?) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.credential = credential |
| | | self.firstAccessToken = firstAccessToken |
| | | } |
| | | |
| | | @MainActor required init?(coder: NSCoder) { |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | title = "验证手机号" |
| | | } |
| | | |
| | | @IBAction func isReadAction(_ sender: UIButton) { |
| | | btn_isRead.isSelected = !btn_isRead.isSelected |
| | | } |
| | | |
| | | @IBAction func getCodeAction(_ sender: UIButton) { |
| | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func userRegisterTreatyAction(_ sender: UIButton) { |
| | | let vc = LoginTreatyVC() |
| | | vc.topIndex = 0 |
| | | vc.clickHandle {[unowned self] state in |
| | | self.btn_isRead.isSelected = state |
| | | } |
| | | vc.modalPresentationStyle = .custom |
| | | present(vc, animated: true) |
| | | } |
| | | |
| | | @IBAction func userPrivateTreatyAction(_ sender: UIButton) { |
| | | let vc = LoginTreatyVC() |
| | | vc.topIndex = 1 |
| | | vc.clickHandle {[unowned self] state in |
| | | self.btn_isRead.isSelected = state |
| | | } |
| | | vc.modalPresentationStyle = .custom |
| | | present(vc, animated: true) |
| | | } |
| | | |
| | | @IBAction func loginAction(_ sender: UIButton) { |
| | | view.endEditing(true) |
| | | |
| | | guard btn_isRead.isSelected else { |
| | | alertError(msg: "请先阅读并同意《用户注册协议》《用户隐私协议》");return |
| | | } |
| | | |
| | | guard tf_phone.text!.jq_isPhone else { |
| | | alertError(msg: "请输入正确的手机号");return |
| | | } |
| | |
| | | Services.confirmByApple(cellPhone: tf_phone.text!, captcha: tf_code.text!, loginType: .apple, wxOrAppleId: credentialUser,name: formatName, mail: credential!.email).subscribe(onNext: {data in |
| | | if var model = data.data{ |
| | | model.loginByAppleToken = String(data: self.credential!.identityToken!, encoding: .utf8) |
| | | model.accessToken = self.firstAccessToken ?? "" |
| | | model.appleId = self.credential!.user |
| | | sceneDelegate?.loginSuccess() |
| | | NotificationCenter.default.post(name: LoginDismiss_Noti, object: nil, userInfo: nil) |
| | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="Button" image="btn_choose"/> |
| | | <state key="selected" image="btn_choose_s"/> |
| | | <connections> |
| | | <action selector="isReadAction:" destination="-1" eventType="touchUpInside" id="Qpg-Tx-ank"/> |
| | | </connections> |
| | | </button> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我已阅读并同意" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="38g-LO-yZD"> |
| | | <rect key="frame" x="57.000000000000007" y="350" width="83.666666666666686" height="14.333333333333314"/> |
| | |
| | | <state key="normal" title="《用户隐私协议》"> |
| | | <color key="titleColor" red="0.58823529409999997" green="0.67843137249999996" blue="0.50588235290000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | </state> |
| | | <connections> |
| | | <action selector="userPrivateTreatyAction:" destination="-1" eventType="touchUpInside" id="BiC-Bb-hbQ"/> |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ztb-yJ-wp8"> |
| | | <rect key="frame" x="145.66666666666666" y="343.66666666666669" width="84" height="27"/> |
| | |
| | | <state key="normal" title="《用户注册协议》"> |
| | | <color key="titleColor" red="0.58823529409999997" green="0.67843137249999996" blue="0.50588235290000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | </state> |
| | | <connections> |
| | | <action selector="userRegisterTreatyAction:" destination="-1" eventType="touchUpInside" id="iLB-7u-HH0"/> |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zN9-OK-XPQ"> |
| | | <rect key="frame" x="31" y="423" width="331" height="40"/> |
| | |
| | | self.queryNotice() |
| | | }).disposed(by: disposeBag) |
| | | |
| | | |
| | | NotificationCenter.default.rx.notification(LoginSuccess_Noti).take(until: self.rx.deallocated).subscribe(onNext: {data in |
| | | self.getData() |
| | | self.queryNotice() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | private func getData(){ |
| | | Services.getUserDetail().subscribe(onNext: {data in |
| | | Services.getUserInfo().subscribe(onNext: {[weak self] data in |
| | | if let model = data.data{ |
| | | UserViewModel.saveAvatarInfo(model) |
| | | self?.setUserUI(model: model) |
| | | |
| | | } |
| | | }).disposed(by: self.disposeBag) |
| | | },onError: {[weak self]error in |
| | | let model = UserViewModel.getAvatarInfo() |
| | | if model.id > 0{ |
| | | self?.setUserUI(model: model) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | Services.getUserInfo().subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | private func setUserUI(model:UserInfoModel){ |
| | | self.image_userAvatar.sd_setImage(with: URL(string: model.avatar)) |
| | | self.label_userName.text = model.nickname |
| | | self.label_phone.text = model.cellPhone.jq_blotOutPhone() |
| | |
| | | |
| | | self.label_today.attributedText = AttributedStringbuilder.build().add(string: "\(timeTurple.hour)", withFont: .systemFont(ofSize: 23), withColor: UIColor(hexString: "#152715")!).add(string: "时", withFont: .systemFont(ofSize: 12), withColor: UIColor(hexString: "#152715")!).add(string: "\(timeTurple.minute)", withFont: .systemFont(ofSize: 23), withColor: UIColor(hexString: "#152715")!).add(string: "分", withFont: .systemFont(ofSize: 12), withColor: UIColor(hexString: "#152715")!).mutableAttributedString |
| | | |
| | | |
| | | |
| | | if model.isVip == .yes{ |
| | | self.image_vipBg.image = UIImage(named: "bg_vip") |
| | | self.label_vipInfo.text = "你已是高级会员" |
| | |
| | | self.label_expirtTime.text = "你还未开通会员服务" |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @objc func rankAction(){ |
| | | let vc = WebVC() |
| | |
| | | } |
| | | |
| | | @IBAction func vipCenterAction(_ sender: Any) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = VIPCenterVC() |
| | | push(vc: vc) |
| | | } |
| | | |
| | | |
| | | @IBAction func userProfileAction(_ sender: UIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let profileVC = UserProfileVC() |
| | | jq_push(vc: profileVC) |
| | | } |
| | | |
| | | @IBAction func studyLevelAction(_ sender: TapBtn) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = LevelVC() |
| | | push(vc: vc) |
| | | } |
| | |
| | | |
| | | //学习记录 |
| | | @IBAction func studyAction(_ sender: UIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = StudyListVC() |
| | | push(vc: vc) |
| | | } |
| | |
| | | |
| | | //我的账户 |
| | | @IBAction func myAccountAction(_ sender: QMUIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = WalletVC() |
| | | push(vc: vc) |
| | | } |
| | | |
| | | //观看历史 |
| | | @IBAction func watchHistoryAction(_ sender: QMUIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = WatchHistoryVC(type: .history) |
| | | push(vc: vc) |
| | | } |
| | | |
| | | //我的收藏 |
| | | @IBAction func myColletAction(_ sender: QMUIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = WatchHistoryVC(type: .collect) |
| | | push(vc: vc) |
| | | } |
| | | |
| | | /// 我的已购 |
| | | @IBAction func paymentCourseAction(_ sender: QMUIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = WatchHistoryVC(type: .payment) |
| | | push(vc: vc) |
| | | } |
| | |
| | | </userDefinedRuntimeAttribute> |
| | | </userDefinedRuntimeAttributes> |
| | | </imageView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xiq-PE-zPH"> |
| | | <rect key="frame" x="86" y="17.666666666666671" width="15.333333333333329" height="20.333333333333329"/> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="请先登录" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xiq-PE-zPH"> |
| | | <rect key="frame" x="86" y="17.666666666666671" width="67.666666666666686" height="20.333333333333329"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="17"/> |
| | | <color key="textColor" red="0.082352941176470587" green="0.15294117647058825" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <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="xL7-Qf-iI2"> |
| | | <rect key="frame" x="86" y="48.333333333333336" width="13" height="17.000000000000007"/> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xL7-Qf-iI2"> |
| | | <rect key="frame" x="86" y="48.333333333333336" width="0.0" height="0.0"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="14"/> |
| | | <color key="textColor" red="0.46666666666666667" green="0.46666666666666667" blue="0.46666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | } |
| | | |
| | | @IBAction func bindPhoneAction(_ sender: Any) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = BindPhone_1_VC() |
| | | push(vc: vc) |
| | | } |
| | | |
| | | |
| | | @IBAction func updatePwdAction(_ sender: TapBtn) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = ForgotPasswordVC() |
| | | push(vc: vc) |
| | | } |
| | |
| | | |
| | | class SettingVC: BaseVC { |
| | | |
| | | @IBOutlet weak var btn_exchange: UIButton! |
| | | @IBOutlet weak var btn_logout: UIButton! |
| | | @IBOutlet weak var btn_dispel: TapBtn! |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | title = "设置" |
| | | |
| | | btn_exchange.isHidden = UserViewModel.getLoginInfo()?.accessToken.isEmpty ?? true |
| | | btn_logout.isHidden = UserViewModel.getLoginInfo()?.accessToken.isEmpty ?? true |
| | | btn_dispel.isHidden = UserViewModel.getLoginInfo()?.accessToken.isEmpty ?? true |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | } |
| | | |
| | | @IBAction func bindPhoneAction(_ sender: TapBtn) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = BindAccountVC() |
| | | push(vc: vc) |
| | | } |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="Safe area layout guides" minToolsVersion="9.0"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SettingVC" customModule="XQMuse" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="btn_dispel" destination="ta8-pP-aEf" id="cYz-J5-XFi"/> |
| | | <outlet property="btn_exchange" destination="yK9-0E-44J" id="Dlg-Zq-IOs"/> |
| | | <outlet property="btn_logout" destination="7uR-yB-LEb" id="scc-Tc-lfH"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | </connections> |
| | | </placeholder> |
| | |
| | | <rect key="frame" x="0.0" y="0.0" width="382" height="48"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="账号绑定" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NDO-GB-voX"> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="61.333333333333329" height="18"/> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="59.666666666666657" height="18"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/> |
| | | <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | <rect key="frame" x="0.0" y="48" width="382" height="48"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="清理缓存" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jnR-cP-A56"> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="61.333333333333329" height="18"/> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="59.666666666666657" height="18"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/> |
| | | <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | <rect key="frame" x="0.0" y="96" width="382" height="48"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="关于心泉" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="B6x-dn-wFm"> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="61.333333333333329" height="18"/> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="59.666666666666657" height="18"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/> |
| | | <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | <rect key="frame" x="0.0" y="144" width="382" height="48"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="注销账号" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tVJ-zS-iAQ"> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="61.333333333333329" height="18"/> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="59.666666666666657" height="18"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/> |
| | | <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | <rect key="frame" x="0.0" y="192" width="382" height="48"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="协议政策" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bcv-yx-5hJ"> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="61.333333333333329" height="18"/> |
| | | <rect key="frame" x="11.666666666666668" y="15" width="59.666666666666657" height="18"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/> |
| | | <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | alert(msg: "请先阅读并同意《会员用户协议》");return |
| | | } |
| | | |
| | | guard products.count != 0 else {return} |
| | | |
| | | let product = products[selectIndex] |
| | | |
| | |
| | | import RxRelay |
| | | import RxSwift |
| | | |
| | | class WatchHistoryViewModel:RefreshInnerModel<CourseModel>{ |
| | | class WatchHistoryViewModel:RefreshModel<CourseModel>{ |
| | | |
| | | let state = BehaviorRelay<Int>(value: 1) |
| | | var type = BehaviorRelay<WatchType>(value: .collect) |
| | | |
| | | override func api() -> (Observable<BaseResponse<BaseResponseList<CourseModel>>>)? { |
| | | override func api() -> (Observable<BaseResponse<[CourseModel]>>)? { |
| | | switch type.value { |
| | | case .history:Services.lookHistory(page: page, pageSize: 20, state: state.value) |
| | | case .collect:Services.myCollect(page: page, pageSize: 20, state: state.value) |
| | | case .payment:Services.myOrderCourse(page: page, pageSize: 20, state: state.value) |
| | | case .history:return Services.lookHistory(page: page, pageSize: 20, state: state.value) |
| | | case .collect:return Services.myCollect(page: page, pageSize: 20, state: state.value) |
| | | case .payment:return Services.myOrderCourse(page: page, pageSize: 20, state: state.value) |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | extension WatchHistoryDetailVC:UICollectionViewDelegate & UICollectionViewDataSource{ |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return viewModel.dataSource.value?.list.count ?? 0 |
| | | return viewModel.dataSource.value.count |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBannerCCell", for: indexPath) as! HomeRelaxBannerCCell |
| | | let m = viewModel.dataSource.value!.list[indexPath.row] |
| | | let m = viewModel.dataSource.value[indexPath.row] |
| | | cell.setCourseModel(m) |
| | | return cell |
| | | } |
| | |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | |
| | | let m = viewModel.dataSource.value!.list[indexPath.row] |
| | | let m = viewModel.dataSource.value[indexPath.row] |
| | | if viewModel.state.value == 1{ |
| | | let vc = HomeItemDetailVC(id: m.id) |
| | | let vc = HomeItemDetailVC(id: m.businessId) |
| | | JQ_currentViewController().jq_push(vc: vc) |
| | | }else{ |
| | | let vc = CourseDetialVC(courseId: m.id) |
| | | let vc = CourseDetialVC(courseId: m.businessId) |
| | | JQ_currentViewController().jq_push(vc: vc) |
| | | } |
| | | } |
| | |
| | | var generalPrice: Double = 0 |
| | | var headers = [String]() |
| | | var id: Int = 0 |
| | | var businessId:Int = 0 // 课程/音频id 收藏用 |
| | | var iosPrice: Int = 0 |
| | | var isBuy: ConditionType = .no |
| | | var isVip: ConditionType = .no |
| | |
| | | var appUserId: Int = 0 |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var currentEnergyValue: Int = 0 |
| | | var energyValue: Int = 0 |
| | | var delFlag: Int = 0 |
| | | var growthValue: Int = 0 |
| | | var id: Int = 0 |
| | |
| | | |
| | | class func loginByWechat(headImgUrl:String,nickname:String,sex:Int,wxOpenId:String)->Observable<BaseResponse<LoginUserInfoModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/appleLogin") |
| | | params.interface(url: "/auth/app/wxLogin") |
| | | .append(key: "headImgUrl", value: headImgUrl) |
| | | .append(key: "nickname", value: nickname) |
| | | .append(key: "sex", value: sex) |
| | | .append(key: "wxOpenId", value: wxOpenId) |
| | | .append(key: "apipost_id", value: "246d7806b0e26c") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | |
| | | /// Apple登录 【验证】 |
| | |
| | | .append(key: "name", value: name) |
| | | .append(key: "mail", value: mail) |
| | | .append(key: "apipost_id", value: "246d7806b0e26a") |
| | | return NetworkRequest.request(params: params, method: .post,encoding: (JSONEncoding.self as! ParameterEncoding), progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | |
| | | /// 发送验证码 |
| | |
| | | .append(key: "cellPhone", value: cellPhone) |
| | | .append(key: "captcha", value: captcha) |
| | | .append(key: "apipost_id", value: "246d7806b0e26b") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | |
| | | class func updatePwd(cellPhone:String,password:String,secretCode:String)->Observable<BaseResponse<SimpleModel>>{ |
| | |
| | | .append(key: "password", value: password.jq_md5String().uppercased()) |
| | | .append(key: "secret", value: secretCode) |
| | | .append(key: "apipost_id", value: "246d780670e266") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | } |
| | | |
| | |
| | | .append(key: "apipost_id", value: "25c3e3d0b0e160") |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | } |
| | | |
| | | class func watchMuse(id:Int,timeLook:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/user/user/app-user-viewing-history/saveViewingHistory") |
| | | .append(key: "id", value: id) |
| | | .append(key: "timeLook", value: timeLook) |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | } |
| | | } |
| | | |
| | | /// 课程 |
| | | extension Services{ |
| | | |
| | | class func watchClouse(chapterId:Int,isOver:Bool,minuteLook:Int,secondLook:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/user/user/app-user-viewing-history/saveCourseStudyHistory") |
| | | .append(key: "id", value: chapterId) |
| | | .append(key: "isOver", value: isOver) |
| | | .append(key: "isOver", value: isOver) |
| | | .append(key: "minuteLook", value: minuteLook) |
| | | .append(key: "secondLook", value: secondLook) |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | } |
| | | |
| | | //课程分类 |
| | | class func getCourseCategory()->Observable<BaseResponse<[CategoryModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/course/client/course/course/studyPage") |
| | | .append(key: "apipost_id", value: "2d2eb9d23993be") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | } |
| | | |
| | |
| | | /// 冥想等级 |
| | | class func userHeadingLevel()->Observable<BaseResponse<HeadingLevelModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/client/app-user/healingLevel") |
| | | params.interface(url: "/user/client/app-user/healingLevel") |
| | | .append(key: "apipost_id", value: "34d924b4b991f0") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | |
| | | //添加银行卡 |
| | | class func addBank(_ model:AddBankInfoVC.AddBankRequestModel)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/user/client/app-user-withdraw/withdraw") |
| | | params.interface(url: "/user/client/app-user-withdraw/addBank") |
| | | .append(key: "apipost_id", value: "361bdf11f992d1") |
| | | .append(dic: model.toRequest()) |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | |
| | | /// 观看历史 |
| | | /// - Parameters: |
| | | /// - state: 1冥想 2课程 |
| | | class func lookHistory(page:Int,pageSize:Int = 20,state:Int)->Observable<BaseResponse<BaseResponseList<CourseModel>>>{ |
| | | class func lookHistory(page:Int,pageSize:Int = 20,state:Int)->Observable<BaseResponse<[CourseModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/user/user/app-user-viewing-history/lookHistory") |
| | | .append(key: "apipost_id", value: "361bdf123992fb") |
| | |
| | | /// 我的收藏 |
| | | /// - Parameters: |
| | | /// - state: 1冥想 2课程 |
| | | class func myCollect(page:Int,pageSize:Int = 20,state:Int)->Observable<BaseResponse<BaseResponseList<CourseModel>>>{ |
| | | class func myCollect(page:Int,pageSize:Int = 20,state:Int)->Observable<BaseResponse<[CourseModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/course/client/course/course/myCollect") |
| | | .append(key: "apipost_id", value: "365e099bb9988b") |
| | |
| | | /// 我的购买 |
| | | /// - Parameters: |
| | | /// - state: 1冥想 2课程 |
| | | class func myOrderCourse(page:Int,pageSize:Int = 20,state:Int)->Observable<BaseResponse<BaseResponseList<CourseModel>>>{ |
| | | class func myOrderCourse(page:Int,pageSize:Int = 20,state:Int)->Observable<BaseResponse<[CourseModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/order/client/order/order/myOrderCourse") |
| | | .append(key: "apipost_id", value: "365f4fc1b99030") |
| | |
| | | } |
| | | |
| | | /// 兑换礼物 |
| | | class func exchangeGift(prizeId:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | | class func exchangeGift(prizeId:Int)->Observable<BaseResponse<String>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/user/client/app-user-tree/exchange") |
| | | .append(key: "apipost_id", value: "2e76346339912a") |
| | |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | .interface(url: "/system/system/common-question/getQrCode") |
| | | .append(key: "apipost_id", value: "2fcbf1daf99704") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: false) |
| | | } |
| | | |
| | | /// 问题列表 |
| | |
| | | .append(key: "apipost_id", value: "36618045f991c4") |
| | | .append(key: "pageCurr", value: page) |
| | | .append(key: "pageSize", value: pageSize) |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func addQuestion(content:String,meditationId:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | |
| | | |
| | | class CountdownChooseListView: UIView,JQNibView{ |
| | | |
| | | enum CountDownStatus { |
| | | case close |
| | | case choose(Int) |
| | | } |
| | | |
| | | @IBOutlet weak var btn_cancel: UIButton! |
| | | @IBOutlet weak var stackView: UIStackView! |
| | | @IBOutlet weak var view_content: UIView! |
| | |
| | | @IBOutlet weak var tf_input: UITextField! |
| | | private var disposeBag = DisposeBag() |
| | | private var clouse:((Int)->Void)? |
| | | private var status:CountDownStatus = .close |
| | | |
| | | var numberMinutes = 1 |
| | | |
| | | override func awakeFromNib() { |
| | |
| | | |
| | | @IBAction func cancelAction(_ sender: UIButton) { |
| | | endEditing(true) |
| | | clouse?(numberMinutes) |
| | | |
| | | if case .choose(let v) = status { |
| | | clouse?(v) |
| | | } |
| | | |
| | | cons_bottom.constant = -JQ_ScreenH |
| | | UIView.animate(withDuration: 0.4) { |
| | | self.alpha = 0 |
| | |
| | | label.textColor = UIColor(hexString: "#8AAE65") |
| | | |
| | | switch label.text { |
| | | case "关闭倒计时":numberMinutes = -1;break |
| | | case "自定义","分钟":numberMinutes = self.tf_input.text!.int ?? 1;break |
| | | case "关闭倒计时": |
| | | numberMinutes = -1 |
| | | status = .close |
| | | case "自定义","分钟": |
| | | numberMinutes = self.tf_input.text!.int ?? 1 |
| | | status = .choose(numberMinutes) |
| | | default: |
| | | numberMinutes = label.text?.jq_filterNum().int ?? 0 |
| | | self.tf_input.text = numberMinutes.string |
| | | |
| | | status = .choose(numberMinutes) |
| | | } |
| | | } |
| | | |
| | |
| | | return p |
| | | }() |
| | | |
| | | required init(url:String? = nil,autoPlay:Bool = false,placeHoderImageUrl:String? = nil) { |
| | | required init(url:String? = nil,autoPlay:Bool = false,placeHoderImageUrl:String? = nil,delegate:CLPlayerDelegate? = nil) { |
| | | super.init(frame: .zero) |
| | | addSubview(player) |
| | | player.delegate = self |
| | | player.delegate = delegate |
| | | player.snp.makeConstraints { make in |
| | | make.edges.equalToSuperview() |
| | | } |
| | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | } |
| | | |
| | | extension VideoView:CLPlayerDelegate{ |
| | | |
| | | } |
| | |
| | | private var label_name:UILabel! |
| | | private var btn_handle:UIButton! |
| | | private var btn_handleClose:UIButton! |
| | | private var audioPlayer:AudioPlayer! |
| | | private(set) var audioPlayer:AudioPlayer! |
| | | private var isAniLoop:Bool = false |
| | | private var meditationModel:MeditationModel?{ |
| | | didSet{ |
| | |
| | | make.bottom.equalToSuperview().offset(-(tabBarHeight)) |
| | | } |
| | | vc.startRunloopAni() |
| | | } |
| | | } |
| | | } |
| | | |
| | | static func hidden(){ |
| | | if let tabBarVC = JQ_currentViewController().navigationController?.tabBarController as? BaseTabBarVC{ |
| | | if let vc = tabBarVC.children.filter({$0 is PayMusicVC}).first{ |
| | | AudioPlayer.destroy() |
| | | vc.view.removeFromSuperview() |
| | | vc.removeFromParent() |
| | | } |
| | | } |
| | | } |
| | |
| | | self.playIndex = firstPlayIndex |
| | | self.meditationModel = model |
| | | |
| | | let urls = model.backgroundUrl.components(separatedBy: ",").map { str in |
| | | return URL(string: str)! |
| | | let urls = model.meditationMusicList.map { url in |
| | | return URL(string: url)! |
| | | } |
| | | |
| | | if urls.count == 0{ |
| | | alertError(msg: "数据获取失败");return |
| | | } |
| | | |
| | | let masterUrl = URL(string: model.tutorAudioUrl) |
| | |
| | | |
| | | |
| | | if loadTime >= totalTime{ |
| | | if weakSelf.playIndex <= urls.count - 1{ |
| | | if weakSelf.playIndex < urls.count - 1{ |
| | | weakSelf.next() |
| | | weakSelf.delegate?.playState(.next) |
| | | }else{ |
| | | weakSelf.delegate?.playState(.end) |
| | | PayMusicVC.hidden() |
| | | MPNowPlayingInfoCenter.default().nowPlayingInfo = nil |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | func next(){ |
| | | if UserDefaultSettingViewModel.getSetting()?.playModel == .line{ |
| | | playIndex += 1 |
| | | } |
| | | |
| | | let index = min((urls.count - 1), playIndex) |
| | | bgmPlayer?.replaceCurrentItem(with: AVPlayerItem(url: urls[index])) |
| | | bgmPlayer?.play() |
| | |
| | | if newTimes <= 0{ |
| | | weakSelf.times.accept(nil) |
| | | weakSelf.stopTimer() |
| | | weakSelf.bgmPlayer?.pause() |
| | | weakSelf.masterPlayer?.pause() |
| | | weakSelf.scenePlayer?.pause() |
| | | MPNowPlayingInfoCenter.default().nowPlayingInfo = nil |
| | | AudioPlayer.destroy() |
| | | PayMusicVC.hidden() |
| | | }else{ |
| | | weakSelf.times.accept(newTimes) |
| | | } |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | |
| | | <subviews> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="e5F-Yd-WS5"> |
| | | <rect key="frame" x="11" y="43.666666666666657" width="50" height="50"/> |
| | | <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" constant="50" id="Iyf-X2-uW5"/> |
| | | <constraint firstAttribute="height" constant="50" id="kwz-cW-a3N"/> |
| | |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="所需能量值:0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zFc-Mw-j6J"> |
| | | <rect key="frame" x="71" y="86" width="68" height="12"/> |
| | | <rect key="frame" x="71" y="86" width="66.666666666666686" height="12"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/> |
| | | <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | self.taskListView.setTreeInfoModel(m) |
| | | |
| | | //检查hash,进行同步 |
| | | if m.toJSON()?.jq_hash() != self.treeInfoModel?.toJSON()?.jq_hash(){ |
| | | // if m.toJSON()?.jq_hash() != self.treeInfoModel?.toJSON()?.jq_hash(){ |
| | | self.treeInfoModel = m |
| | | self.updateTreeInfo() |
| | | } |
| | | |
| | | self.updateAni(false) |
| | | try? self.cacheTreeInfoModel.save(m) |
| | | // } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | |
| | | // if treeLevel.rawValue != treeInfoModel?.treeLevelType.rawValue{ |
| | | // treeLevel = treeInfoModel!.treeLevelType |
| | | // } |
| | | |
| | | icon_energy.text = String(format: "当前能量值:%ld", treeInfoModel!.currentEnergyValue) |
| | | icon_energy.text = String(format: "当前能量值:%ld", treeInfoModel!.energyValue) |
| | | setProgress(current: treeInfoModel!.growthValue, total: treeInfoModel!.nextLevel) |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | taskListView.signSuccess {[weak self] in |
| | | self?.getTreeData() |
| | | } |
| | | } |
| | | |
| | | // 0 - 100 |
| | |
| | | |
| | | //能量明细 |
| | | @IBAction func energyDetailAction(_ sender: TapBtn) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = TreeTeskDetailVC() |
| | | push(vc: vc) |
| | | } |
| | | |
| | | //兑换 |
| | | @IBAction func exchangeAction(_ sender: TapBtn) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | let vc = TreeTeskEnergyExchangeVC() |
| | | push(vc: vc) |
| | | } |
| | | |
| | | @IBAction func wateringAction(_ sender: UIButton) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | |
| | | sender.isUserInteractionEnabled = false |
| | | |
| | | if treeInfoModel == nil {return} |
| | | |
| | | guard treeInfoModel!.currentEnergyValue != 0 else{ |
| | | guard treeInfoModel!.energyValue != 0 else{ |
| | | alert(msg: "已经没有能量值了,快去做任务吧");return |
| | | } |
| | | |
| | |
| | | weakSelf.voicePlayer.play() |
| | | } |
| | | weakSelf.updateAni() |
| | | weakSelf.getTreeData() |
| | | return |
| | | } |
| | | weakSelf.treeInfoModel?.currentEnergyValue = 0 |
| | | |
| | | weakSelf.treeInfoModel?.growthValue = m.growthValue |
| | | weakSelf.treeInfoModel?.energyValue = 0 |
| | | weakSelf.treeInfoModel?.nextLevel = m.nextLevel |
| | | weakSelf.updateTreeInfo() |
| | | } |
| | |
| | | push(vc: vc) |
| | | } |
| | | |
| | | private func updateAni(){ |
| | | private func updateAni(_ needAni:Bool = true){ |
| | | let treeLevel = treeInfoModel?.treeLevelType ?? .level_1 |
| | | |
| | | guard let animateUrl = Bundle.main.url(forResource: treeLevel.aniResource, withExtension: "png") else {return} |
| | |
| | | make.height.equalTo(731 * scale) |
| | | } |
| | | |
| | | UIView.animate(withDuration: 0.6) { |
| | | let duration = needAni ? 0.6:0 |
| | | UIView.animate(withDuration: duration) { |
| | | self.aPNGTreeImageView?.alpha = 0 |
| | | |
| | | }completion: { state in |
| | |
| | | CommonAlertView.show(title: "提示", attribute: attribute, isSingle: false, cancelStr: "再想想", completeStr: "确认") { state in |
| | | if state{ |
| | | Services.exchangeGift(prizeId: m.id).subscribe(onNext: {data in |
| | | TreeTeskExchangeSuccessView.show() |
| | | TreeTeskExchangeSuccessView.show(code: data.data ?? "",customerImage: self.image_qrCode.image ?? UIImage()) |
| | | self.viewModel.beginRefresh() |
| | | }).disposed(by: self.disposeBag) |
| | | } |
| | | } |
| | |
| | | class TreeTeskExchangeSuccessView: UIView,JQNibView{ |
| | | @IBOutlet weak var view_container: UIView! |
| | | @IBOutlet weak var image_qrCode: UIImageView! |
| | | @IBOutlet weak var label_code: UILabel! |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | |
| | | image_qrCode.addGestureRecognizer(longPress) |
| | | } |
| | | |
| | | static func show(){ |
| | | static func show(code:String,customerImage:UIImage){ |
| | | let view = TreeTeskExchangeSuccessView.jq_loadNibView() |
| | | sceneDelegate?.window?.addSubview(view) |
| | | view.label_code.text = "领取验证码:\(code)" |
| | | view.image_qrCode.image = customerImage |
| | | view.frame = sceneDelegate?.window?.frame ?? .zero |
| | | |
| | | UIView.animate(withDuration: 0.5, delay: 0.1, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.0, options: .curveEaseIn) { |
| | |
| | | </constraints> |
| | | <connections> |
| | | <outlet property="image_qrCode" destination="GQk-cT-1IF" id="U2k-zg-3wi"/> |
| | | <outlet property="label_code" destination="psN-sL-6pq" id="IdT-sk-KdH"/> |
| | | <outlet property="view_container" destination="4ru-7s-yUN" id="C6v-VX-yVc"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="65" y="21"/> |
| | |
| | | @IBOutlet weak var tap_sign: TapBtn! |
| | | |
| | | private var clouse:((TreeTeskListSwipe)->Void)? |
| | | private var signClouse:(()->Void)? |
| | | private var disposeBag = DisposeBag() |
| | | |
| | | private var treeInfoModel:TreeInfoModel? |
| | |
| | | self.clouse = clouse |
| | | } |
| | | |
| | | func signSuccess(signClouse:@escaping ()->Void){ |
| | | self.signClouse = signClouse |
| | | } |
| | | |
| | | |
| | | func setTreeInfoModel(_ model:TreeInfoModel){ |
| | | self.treeInfoModel = model |
| | |
| | | } |
| | | |
| | | @IBAction func signAction(_ sender: TapBtn) { |
| | | guard sceneDelegate!.checkisLoginState() else {return} |
| | | |
| | | tap_sign.isUserInteractionEnabled = false |
| | | label_sign.text = "已签到" |
| | | view_sign.backgroundColor = .gray.withAlphaComponent(0.1) |
| | | label_sign.textColor = .white |
| | | view_sign_cricle.jq_borderColor = .gray.withAlphaComponent(0.9) |
| | | Services.treeTaskSign().subscribe(onNext: {[weak self] _ in |
| | | guard let weakSelf = self else { return } |
| | | weakSelf.signClouse?() |
| | | weakSelf.tap_sign.isUserInteractionEnabled = false |
| | | weakSelf.label_sign.text = "已签到" |
| | | weakSelf.view_sign.backgroundColor = .gray.withAlphaComponent(0.1) |
| | | weakSelf.label_sign.textColor = .white |
| | | weakSelf.view_sign_cricle.jq_borderColor = .gray.withAlphaComponent(0.9) |
| | | |
| | | let imageView = UIImageView(image: UIImage(named: "icon_signSuccess")) |
| | | imageView.transform = .init(scaleX: 0.1, y: 0.1) |
| | |
| | | imageView.removeFromSuperview() |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | |
| | | |
| | | } |
| | | |
| | | @IBAction func toMuse(_ sender: TapBtn) { |
| | |
| | | JQ_currentViewController().present(loginNav, animated: true) |
| | | } |
| | | |
| | | func loginSuccess(){ |
| | | //判断是否需要登录 |
| | | func checkisLoginState()->Bool{ |
| | | if UserViewModel.getLoginInfo()?.accessToken.isEmpty ?? true{ |
| | | sceneDelegate?.needLogin() |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | |
| | | func loginSuccess(){ |
| | | NotificationCenter.default.post(name: LoginSuccess_Noti, object: nil) |
| | | } |
| | | |
| | | func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { |