| | |
| | | 13649E9C2C00304C001B04E2 /* ListenFight_lesson_1_CCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13649E9A2C00304C001B04E2 /* ListenFight_lesson_1_CCell.swift */; }; |
| | | 13649E9D2C00304C001B04E2 /* ListenFight_lesson_1_CCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13649E9B2C00304C001B04E2 /* ListenFight_lesson_1_CCell.xib */; }; |
| | | 137CB4292BFF505800D32862 /* HomeListenFightVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 137CB4282BFF505800D32862 /* HomeListenFightVC.swift */; }; |
| | | 13812B9C2C0F02B700905CCE /* VoicePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13812B9B2C0F02B600905CCE /* VoicePlayer.swift */; }; |
| | | 138964002BFDF98200AEDCD9 /* StudyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 138963FE2BFDF98200AEDCD9 /* StudyVC.swift */; }; |
| | | 138964012BFDF98200AEDCD9 /* StudyVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 138963FF2BFDF98200AEDCD9 /* StudyVC.xib */; }; |
| | | 13A049FF2C058B1400F1F52E /* HomeListenFight_lesson_5_VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A049FE2C058B1400F1F52E /* HomeListenFight_lesson_5_VC.swift */; }; |
| | |
| | | 13649E9A2C00304C001B04E2 /* ListenFight_lesson_1_CCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListenFight_lesson_1_CCell.swift; sourceTree = "<group>"; }; |
| | | 13649E9B2C00304C001B04E2 /* ListenFight_lesson_1_CCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ListenFight_lesson_1_CCell.xib; sourceTree = "<group>"; }; |
| | | 137CB4282BFF505800D32862 /* HomeListenFightVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeListenFightVC.swift; sourceTree = "<group>"; }; |
| | | 13812B9B2C0F02B600905CCE /* VoicePlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoicePlayer.swift; sourceTree = "<group>"; }; |
| | | 138963FE2BFDF98200AEDCD9 /* StudyVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyVC.swift; sourceTree = "<group>"; }; |
| | | 138963FF2BFDF98200AEDCD9 /* StudyVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StudyVC.xib; sourceTree = "<group>"; }; |
| | | 13A049FE2C058B1400F1F52E /* HomeListenFight_lesson_5_VC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeListenFight_lesson_5_VC.swift; sourceTree = "<group>"; }; |
| | |
| | | children = ( |
| | | 1302783E2BFD978900DDCE81 /* Config.swift */, |
| | | 1302783F2BFD978900DDCE81 /* Enums.swift */, |
| | | 13812B9B2C0F02B600905CCE /* VoicePlayer.swift */, |
| | | ); |
| | | path = Config; |
| | | sourceTree = "<group>"; |
| | |
| | | 13A04A032C05BFDC00F1F52E /* HomeListenGame_2_VC.swift in Sources */, |
| | | 130278592BFD985E00DDCE81 /* BitrhdayPickerView.swift in Sources */, |
| | | 133386382C007E91002EE788 /* HomeListenFight_lesson_2_VC.swift in Sources */, |
| | | 13812B9C2C0F02B700905CCE /* VoicePlayer.swift in Sources */, |
| | | 1302787B2BFD9ED600DDCE81 /* MarketContentVC.swift in Sources */, |
| | | 13649E9C2C00304C001B04E2 /* ListenFight_lesson_1_CCell.swift in Sources */, |
| | | 13EEB8A02BFF28A7002996FC /* HomeListenVC.swift in Sources */, |
New file |
| | |
| | | { |
| | | "images" : [ |
| | | { |
| | | "filename" : "icon_answer.png", |
| | | "idiom" : "universal", |
| | | "scale" : "1x" |
| | | }, |
| | | { |
| | | "filename" : "icon_answer@2x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "2x" |
| | | }, |
| | | { |
| | | "idiom" : "universal", |
| | | "scale" : "3x" |
| | | } |
| | | ], |
| | | "info" : { |
| | | "author" : "xcode", |
| | | "version" : 1 |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // VoicePlayer.swift |
| | | // DolphinEnglishLearnStudent |
| | | // |
| | | // Created by 无故事王国 on 2024/6/4. |
| | | // |
| | | |
| | | import Foundation |
| | | import AVFAudio |
| | | |
| | | |
| | | /// 音频播放器 |
| | | class VoicePlayer:NSObject{ |
| | | /// 缓存地址 |
| | | private let voiceCacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("voices") |
| | | private static var _sharedInstance: VoicePlayer? |
| | | private var player:AVAudioPlayer? |
| | | |
| | | //是否正在播放 |
| | | var isPlaying:Bool{return player?.isPlaying ?? false} |
| | | //播放完成回调 |
| | | private var playComplete:(()->Void)? |
| | | |
| | | |
| | | /// 单例 |
| | | /// - Returns: <#description#> |
| | | class func share() -> VoicePlayer { |
| | | guard let instance = _sharedInstance else { |
| | | _sharedInstance = VoicePlayer() |
| | | try? FileManager.default.createDirectory(at: _sharedInstance!.voiceCacheDirectory, withIntermediateDirectories: true) |
| | | return _sharedInstance! |
| | | } |
| | | return instance |
| | | } |
| | | |
| | | private override init() {} // 私有化init方法 |
| | | |
| | | ///销毁单例对象 |
| | | class func destroy() { |
| | | _sharedInstance = nil |
| | | } |
| | | |
| | | /// 播放语音 |
| | | /// - Parameter url: Https的语音地址 |
| | | func playerAt(url:String?){ |
| | | guard let u = url else {return} |
| | | if player?.isPlaying ?? false{ |
| | | VoicePlayer.share().playComplete?() //先通知完成播放 |
| | | player?.stop() |
| | | } |
| | | |
| | | //文件存在:直接播放缓存路径的语音 |
| | | let fileURL = voiceCacheDirectory.appendingPathComponent(URL(fileURLWithPath: u).lastPathComponent).droppedScheme() |
| | | if FileManager.default.fileExists(atPath: fileURL!.absoluteString){ |
| | | player = try? AVAudioPlayer(contentsOf: fileURL!) |
| | | player?.delegate = self |
| | | player?.play() |
| | | }else{ |
| | | //文件不存在:执行下载 |
| | | let downloadTask = URLSession.shared.downloadTask(with: URL(string: u)!) { tempLocalUrl, response, error in |
| | | if let tempLocalUrl = tempLocalUrl, error == nil { |
| | | do { |
| | | let finalCacheUrl = self.voiceCacheDirectory.appendingPathComponent(URL(fileURLWithPath: u).lastPathComponent) |
| | | try FileManager.default.moveItem(at: tempLocalUrl, to: finalCacheUrl) |
| | | self.player = try? AVAudioPlayer(contentsOf: finalCacheUrl) |
| | | self.player?.delegate = self |
| | | self.player?.play() |
| | | } catch { |
| | | print("视频缓存失败:catch") |
| | | } |
| | | } else { |
| | | print("视频缓存失败:\(error?.localizedDescription ?? "")") |
| | | } |
| | | } |
| | | downloadTask.resume() |
| | | } |
| | | } |
| | | |
| | | func playerEnd(){ |
| | | player?.stop() |
| | | playComplete?() |
| | | |
| | | } |
| | | |
| | | func playEnd(course:@escaping ()->Void){ |
| | | self.playComplete = course |
| | | } |
| | | } |
| | | |
| | | extension VoicePlayer:AVAudioPlayerDelegate{ |
| | | func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { |
| | | VoicePlayer.share().playComplete?() |
| | | } |
| | | |
| | | func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: (any Error)?) { |
| | | print("播放错误") |
| | | } |
| | | } |
| | |
| | | var expressNumber: String = "" |
| | | var expressTime: String = "" |
| | | var goodsId: Int = 0 |
| | | var goodsName: String = "" |
| | | var id: Int = 0 |
| | | var insertTime: String = "" |
| | | var integral: Int = 0 |
| | | var orderNumber: String = "" |
| | | var state: Int = 0 |
| | | var state: Int = 0 //订单状态1待发货2已发货3已完成 |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userId: Int = 0 |
| | | var goodsType = [String]() |
| | | var coverImg:String = "" |
| | | } |
| | | |
| | | struct StudyGamesModel:HandyJSON{ |
| | |
| | | |
| | | struct StudyGamesRecordModel:HandyJSON{ |
| | | var accuracy: Int = 0 |
| | | var createBy: String? |
| | | var createTime: String? |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var disabled: Bool = false |
| | | var gameDifficulty: Int = 0 |
| | | var gameId: Int = 0 |
| | | var gameName: String? |
| | | var gameName: String = "" |
| | | var id: Int = 0 |
| | | var updateBy: String? |
| | | var updateTime: String? |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userId: Int = 0 |
| | | var useTime: Int = 0 |
| | | } |
| | | |
| | | struct StudyDataRecordModel:HandyJSON{ |
| | | var answer: Int = 0 |
| | | var createBy: String? |
| | | var createTime: String? |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var day: Int = 0 |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | |
| | | var surplus: Int = 0 |
| | | var todayStudy: Int = 0 |
| | | var totalStudy: Int = 0 |
| | | var updateBy: String? |
| | | var updateTime: String? |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userId: Int = 0 |
| | | var week: Int = 0 |
| | | var weekStudy: Int = 0 |
| | |
| | | var type = 0 |
| | | var week = 0 |
| | | } |
| | | |
| | | class Listen1Model:HandyJSON{ |
| | | var data:Listen1DataModel? |
| | | var subjectList = [Listen1SubModel]() |
| | | |
| | | required init(){} |
| | | } |
| | | struct Listen1DataModel:HandyJSON{ |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var day: Int = 0 |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | | var integral: Int = 0 |
| | | var isVip: Int = 0 |
| | | var studyId: Int = 0 |
| | | var subject: String = "" |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var week: Int = 0 |
| | | } |
| | | |
| | | class Listen1SubModel:HandyJSON{ |
| | | |
| | | required init() {} |
| | | |
| | | var correct: String = "" |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var disabled: Bool = false |
| | | var english: String = "" |
| | | var error: String = "" |
| | | var id: Int = 0 |
| | | var img: String = "" |
| | | var name: String = "" |
| | | var state: Int = 0 |
| | | var type: String = "" |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | } |
| | | |
| | | struct Listen4Model:HandyJSON{ |
| | | var data = [Listen4DataModel]() |
| | | } |
| | | |
| | | struct Listen4DataModel:HandyJSON{ |
| | | var answerSubject: Int = 0 |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var day: Int = 0 |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | | var integral: Int = 0 |
| | | var isAnswer: Int = 0 |
| | | var isVip: Int = 0 |
| | | var studyId: Int = 0 |
| | | var subject: Int = 0 |
| | | var subjectList = [Listen1SubModel]() |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var week: Int = 0 |
| | | } |
| | |
| | | class HomeListenFight_lesson_1_VC: BaseVC { |
| | | |
| | | private var viewModel = FightAnswerViewModel() |
| | | private var listen1Model:Listen1Model! |
| | | private var randomElement:Listen1SubModel? |
| | | private var page:Int! |
| | | var rootViewModel:HomeListenFightViewModel! |
| | | |
| | | private lazy var menuView:StudyHandleView = { |
| | | let menu = StudyHandleView.jq_loadNibView() |
| | | menu.listenType = .lesson1 |
| | | return menu |
| | | }() |
| | | private var menuView:StudyHandleView = StudyHandleView.jq_loadNibView() |
| | | |
| | | private lazy var collectionView:UICollectionView = { |
| | | let flowLayout = UICollectionViewFlowLayout() |
| | |
| | | return collection |
| | | }() |
| | | |
| | | required init(page:Int,listen1Model:Listen1Model){ |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.page = page |
| | | self.listen1Model = listen1Model |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | navigationItem.titleView = UIView() |
| | | collectionView.reloadData() |
| | | |
| | | menuView.listenType = .lesson1 |
| | | |
| | | // collectionView.isUserInteractionEnabled = false |
| | | //制造随机 |
| | | randomElement = listen1Model.subjectList.randomElement() |
| | | menuView.vioceSoundUrl = randomElement?.correct |
| | | |
| | | VoicePlayer.share().playEnd {[weak self] in |
| | | self?.menuView.reset() |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | guard let index = index else { return } |
| | | |
| | | //判断选中是否正确逻辑 |
| | | |
| | | if let cell = self?.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: index) as? ListenFight_lesson_1_CCell{ |
| | | var answer:Fight_lessonType = .none |
| | | |
| | | answer = .success |
| | | if self?.randomElement?.id == self?.listen1Model.subjectList[index.row].id{ |
| | | answer = .success |
| | | self?.rootViewModel.correctNum += 1 |
| | | }else{ |
| | | answer = .fail |
| | | self?.rootViewModel.errorNum += 1 |
| | | } |
| | | |
| | | switch answer { |
| | | case .success: |
| | |
| | | self?.answerSuccess(cell) |
| | | case .fail: |
| | | self?.viewModel.answerType.accept(.fail) |
| | | self?.answerFail() |
| | | // self?.collectionView.isUserInteractionEnabled = false |
| | | self?.answerFail(errorSound: self?.listen1Model.subjectList[index.row].error) |
| | | default:break |
| | | } |
| | | } |
| | |
| | | //回答正确 |
| | | private func answerSuccess(_ cell:ListenFight_lesson_1_CCell){ |
| | | menuView.snp.removeConstraints() |
| | | collectionView.isUserInteractionEnabled = false |
| | | // collectionView.isUserInteractionEnabled = false |
| | | let v = cell.view_topHandle.convert(cell.bounds, to: self.view) |
| | | UIView.animate(withDuration: 0.3) { |
| | | self.menuView.snp.updateConstraints { make in |
| | |
| | | self.collectionView.reloadData() |
| | | DispatchQueue.main.asyncAfter(deadline: .now()+2){ |
| | | NotificationCenter.default.post(name: NextLession_Noti, object: nil) |
| | | self.collectionView.isUserInteractionEnabled = true |
| | | // self.collectionView.isUserInteractionEnabled = true |
| | | self.viewModel.answerType.accept(.none) |
| | | self.viewModel.selectIndex.accept(nil) |
| | | self.rootViewModel.answerItems[self.page] = self.listen1Model |
| | | } |
| | | } |
| | | } |
| | | |
| | | private func answerFail(){ |
| | | private func answerFail(errorSound:String?){ |
| | | self.collectionView.reloadData() |
| | | VoicePlayer.share().playerAt(url: errorSound) |
| | | } |
| | | } |
| | | |
| | |
| | | }else{ |
| | | cell.setState(state: .none) |
| | | } |
| | | cell.setListen1SubModel(listen1Model.subjectList[indexPath.row]) |
| | | return cell |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 4 |
| | | return min(4,listen1Model.subjectList.count) |
| | | } |
| | | } |
| | |
| | | AwardListView.show(items: data.data ?? []) {[weak self] model in |
| | | let vc = MarketContentVC(goodsId: model.id) |
| | | self?.push(vc: vc) |
| | | }closeClouse: {[weak self] in |
| | | let listenMenuVC = HomeListenMenuVC() |
| | | listenMenuVC.title = "第一年学习周目选择" |
| | | self?.push(vc: listenMenuVC) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | |
| | | |
| | | class ListenFight_lesson_1_CCell: UICollectionViewCell { |
| | | |
| | | @IBOutlet weak var label_title: UILabel! |
| | | @IBOutlet weak var image_state: UIImageView! |
| | | @IBOutlet weak var image_cover: UIImageView! |
| | | @IBOutlet weak var view_topHandle: UIView! |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | image_state.alpha = 0 |
| | | image_state.transform = .init(scaleX: 0.1, y: 0.1) |
| | | label_title.isHidden = true |
| | | } |
| | | |
| | | func setState(state:Fight_lessonType){ |
| | |
| | | UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.4, options: .layoutSubviews) { |
| | | self.image_state.alpha = 1 |
| | | self.image_state.transform = .init(scaleX: 1, y: 1) |
| | | UIView.animate(withDuration: 0.5, delay: 3.0) { |
| | | self.image_state.alpha = 0 |
| | | } |
| | | } |
| | | case .none: |
| | | image_state.alpha = 0 |
| | | image_state.transform = .init(scaleX: 0.1, y: 0.1) |
| | | } |
| | | } |
| | | |
| | | func setListen1SubModel(_ model:Listen1SubModel){ |
| | | image_cover.sd_setImage(with: URL(string: model.img)) |
| | | } |
| | | } |
| | |
| | | <subviews> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JdK-rh-KJI"> |
| | | <rect key="frame" x="5" y="5" width="435" height="40"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rgH-1a-mKt"> |
| | | <rect key="frame" x="0.0" y="0.0" width="435" height="40"/> |
| | | <color key="backgroundColor" red="0.53725490196078429" green="0.52941176470588236" blue="0.49411764705882355" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/> |
| | | <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | </subviews> |
| | | <color key="backgroundColor" red="0.83137254900000002" green="0.82352941180000006" blue="0.80392156859999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="40" id="1mb-ik-h6n"/> |
| | | <constraint firstAttribute="trailing" secondItem="rgH-1a-mKt" secondAttribute="trailing" id="Zjf-E9-9in"/> |
| | | <constraint firstAttribute="bottom" secondItem="rgH-1a-mKt" secondAttribute="bottom" id="aMm-rB-Ltu"/> |
| | | <constraint firstItem="rgH-1a-mKt" firstAttribute="leading" secondItem="JdK-rh-KJI" secondAttribute="leading" id="eZG-zI-A7g"/> |
| | | <constraint firstItem="rgH-1a-mKt" firstAttribute="top" secondItem="JdK-rh-KJI" secondAttribute="top" id="pG4-rt-Gkh"/> |
| | | </constraints> |
| | | </view> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="bdL-d4-7NQ"> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="bdL-d4-7NQ"> |
| | | <rect key="frame" x="5" y="45" width="435" height="329"/> |
| | | </imageView> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kkd-SI-bwq"> |
| | |
| | | </constraints> |
| | | <size key="customSize" width="445" height="379"/> |
| | | <connections> |
| | | <outlet property="image_cover" destination="bdL-d4-7NQ" id="r4U-gR-Ehg"/> |
| | | <outlet property="image_state" destination="kkd-SI-bwq" id="oOC-yo-jjk"/> |
| | | <outlet property="label_title" destination="rgH-1a-mKt" id="8rB-l0-3TW"/> |
| | | <outlet property="view_topHandle" destination="JdK-rh-KJI" id="3e6-NI-AsQ"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="232.3170731707317" y="103.47457627118645"/> |
| | |
| | | |
| | | @IBOutlet weak var img_cover: UIImageView! |
| | | @IBOutlet weak var view_container: UIView! |
| | | @IBOutlet weak var btn_play: UIButton! |
| | | @IBOutlet weak var btn_playing: UIButton! |
| | | |
| | | private var model:Listen1SubModel! |
| | | private var playAtClouse:((IndexPath)->Void)? |
| | | var indexPath:IndexPath! |
| | | |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | view_container.jq_addShadows(shadowColor: .black.withAlphaComponent(0.31), corner: 8, radius: 3, offset: CGSize(width: 0, height: 1), opacity: 1) |
| | | } |
| | | |
| | | func setModel(_ model:Listen1SubModel,isplaying:Bool){ |
| | | self.model = model |
| | | self.btn_play.alpha = (isplaying ? 0:1) |
| | | } |
| | | |
| | | func palyVoiceAt(_ clouse:@escaping(IndexPath)->Void){ |
| | | self.playAtClouse = clouse |
| | | } |
| | | |
| | | |
| | | @IBAction func playAction(_ sender: Any) { |
| | | VoicePlayer.share().playerAt(url: model.correct ?? "") |
| | | playAtClouse?(indexPath) |
| | | } |
| | | } |
| | |
| | | <rect key="frame" x="104" y="10" width="32" height="32"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="icon_play"/> |
| | | <connections> |
| | | <action selector="playAction:" destination="gTV-IL-0wX" eventType="touchUpInside" id="IWn-Zu-bCh"/> |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9Dc-Ns-SMP"> |
| | | <rect key="frame" x="25" y="12.5" width="27" height="27"/> |
| | |
| | | </constraints> |
| | | <size key="customSize" width="630" height="554"/> |
| | | <connections> |
| | | <outlet property="btn_play" destination="7yc-PU-RgV" id="b2b-5W-bGC"/> |
| | | <outlet property="btn_playing" destination="9Dc-Ns-SMP" id="PsY-Nd-d5z"/> |
| | | <outlet property="img_cover" destination="n5n-eb-5xI" id="Wk5-s2-MQj"/> |
| | | <outlet property="view_container" destination="qxz-6s-e5b" id="Ikx-kW-UkZ"/> |
| | | </connections> |
| | |
| | | @IBOutlet weak var img_cover: UIImageView! |
| | | @IBOutlet weak var view_container: UIView! |
| | | @IBOutlet weak var img_state: UIImageView! |
| | | @IBOutlet weak var btn_handle: UIButton! |
| | | @IBOutlet weak var btn_voice: UIButton! |
| | | @IBOutlet weak var btn_play: UIButton! |
| | | private var model:Listen1SubModel? |
| | | var indexPath:IndexPath! |
| | | private var playAtIndexClouse:((IndexPath)->Void)? |
| | | |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | view_container.jq_addShadows(shadowColor: .black.withAlphaComponent(0.31), corner: 8, radius: 3, offset: CGSize(width: 0, height: 1), opacity: 1) |
| | | } |
| | | |
| | | func setModel(_ m:Listen1SubModel){ |
| | | model = m |
| | | img_cover.sd_setImage(with: URL(string: m.img)) |
| | | } |
| | | |
| | | func playAtIndex(clouse:@escaping(IndexPath)->Void){ |
| | | self.playAtIndexClouse = clouse |
| | | |
| | | } |
| | | |
| | | @IBAction func playAction(_ sender: UIButton) { |
| | | if let m = model{ |
| | | btn_play.isHidden = true |
| | | VoicePlayer.share().playerAt(url: m.correct) |
| | | playAtIndexClouse?(indexPath) |
| | | VoicePlayer.share().playEnd { |
| | | self.btn_play.isHidden = false |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | <rect key="frame" x="104" y="10" width="32" height="32"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="icon_play"/> |
| | | <connections> |
| | | <action selector="playAction:" destination="gTV-IL-0wX" eventType="touchUpInside" id="FV8-uE-yj8"/> |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kgj-Ss-D90"> |
| | | <rect key="frame" x="65" y="12.5" width="27" height="27"/> |
| | |
| | | </constraints> |
| | | <size key="customSize" width="597" height="510"/> |
| | | <connections> |
| | | <outlet property="btn_handle" destination="ZuK-r9-26C" id="Ztw-HE-Srj"/> |
| | | <outlet property="btn_play" destination="LLy-9v-eQJ" id="tTl-C3-lNJ"/> |
| | | <outlet property="btn_voice" destination="kgj-Ss-D90" id="sHd-pN-FVy"/> |
| | | <outlet property="img_cover" destination="XW5-ds-CXG" id="yuo-h2-TG8"/> |
| | | <outlet property="img_state" destination="eyJ-Qy-E0w" id="6YM-Di-5yt"/> |
| | | <outlet property="view_container" destination="OJ6-0b-fVC" id="4Y2-jo-yTH"/> |
| | |
| | | import UIKit |
| | | |
| | | class HomeListen_item_TCell: UITableViewCell { |
| | | @IBOutlet weak var view_bg1: UIView! |
| | | @IBOutlet weak var view_bg2: UIView! |
| | | @IBOutlet weak var label_title: UILabel! |
| | | |
| | | override func awakeFromNib() { |
| | |
| | | </tableViewCellContentView> |
| | | <connections> |
| | | <outlet property="label_title" destination="28J-ZC-IiE" id="kDk-K7-10L"/> |
| | | <outlet property="view_bg1" destination="9XB-yf-tzC" id="u8S-3q-p3Y"/> |
| | | <outlet property="view_bg2" destination="pk7-Y8-Mtb" id="Dyb-wb-cSg"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="282.80487804878049" y="47.033898305084747"/> |
| | | </tableViewCell> |
| | |
| | | |
| | | let NextLession_Noti = Notification.Name.init("NextLession_Noti") |
| | | |
| | | enum ListenType{ |
| | | case lesson1 //自主学习-听音选图 |
| | | case lesson2 //自主学习-看图选音 |
| | | case lesson3 //自主学习-归纳排除 |
| | | case lesson4 //自主学习-有问有答 |
| | | case lesson5 //自主学习-音图相配 |
| | | case game1 //游戏类型-超级听力 |
| | | case game2 //游戏类型-超级记忆 |
| | | case story1 //故事类型-自主故事1-看图配音 |
| | | case story2 //故事类型-自主故事2-框架记忆 |
| | | enum ListenType:Int{ |
| | | case lesson1 = 1 //自主学习-听音选图 |
| | | case lesson2 = 2 //自主学习-看图选音 |
| | | case lesson3 = 3 //自主学习-归纳排除 |
| | | case lesson4 = 4 //自主学习-有问有答 |
| | | case lesson5 = 5 //自主学习-音图相配 |
| | | case game1 = 6 //游戏类型-超级听力 |
| | | case game2 = 7 //游戏类型-超级记忆 |
| | | case story1 = 8 //故事类型-自主故事1-看图配音 |
| | | case story2 = 9 //故事类型-自主故事2-框架记忆 |
| | | |
| | | var rawTitle:String{ |
| | | switch self { |
| | | case .lesson1:return "自主学习1-听音选图" |
| | | case .lesson2:return "自主学习2-看图选音" |
| | | case .lesson3:return "自主学习3-归纳排除" |
| | | case .lesson4:return "自主学习4-有问有答" |
| | | case .lesson5:return "自主学习5-音图相配" |
| | | case .game1:return "游戏类型1-超级听力" |
| | | case .game2:return "游戏类型2-超级记忆" |
| | | case .story1:return "自主故事1-看图配音" |
| | | case .story2:return "自主故事2-框架记忆" |
| | | } |
| | | } |
| | | } |
| | | |
| | | class HomeListenFightViewModel{ |
| | |
| | | var currentPage = BehaviorRelay<Int>(value: 0) |
| | | var maxPage = BehaviorRelay<Int>(value: 5) |
| | | var listenType = BehaviorRelay<ListenType>(value:.lesson1) |
| | | var times:Int = 0 |
| | | |
| | | //回答错误数量 |
| | | var correctNum:Int = 0{ |
| | | didSet{ |
| | | print("回答正确:\(correctNum)") |
| | | } |
| | | } |
| | | |
| | | var errorNum:Int = 0{ |
| | | didSet{ |
| | | print("回答错误:\(correctNum)") |
| | | } |
| | | } |
| | | |
| | | //所有回答的 |
| | | var answerItems = Dictionary<Int,Any>() //{page:0,data:String,currectAt:0} |
| | | } |
| | | |
| | | class HomeListenFightVC: BaseVC { |
| | | |
| | | private var viewModel = HomeListenFightViewModel() |
| | | var data:Any? |
| | | |
| | | private lazy var label_pageNum:UILabel = { |
| | | let label = UILabel() |
| | |
| | | private lazy var pageVC:FFPageViewController = { |
| | | let vc = FFPageViewController() |
| | | vc.scrollview.isScrollEnabled = false |
| | | vc.prePages = UInt(viewModel.maxPage.value) / 2 |
| | | vc.maxPages = UInt(viewModel.maxPage.value) + 1 |
| | | return vc |
| | | }() |
| | | |
| | | private var timer:Timer! |
| | | |
| | | |
| | | init(listenType:ListenType) { |
| | |
| | | label_pageNum.isHidden = true |
| | | } |
| | | |
| | | timer = Timer(fire: .distantPast, interval: 1.0, repeats: true, block: {[weak self] _ in |
| | | self?.viewModel.times += 1 |
| | | }) |
| | | |
| | | timer.fire() |
| | | RunLoop.current.add(timer, forMode: .common) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | |
| | | //完成 |
| | | if nextPage >= weakSelf.viewModel.maxPage.value{ |
| | | let vc = HomeStudyCompleteVC() |
| | | vc.title = "自主学习1-听音选图" |
| | | |
| | | var toalIntegral:Int = 0 |
| | | var ids = [Int]() |
| | | for v in weakSelf.viewModel.answerItems.values{ |
| | | if let v = v as? Listen1Model{ |
| | | toalIntegral += v.data?.integral ?? 0 |
| | | ids.append(v.data?.studyId ?? 0) |
| | | } |
| | | } |
| | | |
| | | Services.completeLearing(type: weakSelf.viewModel.listenType.value.rawValue, studyTime: weakSelf.viewModel.times, studyIds: ids, isComplete: false).subscribe(onNext: {data in |
| | | |
| | | }).disposed(by: weakSelf.disposeBag) |
| | | |
| | | weakSelf.timer.invalidate() |
| | | let vc = HomeStudyCompleteVC(correctNum: weakSelf.viewModel.correctNum, errorNum: weakSelf.viewModel.errorNum, totalCoin: toalIntegral) |
| | | vc.title = weakSelf.viewModel.listenType.value.rawTitle |
| | | weakSelf.push(vc: vc) |
| | | return |
| | | } |
| | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | deinit{ |
| | | timer.invalidate() |
| | | } |
| | | |
| | | @objc func quitAction(){ |
| | | CommonAlertView.show(content: "未完成全部答题,确认退出吗?") { |
| | | self.navigationController?.popViewController(animated: true) |
| | |
| | | } |
| | | |
| | | @objc func beforeAction(){ |
| | | let beforePage = max(1, viewModel.currentPage.value - 1) |
| | | let beforePage = max(0, viewModel.currentPage.value - 1) |
| | | pageVC.scroll(toPage: beforePage, animation: true) |
| | | viewModel.currentPage.accept(beforePage) |
| | | } |
| | |
| | | func pageViewController(_ pageViewConteoller: FFPageViewController, controllerForPage page: Int) -> UIViewController { |
| | | |
| | | if viewModel.listenType.value == .lesson1{ |
| | | let vc = HomeListenFight_lesson_1_VC() |
| | | let vc = HomeListenFight_lesson_1_VC(page: page,listen1Model:data as! Listen1Model) |
| | | vc.rootViewModel = viewModel |
| | | return vc |
| | | } |
| | | |
| | | if viewModel.listenType.value == .lesson2{ |
| | | let vc = HomeListenFight_lesson_2_VC() |
| | | let vc = HomeListenFight_lesson_2_VC(page: page,listen1Model:data as! Listen1Model) |
| | | vc.rootViewModel = viewModel |
| | | return vc |
| | | } |
| | | |
| | | if viewModel.listenType.value == .lesson3{ |
| | | let vc = HomeListenFight_lesson_3_VC() |
| | | let vc = HomeListenFight_lesson_3_VC(page: page, listen1Model: data as! Listen1Model) |
| | | vc.rootViewModel = viewModel |
| | | return vc |
| | | } |
| | | |
| | | if viewModel.listenType.value == .lesson4{ |
| | | let vc = HomeListenFight_lesson_4_VC() |
| | | let vc = HomeListenFight_lesson_4_VC(page: page, listen4Model: data as! Listen4Model) |
| | | vc.rootViewModel = viewModel |
| | | return vc |
| | | } |
| | | |
| | | if viewModel.listenType.value == .lesson5{ |
| | | let vc = HomeListenFight_lesson_5_VC() |
| | | let vc = HomeListenFight_lesson_5_VC(page: page, listen1Model: data as! Listen1Model) |
| | | vc.rootViewModel = viewModel |
| | | return vc |
| | | } |
| | | |
| | |
| | | |
| | | private var viewModel = FightAnswerViewModel() |
| | | |
| | | private var listen1Model:Listen1Model! |
| | | private var randomElement:Listen1SubModel? |
| | | private var page:Int! |
| | | var rootViewModel:HomeListenFightViewModel! |
| | | |
| | | private lazy var stackView:UIStackView = { |
| | | let stackView = UIStackView() |
| | | stackView.spacing = 78 |
| | |
| | | return collection |
| | | }() |
| | | |
| | | |
| | | required init(page:Int,listen1Model:Listen1Model){ |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.page = page |
| | | self.listen1Model = listen1Model |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | navigationItem.titleView = UIView() |
| | | viewModel.selectIndex.accept(IndexPath(row: 0, section: 0)) |
| | | |
| | | } |
| | | |
| | | override func setUI() { |
| | | super.setUI() |
| | | |
| | | viewModel.selectIndex.accept(IndexPath(row: 0, section: 0)) |
| | | |
| | | collectionView.delegate = self |
| | | collectionView.dataSource = self |
| | |
| | | make.width.greaterThanOrEqualTo(100) |
| | | } |
| | | |
| | | addStackView() |
| | | VoicePlayer.share().playEnd {[weak self] in |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | private func addStackView(){ |
| | | stackView.removeArrangedSubviews() |
| | | |
| | | var tempViews = [StudyHandleView]() |
| | | for index in 0...2{ |
| | | let handleView = StudyHandleView.jq_loadNibView() |
| | | handleView.listenType = .lesson2 |
| | | handleView.btn_choose.tag = 10 + index |
| | | |
| | | let row = viewModel.selectIndex.value!.row |
| | | let model = listen1Model.subjectList[row] |
| | | |
| | | if index == 0{ |
| | | handleView.vioceSoundUrl = model.correct |
| | | } |
| | | |
| | | if index == 1{ |
| | | handleView.vioceSoundUrl = model.error.components(separatedBy: ",").first |
| | | } |
| | | |
| | | if index == 2{ |
| | | handleView.vioceSoundUrl = model.error.components(separatedBy: ",").last |
| | | } |
| | | |
| | | handleView.chooseClouse {[weak self] btn in |
| | | guard let weakSelf = self else { return } |
| | | let row = weakSelf.viewModel.selectIndex.value!.row |
| | | |
| | | var lessionType:Fight_lessonType = .none |
| | | |
| | | lessionType = .success |
| | | if handleView.vioceSoundUrl == weakSelf.listen1Model.subjectList[row].correct{ |
| | | lessionType = .success |
| | | }else{ |
| | | lessionType = .fail |
| | | } |
| | | |
| | | switch lessionType { |
| | | case .success: |
| | | weakSelf.rootViewModel.correctNum += 1 |
| | | handleView.btn_choose.isEnabled = false |
| | | handleView.btn_state.setImage(UIImage(named: "icon_success_small"), for: .normal) |
| | | UIView.animate(withDuration: 0.5) { |
| | |
| | | self?.answerSuccess(cell,index: index) |
| | | } |
| | | case .fail: |
| | | weakSelf.rootViewModel.errorNum += 1 |
| | | handleView.btn_state.setImage(UIImage(named: "icon_waring_small"), for: .normal) |
| | | UIView.animate(withDuration: 0.5) { |
| | | handleView.btn_state.alpha = 1 |
| | |
| | | make.height.equalTo(52) |
| | | make.width.greaterThanOrEqualTo(159) |
| | | } |
| | | stackView.addArrangedSubview(handleView) |
| | | tempViews.append(handleView) |
| | | } |
| | | |
| | | tempViews.shuffle() //乱序 |
| | | stackView.addArrangedSubviews(tempViews) |
| | | } |
| | | |
| | | private func answerSuccess(_ cell:ListenFight_lesson_1_CCell,index:Int){ |
| | |
| | | self.view.layoutIfNeeded() |
| | | }completion: { _ in |
| | | self.resetStackView() |
| | | |
| | | } |
| | | } |
| | | |
| | | private func resetStackView(){ |
| | | for v in stackView.arrangedSubviews as! [StudyHandleView]{ |
| | | v.view_choose.alpha = 0 |
| | | v.btn_choose.isEnabled = true |
| | | v.btn_choose.isSelected = false |
| | | v.btn_state.setImage(nil, for: .normal) |
| | | } |
| | | let newRow = viewModel.selectIndex.value!.row+1 |
| | | viewModel.selectIndex.accept(IndexPath(row: newRow, section: 0)) |
| | | |
| | | collectionView.reloadData() |
| | | if newRow == 4{ |
| | | NotificationCenter.default.post(name: NextLession_Noti, object: nil) |
| | | rootViewModel.answerItems[page] = listen1Model |
| | | NotificationCenter.default.post(name: NextLession_Noti, object: nil);return |
| | | } |
| | | addStackView() |
| | | } |
| | | |
| | | override func setRx() { |
| | | viewModel.selectIndex.subscribe(onNext: {[weak self] index in |
| | | |
| | | guard let index = index else { return } |
| | | |
| | | //判断选中是否正确逻辑 |
| | | if let cell = self?.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: index) as? ListenFight_lesson_1_CCell{ |
| | | var answerType:Fight_lessonType = .none |
| | | answerType = .success |
| | | |
| | | switch answerType { |
| | | case .success: |
| | | self?.viewModel.answerType.accept(.success) |
| | | case .fail: |
| | | self?.viewModel.answerType.accept(.fail) |
| | | default:break |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | // viewModel.selectIndex.subscribe(onNext: {[weak self] index in |
| | | // guard let index = index else { return } |
| | | // //判断选中是否正确逻辑 |
| | | // if self?.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: index) is ListenFight_lesson_1_CCell{ |
| | | // var answerType:Fight_lessonType = .none |
| | | // answerType = .success |
| | | // switch answerType { |
| | | // case .success: |
| | | // self?.viewModel.answerType.accept(.success) |
| | | // self?.rootViewModel.correctNum += 1 |
| | | // case .fail: |
| | | // self?.viewModel.answerType.accept(.fail) |
| | | // self?.rootViewModel.errorNum += 1 |
| | | // default:break |
| | | // } |
| | | // } |
| | | // }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | | |
| | |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: indexPath) as! ListenFight_lesson_1_CCell |
| | | cell.jq_addShadows(shadowColor: .black.withAlphaComponent(0.31), corner: 5, radius: 5, offset: CGSize(width: 0, height: 1), opacity: 1) |
| | | cell.backgroundColor = .white |
| | | if viewModel.selectIndex.value?.row == indexPath.row{ |
| | | cell.label_title.isHidden = false |
| | | }else{ |
| | | cell.label_title.isHidden = true |
| | | } |
| | | cell.setListen1SubModel(listen1Model.subjectList[indexPath.row]) |
| | | cell.label_title.text = listen1Model.subjectList[indexPath.row].name |
| | | return cell |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 4 |
| | | return min(4,listen1Model.subjectList.count) |
| | | } |
| | | } |
| | |
| | | return sta |
| | | }() |
| | | |
| | | private var listen1Model:Listen1Model! |
| | | private var page:Int! |
| | | private var answterCount:Int = 0 //回答计数,用于确定角标 |
| | | var rootViewModel:HomeListenFightViewModel! |
| | | |
| | | required init(page:Int,listen1Model:Listen1Model){ |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.page = page |
| | | self.listen1Model = listen1Model |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | navigationItem.titleView = UIView() |
| | | viewModel.selectIndex.accept(IndexPath(row: 0, section: 0)) |
| | | // viewModel.selectIndex.accept(IndexPath(row: 0, section: 0)) |
| | | |
| | | setAnswerStackView() |
| | | |
| | | VoicePlayer.share().playEnd { [weak self] in |
| | | guard let weakSelf = self else { return } |
| | | if weakSelf.viewModel.selectIndex.value != nil{ |
| | | weakSelf.collectionView.reloadItems(at: [weakSelf.viewModel.selectIndex.value!]) |
| | | weakSelf.viewModel.selectIndex.accept(nil) |
| | | } |
| | | weakSelf.collectionView.reloadData() |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | |
| | | private func setAnswerStackView(){ |
| | | |
| | | for subView in stackView.arrangedSubviews{ |
| | | subView.removeFromSuperview() |
| | | } |
| | | stackView.removeArrangedSubviews() |
| | | |
| | | var tempImageArray = [String]() |
| | | |
| | | tempImageArray.append(listen1Model.subjectList[2].img ?? "") |
| | | tempImageArray.append(listen1Model.subjectList[4].img ?? "") |
| | | tempImageArray.append(listen1Model.subjectList[5].img ?? "") |
| | | // tempImageArray.shuffle() |
| | | |
| | | view.addSubview(stackView) |
| | | stackView.snp.makeConstraints { make in |
| | |
| | | answerView.alpha = 0 |
| | | answerView.btn_choose.addTarget(self, action: #selector(chooseAnswerAction), for: .touchUpInside) |
| | | answerView.btn_fullscreen.addTarget(self, action: #selector(fullscreenAction), for: .touchUpInside) |
| | | answerView.img_cover.contentMode = .scaleToFill |
| | | answerView.btn_choose.tag = 10+i |
| | | answerView.btn_fullscreen.tag = 20+i |
| | | answerView.imageUrl = tempImageArray[i] |
| | | answerView.img_cover.sd_setImage(with: URL(string: tempImageArray[i])) |
| | | answerView.snp.makeConstraints { make in |
| | | make.width.equalTo(85) |
| | | make.height.equalTo(52) |
| | |
| | | } |
| | | |
| | | @objc private func chooseAnswerAction(btn:UIButton){ |
| | | |
| | | if viewModel.selectIndex.value == nil{alertError(msg: "请先听题");return} |
| | | |
| | | let index = btn.tag - 10 |
| | | |
| | | var subV:Lesson_3_AnswerView? |
| | |
| | | } |
| | | |
| | | var answerType:Fight_lessonType = .none |
| | | answerType = .success |
| | | |
| | | var valueIndex:Int! //图片的角标 |
| | | if viewModel.selectIndex.value?.section == 0{ |
| | | valueIndex = viewModel.selectIndex.value!.row |
| | | } |
| | | if viewModel.selectIndex.value?.section == 1{ |
| | | valueIndex = viewModel.selectIndex.value!.row + 3 |
| | | } |
| | | |
| | | if subV?.imageUrl == listen1Model.subjectList[valueIndex].img{ |
| | | answerType = .success |
| | | }else{ |
| | | answerType = .fail |
| | | } |
| | | |
| | | switch answerType { |
| | | case .success: |
| | | rootViewModel.correctNum += 1 |
| | | viewModel.answerType.accept(.success) |
| | | |
| | | let copyViewFrame = subV?.convert(subV!.bounds, to: self.view) |
| | | |
| | | let copyView = subV?.copyView() |
| | | copyView?.frame = copyViewFrame! |
| | | copyView?.backgroundColor = .red |
| | | copyView?.img_cover.image = subV?.img_cover.image |
| | | copyView?.img_cover.contentMode = .scaleToFill |
| | | self.view.addSubview(copyView!) |
| | | copyView?.layoutIfNeeded() |
| | | |
| | | if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_3_CCell", for: viewModel.selectIndex.value!) as? ListenFight_lesson_3_CCell{ |
| | | cell.layoutIfNeeded() |
| | | var ansterIndePath:IndexPath? |
| | | if viewModel.selectIndex.value?.section == 0{ |
| | | ansterIndePath = IndexPath(row: 2, section: 0) |
| | | } |
| | | |
| | | if viewModel.selectIndex.value?.section == 1 && (viewModel.selectIndex.value?.row == 0 || viewModel.selectIndex.value?.row == 1){ |
| | | ansterIndePath = IndexPath(row: 1, section: 1) |
| | | } |
| | | |
| | | if viewModel.selectIndex.value?.section == 1 && viewModel.selectIndex.value?.row == 2{ |
| | | ansterIndePath = IndexPath(row: 2, section: 1) |
| | | } |
| | | |
| | | guard ansterIndePath != nil else {return} |
| | | |
| | | if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_3_CCell", for: ansterIndePath!) as? ListenFight_lesson_3_CCell{ |
| | | var newFrame = cell.img_cover.convert(cell.img_cover.bounds, to: self.view) |
| | | copyView?.img_cover.image = cell.img_cover.image |
| | | newFrame.origin.x += 97 |
| | | newFrame.origin.y += (JQ_NavBarHeight - 15) |
| | | newFrame.origin.x += 0 |
| | | newFrame.origin.y += 0 |
| | | UIView.animate(withDuration: 0.4) { |
| | | copyView?.frame = newFrame |
| | | } completion: { _ in |
| | | for subView in self.stackView.arrangedSubviews{ |
| | | subView.removeFromSuperview() |
| | | self.answterCount += 1 |
| | | if self.answterCount == 3{ |
| | | self.rootViewModel.answerItems[self.page] = self.listen1Model |
| | | NotificationCenter.default.post(name: NextLession_Noti, object: nil);return |
| | | } |
| | | |
| | | DispatchQueue.main.asyncAfter(deadline: .now()+1.5) { |
| | | self.setAnswerStackView() |
| | | self.viewModel.selectIndex.accept(nil) |
| | | } |
| | | } |
| | | } |
| | | |
| | | case .fail: |
| | | rootViewModel.errorNum += 1 |
| | | viewModel.answerType.accept(.fail) |
| | | UIView.animate(withDuration: 0.4) { |
| | | subV?.img_state.alpha = 1 |
| | |
| | | |
| | | extension HomeListenFight_lesson_3_VC:UICollectionViewDelegate{ |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | viewModel.selectIndex.accept(indexPath) |
| | | setAnswerStackView() |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_3_CCell", for: indexPath) as! ListenFight_lesson_3_CCell |
| | | cell.backgroundColor = .clear |
| | | cell.indexPath = indexPath |
| | | cell.contentView.backgroundColor = .clear |
| | | cell.palyVoiceAt {[weak self] index in |
| | | self?.viewModel.selectIndex.accept(index) |
| | | if (index.section == 0 && index.row == 2) || (index.section == 1 && index.row > 0){ |
| | | self?.viewModel.selectIndex.accept(index) |
| | | self?.setAnswerStackView() |
| | | } |
| | | |
| | | collectionView.reloadItems(at: [index]) |
| | | } |
| | | |
| | | if indexPath.section == 0{ |
| | | let model = listen1Model.subjectList[indexPath.row] |
| | | if indexPath.row != 2{ |
| | | cell.img_cover.sd_setImage(with: URL(string: model.img)) |
| | | }else{ |
| | | cell.img_cover.image = nil |
| | | } |
| | | cell.setModel(model,isplaying: viewModel.selectIndex.value == indexPath) |
| | | } |
| | | |
| | | if indexPath.section == 1{ |
| | | let model = listen1Model.subjectList[indexPath.row + 3] |
| | | if indexPath.row == 0{ |
| | | cell.img_cover.sd_setImage(with: URL(string: model.img)) |
| | | }else{ |
| | | cell.img_cover.image = nil |
| | | } |
| | | cell.setModel(model,isplaying: viewModel.selectIndex.value == indexPath) |
| | | } |
| | | return cell |
| | | } |
| | | |
| | |
| | | |
| | | private var viewModel = FightAnswerViewModel() |
| | | |
| | | private var listen4Model:Listen4Model! |
| | | private var page:Int! |
| | | var rootViewModel:HomeListenFightViewModel! |
| | | |
| | | private var answerIndex:IndexPath? //答案的Index |
| | | private var answerCount:Int = 0 //回答计数 |
| | | |
| | | private lazy var stackView:UIStackView = { |
| | | let sta = UIStackView() |
| | | sta.spacing = 41 |
| | |
| | | return collection |
| | | }() |
| | | |
| | | required init(page:Int,listen4Model:Listen4Model){ |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.page = page |
| | | self.listen4Model = listen4Model |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | VoicePlayer.share().playEnd { |
| | | print("播放完成") |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | private func setAnswerStackView(){ |
| | | |
| | | for subView in stackView.arrangedSubviews{ |
| | | subView.removeFromSuperview() |
| | | guard viewModel.selectIndex.value != nil else{ |
| | | alertError(msg: "请先听题");return |
| | | } |
| | | |
| | | stackView.removeArrangedSubviews() |
| | | |
| | | if !view.subviews.contains(stackView){ |
| | | view.addSubview(stackView) |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | let answerId = listen4Model.data[viewModel.selectIndex.value!.section].answerSubject |
| | | var tempVoiceArray = [String]() |
| | | for v in listen4Model.data[viewModel.selectIndex.value!.section].subjectList{ |
| | | if v.id == answerId{ |
| | | tempVoiceArray.append(v.correct) |
| | | tempVoiceArray.append(v.error.components(separatedBy: ",").first ?? "") |
| | | tempVoiceArray.append(v.error.components(separatedBy: ",").last ?? "") |
| | | } |
| | | } |
| | | |
| | | tempVoiceArray.shuffle() |
| | | |
| | | |
| | | for i in 0...2{ |
| | | let answerView = Lesson_4_AnswerView.jq_loadNibView() |
| | | answerView.btn_choose.tag = 10 + i |
| | | answerView.voiceUrl = tempVoiceArray[i] |
| | | answerView.btn_choose.addTarget(self, action: #selector(answerAction), for: .touchUpInside) |
| | | answerView.alpha = 0 |
| | | answerView.snp.makeConstraints { make in |
| | |
| | | } |
| | | } |
| | | |
| | | var answerModel:Listen1SubModel? |
| | | for (index,v) in (listen4Model.data[viewModel.selectIndex.value!.section].subjectList).enumerated(){ |
| | | if v.id == listen4Model.data[viewModel.selectIndex.value!.section].answerSubject{ |
| | | answerModel = v |
| | | }else{ |
| | | answerIndex = IndexPath(row: index, section: viewModel.selectIndex.value!.section) |
| | | } |
| | | } |
| | | |
| | | var answerType:Fight_lessonType = .none |
| | | answerType = .success |
| | | if tempSubV?.voiceUrl == answerModel?.correct{ |
| | | answerType = .success |
| | | answerCount += 1 |
| | | rootViewModel.correctNum += 1 |
| | | }else{ |
| | | answerType = .fail |
| | | rootViewModel.errorNum += 1 |
| | | } |
| | | VoicePlayer.share().playerEnd() |
| | | |
| | | switch answerType { |
| | | case .success: |
| | |
| | | self.view.addSubview(copyView) |
| | | self.view.layoutIfNeeded() |
| | | |
| | | |
| | | //获取Cell的顶部试图 |
| | | if let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_4_CCell", for: self.viewModel.selectIndex.value!) as? ListenFight_lesson_4_CCell{ |
| | | if let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_4_CCell", for: self.answerIndex!) as? ListenFight_lesson_4_CCell{ |
| | | var newRect1 = cell.convert(cell.bounds, to: self.collectionView) |
| | | newRect1.origin.x += 76 |
| | | newRect1.origin.y += 33 |
| | |
| | | UIView.animate(withDuration: 0.4) { |
| | | copyView.frame = CGRect(origin: newRect1.origin, size: CGSize(width: 152, height: 52)) |
| | | } completion: { _ in |
| | | self.setAnswerStackView() |
| | | self.viewModel.selectIndex.accept(nil) |
| | | self.stackView.removeArrangedSubviews() |
| | | self.stackView.layoutIfNeeded() |
| | | |
| | | //回答完成,下一答题 |
| | | if self.answerCount == 2{ |
| | | self.rootViewModel.answerItems[self.page] = self.listen4Model |
| | | VoicePlayer.share().playerEnd() |
| | | NotificationCenter.default.post(name: NextLession_Noti, object: nil);return |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | tempSubV?.img_state.alpha = 1 |
| | | }completion: { _ in |
| | | DispatchQueue.main.asyncAfter(deadline: .now()+3) { |
| | | self.setAnswerStackView() |
| | | // self.setAnswerStackView() |
| | | } |
| | | } |
| | | case .none: |
| | |
| | | |
| | | extension HomeListenFight_lesson_4_VC:UICollectionViewDelegate{ |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | viewModel.selectIndex.accept(indexPath) |
| | | |
| | | UIView.animate(withDuration: 0.5) { |
| | | self.collectionView.snp.remakeConstraints { make in |
| | | make.left.equalTo(76) |
| | | make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(0) |
| | | make.width.equalTo(JQ_ScreenW - 164 * 2) |
| | | make.bottom.equalToSuperview() |
| | | } |
| | | self.view.layoutIfNeeded() |
| | | } |
| | | self.setAnswerStackView() |
| | | // viewModel.selectIndex.accept(indexPath) |
| | | } |
| | | } |
| | | |
| | |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_4_CCell", for: indexPath) as! ListenFight_lesson_4_CCell |
| | | cell.backgroundColor = .clear |
| | | cell.contentView.backgroundColor = .clear |
| | | cell.indexPath = indexPath |
| | | cell.playAtIndex {[weak self] index in |
| | | guard let weakSelf = self else { return } |
| | | weakSelf.viewModel.selectIndex.accept(index) |
| | | UIView.animate(withDuration: 0.5) { |
| | | weakSelf.collectionView.snp.remakeConstraints { make in |
| | | make.left.equalTo(76) |
| | | make.top.equalTo(weakSelf.view.safeAreaLayoutGuide.snp.top).offset(0) |
| | | make.width.equalTo(JQ_ScreenW - 164 * 2) |
| | | make.bottom.equalToSuperview() |
| | | } |
| | | weakSelf.view.layoutIfNeeded() |
| | | }completion: { _ in |
| | | weakSelf.setAnswerStackView() |
| | | } |
| | | } |
| | | |
| | | if indexPath == viewModel.selectIndex.value{ |
| | | let m = listen4Model.data[indexPath.section].subjectList[indexPath.row] |
| | | if indexPath == answerIndex{ |
| | | UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.4,options: .layoutSubviews) { |
| | | cell.img_state.alpha = 1 |
| | | cell.img_state.transform = .init(scaleX: 1.0, y: 1.0) |
| | |
| | | cell.img_state.alpha = 0 |
| | | cell.img_state.transform = .init(scaleX: 0.1, y: 0.1) |
| | | } |
| | | //问题 |
| | | if listen4Model.data[indexPath.section].subject == m.id{ |
| | | cell.btn_handle.setImage(UIImage(named: "icon_question"), for: .normal) |
| | | cell.view_handle.isHidden = true |
| | | }else{ |
| | | cell.view_handle.isHidden = false |
| | | } |
| | | cell.setModel(m) |
| | | return cell |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 2 |
| | | return listen4Model.data[section].subjectList.count |
| | | } |
| | | |
| | | func numberOfSections(in collectionView: UICollectionView) -> Int { |
| | | return 2 |
| | | return listen4Model.data.count |
| | | } |
| | | |
| | | } |
| | |
| | | class HomeListenFight_lesson_5_VC: BaseVC { |
| | | |
| | | private var viewModel = FightAnswerViewModel() |
| | | private var listen1Model:Listen1Model! |
| | | private var page:Int! |
| | | private var answterCount:Int = 0 //回答计数,用于确定角标 |
| | | private var playVoiceAt:Int? //播放声音的View |
| | | private var playVoiceRealAt:Int? //播放声音的View -被乱序后,真实Index |
| | | var rootViewModel:HomeListenFightViewModel! |
| | | |
| | | private lazy var collectionView:UICollectionView = { |
| | | let flowLayout = UICollectionViewFlowLayout() |
| | | let w = (JQ_ScreenW - 189 * 2 - 18) / 2.0 |
| | | flowLayout.itemSize = CGSize(width: w, height: w * 0.75) |
| | | flowLayout.itemSize = CGSize(width: w, height: w * 0.70) |
| | | flowLayout.minimumInteritemSpacing = 15 |
| | | flowLayout.minimumLineSpacing = 15 |
| | | flowLayout.scrollDirection = .vertical |
| | |
| | | return sta |
| | | }() |
| | | |
| | | private lazy var label_hint:UILabel = { |
| | | let label = UILabel() |
| | | label.font = .systemFont(ofSize: 18, weight: .medium) |
| | | label.textColor = .black |
| | | label.text = "语音对应内容" |
| | | label.textAlignment = .center |
| | | return label |
| | | }() |
| | | |
| | | required init(page:Int,listen1Model:Listen1Model){ |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.page = page |
| | | self.listen1Model = listen1Model |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | collectionView.reloadData() |
| | | } |
| | | |
| | | override func setUI() { |
| | | super.setUI() |
| | | |
| | | collectionView.delegate = self |
| | | collectionView.dataSource = self |
| | | collectionView.showsVerticalScrollIndicator = false |
| | | collectionView.backgroundColor = .clear |
| | | view.addSubview(collectionView) |
| | | collectionView.snp.makeConstraints { make in |
| | | make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(89) |
| | | make.left.equalTo(189) |
| | | make.width.equalTo(JQ_ScreenW - 189 * 2) |
| | | make.bottom.equalToSuperview() |
| | | } |
| | | |
| | | view.addSubview(stackView) |
| | | stackView.snp.makeConstraints { make in |
| | |
| | | make.height.equalTo(52) |
| | | } |
| | | |
| | | view.addSubview(label_hint) |
| | | label_hint.snp.makeConstraints { make in |
| | | make.left.right.equalToSuperview() |
| | | make.top.equalTo(stackView.snp.bottom).offset(6) |
| | | make.height.equalTo(0) |
| | | } |
| | | |
| | | collectionView.delegate = self |
| | | collectionView.dataSource = self |
| | | collectionView.showsVerticalScrollIndicator = false |
| | | collectionView.backgroundColor = .clear |
| | | view.addSubview(collectionView) |
| | | collectionView.snp.makeConstraints { make in |
| | | make.top.equalTo(self.label_hint.snp.bottom).offset(11) |
| | | make.left.equalTo(189) |
| | | make.width.equalTo(JQ_ScreenW - 189 * 2) |
| | | make.bottom.equalToSuperview() |
| | | } |
| | | |
| | | showHintText(false) |
| | | |
| | | setAnswerStackView() |
| | | } |
| | | |
| | | override func setRx() { |
| | | // viewModel.selectIndex.subscribe(onNext: {indexPath in |
| | | // if let index = indexPath{ |
| | | // |
| | | // } |
| | | // }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | private func setAnswerStackView(){ |
| | |
| | | } |
| | | } |
| | | |
| | | for i in 0...3{ |
| | | var tempArray = [StudyHandleView]() |
| | | for (i,value) in listen1Model.subjectList.enumerated(){ |
| | | let answerView = StudyHandleView.jq_loadNibView() |
| | | answerView.listenType = .lesson5 |
| | | answerView.view_choose.isHidden = true |
| | | answerView.tag = 1000+i |
| | | answerView.playAt {[weak self] index in |
| | | print("--->\(index)--\(answerView.frame.origin.x / 248)") |
| | | self?.playVoiceRealAt = Int(answerView.frame.origin.x) / 248 |
| | | self?.playVoiceAt = index - 1000 |
| | | self?.showHintText(true) |
| | | } |
| | | answerView.vioceSoundUrl = value.correct |
| | | answerView.snp.makeConstraints { make in |
| | | make.width.equalTo(159) |
| | | make.height.equalTo(52) |
| | |
| | | UIView.animate(withDuration: 0.05 + Double(i)) { |
| | | answerView.alpha = 1 |
| | | } |
| | | tempArray.append(answerView) |
| | | } |
| | | tempArray.shuffle() |
| | | stackView.addArrangedSubviews(tempArray) |
| | | } |
| | | |
| | | stackView.insertArrangedSubview(answerView, at: 0) |
| | | private func showHintText(_ state:Bool){ |
| | | if let at = playVoiceAt{ |
| | | label_hint.text = listen1Model.subjectList[at].name |
| | | UIView.animate(withDuration: 0.5) { |
| | | if state{ |
| | | self.label_hint.snp.remakeConstraints { make in |
| | | make.left.right.equalToSuperview() |
| | | make.top.equalTo(self.stackView.snp.bottom).offset(6) |
| | | make.height.equalTo(25) |
| | | } |
| | | }else{ |
| | | self.label_hint.snp.remakeConstraints { make in |
| | | make.left.right.equalToSuperview() |
| | | make.top.equalTo(self.stackView.snp.bottom).offset(6) |
| | | make.height.equalTo(0) |
| | | } |
| | | } |
| | | self.view.layoutIfNeeded() |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | extension HomeListenFight_lesson_5_VC:UICollectionViewDelegate{ |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | |
| | | if playVoiceAt == nil{ |
| | | alertError(msg: "请先听题");return |
| | | } |
| | | |
| | | viewModel.selectIndex.accept(indexPath) |
| | | |
| | | var answerType:Fight_lessonType = .none |
| | | answerType = .success |
| | | let answer = listen1Model.subjectList[playVoiceAt!] |
| | | let selectAnswer = listen1Model.subjectList[indexPath.row] |
| | | |
| | | let tempSubV = stackView.arrangedSubviews[indexPath.row] as! StudyHandleView |
| | | var answerType:Fight_lessonType = .none |
| | | |
| | | if answer.id == selectAnswer.id{ |
| | | answerType = .success |
| | | }else{ |
| | | answerType = .fail |
| | | } |
| | | |
| | | let tempSubV = stackView.arrangedSubviews[self.playVoiceRealAt!] as! StudyHandleView |
| | | |
| | | switch answerType { |
| | | case .success: |
| | | answterCount += 1 |
| | | rootViewModel.correctNum += 1 |
| | | viewModel.answerType.accept(.success) |
| | | DispatchQueue.main.asyncAfter(deadline: .now()+0.4) { |
| | | let copyView = tempSubV.copyView() |
| | | copyView.view_choose.isHidden = true |
| | |
| | | //获取Cell的顶部试图 |
| | | let flowLayout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout |
| | | |
| | | if let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: self.viewModel.selectIndex.value!) as? ListenFight_lesson_1_CCell{ |
| | | if let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: indexPath) as? ListenFight_lesson_1_CCell{ |
| | | var newRect1 = cell.convert(cell.bounds, to: self.collectionView) |
| | | newRect1.origin.x += (collectionView.frame.origin.x + 5) |
| | | newRect1.origin.y += 94 |
| | | newRect1.origin.y += 94 + 25 |
| | | |
| | | UIView.animateKeyframes(withDuration: 0.4, delay: 0,options: .calculationModeLinear) { |
| | | copyView.frame = CGRect(origin: newRect1.origin, size: CGSize(width: flowLayout.itemSize.width - 10 , height: 40)) |
| | | |
| | | }completion: { _ in |
| | | self.playVoiceRealAt = nil |
| | | self.playVoiceAt = nil |
| | | |
| | | if self.answterCount == 4{ |
| | | self.rootViewModel.answerItems[self.page] = self.listen1Model |
| | | VoicePlayer.share().playerEnd() |
| | | NotificationCenter.default.post(name: NextLession_Noti, object: nil) |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | case .fail: |
| | | viewModel.answerType.accept(.fail) |
| | | rootViewModel.errorNum += 1 |
| | | collectionView.reloadData() |
| | | case .none: |
| | | break |
| | |
| | | |
| | | extension HomeListenFight_lesson_5_VC:UICollectionViewDataSource{ |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let model = listen1Model.subjectList[indexPath.row] |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_ListenFight_lesson_1_CCell", for: indexPath) as! ListenFight_lesson_1_CCell |
| | | cell.jq_addShadows(shadowColor: .black.withAlphaComponent(0.31), corner: 8, radius: 3, offset: CGSize(width: 0, height: 1), opacity: 1) |
| | | if viewModel.selectIndex.value == indexPath{ |
| | | cell.setState(state: .success) |
| | | cell.setState(state: viewModel.answerType.value) |
| | | }else{ |
| | | cell.setState(state: .none) |
| | | } |
| | | cell.setListen1SubModel(model) |
| | | return cell |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 4 |
| | | return listen1Model.subjectList.count |
| | | } |
| | | |
| | | func numberOfSections(in collectionView: UICollectionView) -> Int { |
| | |
| | | |
| | | |
| | | private func getData(){ |
| | | Services.weekList(quarter: selectIndexPath.row).subscribe(onNext: {result in |
| | | Services.weekList(quarter: selectIndexPath.row + 1).subscribe(onNext: {result in |
| | | self.dataItems[self.selectIndexPath.row] = result.data ?? [] |
| | | self.collectionView.reloadData() |
| | | }).disposed(by: disposeBag) |
| | |
| | | extension HomeListenMenuVC:UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{ |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | let vc = HomeListenVC() |
| | | let model = dataItems[selectIndexPath.row][indexPath.row] |
| | | |
| | | let quarter = selectIndexPath.row + 1 //季度 |
| | | let week = model.week //周 |
| | | let vc = HomeListenVC(quarter: quarter, week: week) |
| | | push(vc: vc) |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeListenMenuCCell", for: indexPath) as! HomeListenMenuCCell |
| | | cell.setTitle(week: "第一周", title: "提示基础认知能力", coin: 2000) |
| | | cell.contentView.backgroundColor = UIColor.qmui_random() |
| | | let seal = indexPath.row % 10 |
| | | cell.contentView.backgroundColor = UIColor(hexString: repeatColors[seal]) |
| | | let model = dataItems[selectIndexPath.row][indexPath.row] |
| | | cell.setTitle(week: "第\(model.week.jq_cn)周", title: model.title, coin: model.totalIntegral) |
| | | |
| | | return cell |
| | | } |
| | | |
| | |
| | | getData() |
| | | } |
| | | tableView.reloadData() |
| | | collectionView.reloadData() |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | |
| | | private var label_title = UILabel() |
| | | private var label_completeCoin = UILabel() |
| | | |
| | | var listenWeekModel:ListenWeekModel!{ |
| | | didSet{ |
| | | |
| | | } |
| | | } |
| | | |
| | | override init(frame: CGRect) { |
| | | super.init(frame: frame) |
| | | |
| | |
| | | class HomeListenSubVC: BaseVC { |
| | | |
| | | private var page:Int! |
| | | private var quarter:Int! |
| | | private var week:Int! |
| | | private var tableView:UITableView! |
| | | |
| | | required init(page:Int) { |
| | | self.page = page |
| | | required init(page:Int,quarter:Int,week:Int) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.page = page |
| | | self.quarter = quarter |
| | | self.week = week |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | |
| | | extension HomeListenSubVC:UITableViewDelegate{ |
| | | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { |
| | | |
| | | if indexPath.section == 1{ |
| | | let day = page + 1 |
| | | |
| | | if page <= 4{ |
| | | if indexPath.row == 0{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .lesson1)) |
| | | //听音选图 |
| | | Services.listenSelectPicture(day:day, quarter: quarter, week: week).subscribe(onNext: {result in |
| | | if let data = result.data{ |
| | | let fightVC = HomeListenFightVC(listenType: .lesson1) |
| | | fightVC.title = ListenType.lesson1.rawTitle |
| | | fightVC.data = data |
| | | JQ_currentViewController().jq_push(vc:fightVC) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | if indexPath.row == 1{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .lesson2)) |
| | | //看图选音 |
| | | Services.pictureSelectVoice(day: day, quarter: quarter, week: week).subscribe(onNext: {result in |
| | | if let data = result.data{ |
| | | let fightVC = HomeListenFightVC(listenType: .lesson2) |
| | | fightVC.title = ListenType.lesson2.rawTitle |
| | | fightVC.data = data |
| | | JQ_currentViewController().jq_push(vc:fightVC) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | |
| | | } |
| | | |
| | | if indexPath.row == 2{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .lesson3)) |
| | | //归纳排除 |
| | | Services.induceExclude(day: day, quarter: quarter, week: week).subscribe(onNext: {result in |
| | | if let data = result.data{ |
| | | let fightVC = HomeListenFightVC(listenType: .lesson3) |
| | | fightVC.title = ListenType.lesson3.rawTitle |
| | | fightVC.data = data |
| | | JQ_currentViewController().jq_push(vc: fightVC) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | if indexPath.row == 3{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .lesson4)) |
| | | //有问有答 |
| | | Services.questionsAndAnswers(day: day, quarter: quarter, week: week).subscribe(onNext: {result in |
| | | if let data = result.data{ |
| | | let fightVC = HomeListenFightVC(listenType: .lesson4) |
| | | fightVC.title = ListenType.lesson4.rawTitle |
| | | fightVC.data = data |
| | | JQ_currentViewController().jq_push(vc: fightVC) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | if indexPath.row == 4{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .lesson5)) |
| | | //音图相配 |
| | | Services.pictureMateVoice(day: day, quarter: quarter, week: week).subscribe(onNext: {result in |
| | | if let data = result.data{ |
| | | let fightVC = HomeListenFightVC(listenType: .lesson5) |
| | | fightVC.title = ListenType.lesson5.rawTitle |
| | | fightVC.data = data |
| | | JQ_currentViewController().jq_push(vc: fightVC) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | | |
| | | if indexPath.row == 5{ |
| | | //自主游戏 |
| | | if page == 5{ |
| | | if indexPath.row == 0{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .game1)) |
| | | } |
| | | if indexPath.row == 6{ |
| | | if indexPath.row == 1{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .game2)) |
| | | } |
| | | if indexPath.row == 7{ |
| | | } |
| | | |
| | | //听故事 |
| | | if page == 6{ |
| | | if indexPath.row == 0{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .story1)) |
| | | } |
| | | if indexPath.row == 8{ |
| | | if indexPath.row == 1{ |
| | | JQ_currentViewController().jq_push(vc: HomeListenFightVC(listenType: .story2)) |
| | | } |
| | | } |
| | |
| | | |
| | | extension HomeListenSubVC:UITableViewDataSource{ |
| | | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
| | | if section == 0{ |
| | | return 1 |
| | | |
| | | if page <= 4{ |
| | | if section == 0{return 1} |
| | | return 5 |
| | | }else{ |
| | | return 2 |
| | | } |
| | | return 9 |
| | | } |
| | | |
| | | func numberOfSections(in tableView: UITableView) -> Int { |
| | | if page <= 6{ |
| | | if page <= 4{ |
| | | return 2 |
| | | } |
| | | return 1 |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
| | | if indexPath.section == 0{ |
| | | if indexPath.section == 0 && page <= 4{ |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_HomeListen_process_TCell", for: indexPath) as! HomeListen_process_TCell |
| | | return cell |
| | | }else{ |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_HomeListen_item_TCell", for: indexPath) as! HomeListen_item_TCell |
| | | cell.label_title.text = "\(indexPath.row + 1)" |
| | | |
| | | switch indexPath.row { |
| | | case 0:cell.label_title.text = "题目类型一" |
| | | case 1:cell.label_title.text = "题目类型二" |
| | | case 2:cell.label_title.text = "题目类型三" |
| | | case 3:cell.label_title.text = "题目类型四" |
| | | case 4:cell.label_title.text = "题目类型五" |
| | | case 5:cell.label_title.text = "游戏一" |
| | | case 6:cell.label_title.text = "游戏二" |
| | | case 7:cell.label_title.text = "故事一" |
| | | case 8:cell.label_title.text = "故事二" |
| | | default:break |
| | | if page <= 4{ |
| | | cell.view_bg1.isHidden = true |
| | | switch indexPath.row { |
| | | case 0: |
| | | cell.label_title.text = "自主学习1-听音选图" |
| | | cell.view_bg2.backgroundColor = UIColor(hexString: "#6EC3FF") |
| | | case 1: |
| | | cell.label_title.text = "自主学习2-看图选音" |
| | | cell.view_bg2.backgroundColor = UIColor(hexString: "#FF9A85") |
| | | case 2: |
| | | cell.label_title.text = "自主学习3-归纳排除" |
| | | cell.view_bg2.backgroundColor = UIColor(hexString: "#28C8C5") |
| | | case 3: |
| | | cell.label_title.text = "自主学习4-有问有答" |
| | | cell.view_bg2.backgroundColor = UIColor(hexString: "#F8A169") |
| | | case 4: |
| | | cell.label_title.text = "自主学习5-音图相配" |
| | | cell.view_bg2.backgroundColor = UIColor(hexString: "#92CADB") |
| | | default:break |
| | | } |
| | | } |
| | | |
| | | if page == 5{ |
| | | cell.view_bg2.isHidden = true |
| | | switch indexPath.row { |
| | | case 0: |
| | | cell.label_title.text = "自主游戏1-超级听力" |
| | | cell.view_bg1.backgroundColor = UIColor(hexString: "#6EC3FF") |
| | | case 1: |
| | | cell.label_title.text = "自主游戏2-超级记忆" |
| | | cell.view_bg1.backgroundColor = UIColor(hexString: "#FF9A85") |
| | | default:break |
| | | } |
| | | } |
| | | |
| | | if page == 6{ |
| | | cell.view_bg2.isHidden = true |
| | | switch indexPath.row { |
| | | case 0: |
| | | cell.label_title.text = "自主故事1-看图配音" |
| | | cell.view_bg1.backgroundColor = UIColor(hexString: "#6EC3FF") |
| | | case 1: |
| | | cell.label_title.text = "自主故事2-框架记忆" |
| | | cell.view_bg1.backgroundColor = UIColor(hexString: "#FF9A85") |
| | | default:break |
| | | } |
| | | } |
| | | |
| | | return cell |
| | |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | | if indexPath.section == 0{ |
| | | return 145.5 |
| | | if page <= 5{ |
| | | if indexPath.section == 0{return 145.5} |
| | | return 127.5 |
| | | }else{ |
| | | return 127.5 |
| | | } |
| | |
| | | |
| | | //限制后面的点击:天数(1开始) |
| | | private var limitDay = 7 |
| | | private var quarter:Int! |
| | | private var week:Int! |
| | | |
| | | private lazy var menu:SPPageMenu = { |
| | | let menu = SPPageMenu(frame: .zero, trackerStyle: .line) |
| | |
| | | return vc |
| | | }() |
| | | |
| | | required init(quarter:Int,week:Int) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.quarter = quarter |
| | | self.week = week |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | } |
| | |
| | | } |
| | | |
| | | func pageViewController(_ pageViewConteoller: FFPageViewController, controllerForPage page: Int) -> UIViewController { |
| | | return HomeListenSubVC(page: page) |
| | | return HomeListenSubVC(page: page,quarter: quarter,week: week) |
| | | } |
| | | } |
| | |
| | | @IBOutlet weak var btn_choose: UIButton! |
| | | @IBOutlet weak var btn_fullscreen: UIButton! |
| | | @IBOutlet weak var img_cover: UIImageView! |
| | | |
| | | var imageUrl:String = "" |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | img_state.alpha = 0 |
| | |
| | | @IBOutlet weak var btn_choose: UIButton! |
| | | @IBOutlet weak var view_state: UIView! |
| | | @IBOutlet weak var view_handle: UIView! |
| | | |
| | | |
| | | var voiceUrl:String? |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | img_state.alpha = 0 |
| | |
| | | return copyV |
| | | } |
| | | |
| | | |
| | | |
| | | @IBAction func playAction(_ sender: UIButton) { |
| | | if let url = voiceUrl{ |
| | | VoicePlayer.share().playerAt(url: url) |
| | | } |
| | | } |
| | | } |
| | |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qsr-6I-w3R"> |
| | | <rect key="frame" x="0.0" y="0.0" width="152" height="52"/> |
| | | <subviews> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="otl-1Z-qED"> |
| | | <rect key="frame" x="18" y="9.5" width="33" height="33"/> |
| | | <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="otl-1Z-qED"> |
| | | <rect key="frame" x="18" y="15" width="28" height="22"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="icon_question"/> |
| | | <state key="normal" image="icon_answer"/> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mba-RI-50M"> |
| | | <rect key="frame" x="70" y="12.5" width="27" height="27"/> |
| | | <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mba-RI-50M"> |
| | | <rect key="frame" x="65" y="12.5" width="27" height="27"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="icon_play_1"/> |
| | | </button> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_fail" translatesAutoresizingMaskIntoConstraints="NO" id="mkh-g4-79e"> |
| | | <rect key="frame" x="108" y="10" width="32" height="32"/> |
| | | <rect key="frame" x="103" y="10" width="32" height="32"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="32" id="unt-83-tZW"/> |
| | | <constraint firstAttribute="width" constant="32" id="yDR-8r-kHx"/> |
| | | </constraints> |
| | | </imageView> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tfO-7L-o0T"> |
| | | <rect key="frame" x="0.0" y="0.0" width="152" height="52"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <connections> |
| | | <action selector="playAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="mAa-LF-0SJ"/> |
| | | </connections> |
| | | </button> |
| | | </subviews> |
| | | <color key="backgroundColor" red="0.25490196079999999" green="0.63529411759999999" blue="0.92156862750000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <constraints> |
| | | <constraint firstItem="mba-RI-50M" firstAttribute="leading" secondItem="otl-1Z-qED" secondAttribute="trailing" constant="19" id="0nx-t9-1zV"/> |
| | | <constraint firstAttribute="width" constant="152" id="3Zx-vg-H2U"/> |
| | | <constraint firstItem="otl-1Z-qED" firstAttribute="leading" secondItem="qsr-6I-w3R" secondAttribute="leading" constant="18" id="6CA-c8-Zr7"/> |
| | | <constraint firstAttribute="bottom" secondItem="tfO-7L-o0T" secondAttribute="bottom" id="8ro-2n-YNH"/> |
| | | <constraint firstAttribute="trailing" secondItem="tfO-7L-o0T" secondAttribute="trailing" id="A2h-po-R4k"/> |
| | | <constraint firstItem="mba-RI-50M" firstAttribute="centerY" secondItem="otl-1Z-qED" secondAttribute="centerY" id="FTc-eb-PWk"/> |
| | | <constraint firstItem="tfO-7L-o0T" firstAttribute="top" secondItem="qsr-6I-w3R" secondAttribute="top" id="HqC-Ia-1OU"/> |
| | | <constraint firstItem="mkh-g4-79e" firstAttribute="centerY" secondItem="otl-1Z-qED" secondAttribute="centerY" id="N6f-d4-80e"/> |
| | | <constraint firstItem="tfO-7L-o0T" firstAttribute="leading" secondItem="qsr-6I-w3R" secondAttribute="leading" id="QfH-1Q-LyV"/> |
| | | <constraint firstItem="mkh-g4-79e" firstAttribute="leading" secondItem="mba-RI-50M" secondAttribute="trailing" constant="11" id="a9o-Lq-9SP"/> |
| | | <constraint firstItem="otl-1Z-qED" firstAttribute="centerY" secondItem="qsr-6I-w3R" secondAttribute="centerY" id="v0P-gn-zbN"/> |
| | | </constraints> |
| | |
| | | <resources> |
| | | <image name="btn_radio" width="52" height="52"/> |
| | | <image name="btn_radio_u" width="52" height="52"/> |
| | | <image name="icon_answer" width="28" height="14"/> |
| | | <image name="icon_fail" width="80" height="80"/> |
| | | <image name="icon_play_1" width="27" height="27"/> |
| | | <image name="icon_question" width="33" height="33"/> |
| | | </resources> |
| | | </document> |
| | |
| | | import UIKit |
| | | |
| | | class HomeStudyCompleteVC: BaseVC { |
| | | @IBOutlet weak var label_coin: UILabel! |
| | | @IBOutlet weak var label_correctNum: UILabel! |
| | | @IBOutlet weak var label_totalNum: UILabel! |
| | | @IBOutlet weak var label_errorNum: UILabel! |
| | | @IBOutlet weak var label_ratioNum: UILabel! |
| | | |
| | | private var correctNum:Int = 0 |
| | | private var errorNum:Int = 0 |
| | | private var totalCoin:Int = 0 |
| | | |
| | | required init(correctNum:Int,errorNum:Int,totalCoin:Int){ |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.correctNum = correctNum |
| | | self.errorNum = errorNum |
| | | self.totalCoin = totalCoin |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | |
| | | label_coin.text = "恭喜你,已完成全部答题!获得\(totalCoin)积分!" |
| | | label_correctNum.text = "\(correctNum)次" |
| | | label_errorNum.text = "\(errorNum)次" |
| | | label_totalNum.text = "\(correctNum + errorNum)次" |
| | | label_ratioNum.text = String(format: "正确率:%.0lf%%", Double(correctNum) / Double(correctNum + errorNum) * 100) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="HomeStudyCompleteVC" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="label_coin" destination="0Rg-U5-bnk" id="Ue5-07-HUP"/> |
| | | <outlet property="label_correctNum" destination="GyL-R8-T1w" id="ljq-bs-33V"/> |
| | | <outlet property="label_errorNum" destination="8Lo-W3-dxd" id="y0q-RX-MkE"/> |
| | | <outlet property="label_ratioNum" destination="4uZ-XC-Xc3" id="cSZ-ND-O0D"/> |
| | | <outlet property="label_totalNum" destination="EAE-ID-4sP" id="Xpa-MR-y2Y"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | </connections> |
| | | </placeholder> |
| | |
| | | @IBOutlet weak var view_container: UIView! |
| | | private var items = [RecommendModel]() |
| | | private var clickClouse:((RecommendModel)->Void)! |
| | | private var closeClouse:(()->Void)! |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | self.alpha = 0 |
| | |
| | | layoutIfNeeded() |
| | | } |
| | | |
| | | static func show(items:[RecommendModel],clouse:@escaping (RecommendModel)->Void){ |
| | | static func show(items:[RecommendModel],clouse:@escaping (RecommendModel)->Void,closeClouse:@escaping()->Void){ |
| | | |
| | | if items.count == 0{return} |
| | | |
| | | let awardListView = AwardListView.jq_loadNibView() |
| | | awardListView.items = items |
| | | awardListView.clickClouse = clouse |
| | | awardListView.closeClouse = closeClouse |
| | | sceneDelegate?.window?.addSubview(awardListView) |
| | | awardListView.frame = sceneDelegate?.window?.frame ?? .zero |
| | | |
| | |
| | | self.alpha = 0 |
| | | self.view_container.transform = .init(scaleX: 0.1, y: 0.1) |
| | | } completion: { _ in |
| | | self.closeClouse?() |
| | | self.removeFromSuperview() |
| | | } |
| | | } |
| | |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | |
| | | |
| | | UIView.animate(withDuration: 0.4) { |
| | | self.alpha = 0 |
| | | self.view_container.transform = .init(scaleX: 0.1, y: 0.1) |
| | | } completion: { _ in |
| | | self.removeFromSuperview() |
| | | let item = self.items[indexPath.row] |
| | | self.clickClouse(item) |
| | | } |
| | | // UIView.animate(withDuration: 0.4) { |
| | | // self.alpha = 0 |
| | | // self.view_container.transform = .init(scaleX: 0.1, y: 0.1) |
| | | // } completion: { _ in |
| | | // self.removeFromSuperview() |
| | | // let item = self.items[indexPath.row] |
| | | // self.clickClouse(item) |
| | | // } |
| | | } |
| | | } |
| | | |
| | |
| | | super.viewDidLoad() |
| | | |
| | | Services.userInfo().subscribe(onNext: {result in |
| | | if let model = result.data{ |
| | | var items = Array<String>() |
| | | |
| | | if let model = result.data?.user{ |
| | | self.imge_cover.sd_setImage(with: URL(string: model.headImg)) |
| | | self.label_name.text = model.name |
| | | // var items = Array<String>() |
| | | // items.append("剩余积分:\(model.integral)") |
| | | // items.append("学习进度:\(model.integral)") |
| | | items.append("剩余积分:\(model.integral)") |
| | | } |
| | | |
| | | if let model = result.data?.userStudy{ |
| | | items.append("学习进度:\(model.week)") |
| | | items.append("学习总时长:\(model.totalStudy)小时") |
| | | } |
| | | self.label_info.text = items.joined(separator: "|") |
| | | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | override func setUI() { |
| | | super.setUI() |
| | | label_info.text = "" |
| | | btn_address.spacingBetweenImageAndTitle = 11 |
| | | btn_coinRecord.spacingBetweenImageAndTitle = 11 |
| | | btn_exchangeRecord.spacingBetweenImageAndTitle = 11 |
| | |
| | | @IBOutlet weak var label_sendInfo: UILabel! |
| | | @IBOutlet weak var btn_state: UIButton! |
| | | @IBOutlet weak var label_coin: UILabel! |
| | | @IBOutlet weak var img_cover: UIImageView! |
| | | |
| | | @IBOutlet weak var view_container: UIView! |
| | | override func awakeFromNib() { |
| | |
| | | func setModel(_ model:ExchangeRecordModel){ |
| | | label_goodsNum.text = "商品数量:\(model.count)" |
| | | label_coin.text = "\(model.integral)积分" |
| | | |
| | | label_goodsName.text = model.goodsName |
| | | label_types.text = model.goodsType.joined(separator: "|") |
| | | img_cover.sd_setImage(with: URL(string: model.coverImg)) |
| | | var items_consignee = Array<String>() |
| | | items_consignee.append(model.consigneeName) |
| | | items_consignee.append(model.consigneePhone) |
| | |
| | | |
| | | label_sendInfo.isHidden = items_express.filter({!$0.isEmpty}).count == 0 |
| | | label_sendInfo.text = "发货信息:" + items_express.joined(separator: "|") |
| | | |
| | | //订单状态1待发货2已发货3已完成 |
| | | switch model.state{ |
| | | case 1: |
| | | label_state.text = "待发货" |
| | | btn_state.setTitle("修改地址", for: .normal) |
| | | btn_state.isHidden = false |
| | | case 2: |
| | | label_state.text = "平台已发货,请耐心等待" |
| | | btn_state.setTitle("已收货", for: .normal) |
| | | btn_state.isHidden = false |
| | | case 3: |
| | | label_state.text = "已完成" |
| | | btn_state.isHidden = true |
| | | default: |
| | | btn_state.isHidden = true |
| | | } |
| | | } |
| | | |
| | | @IBAction func handleAction(_ sender: UIButton) { |
| | |
| | | <viewLayoutGuide key="safeArea" id="njF-e1-oar"/> |
| | | <connections> |
| | | <outlet property="btn_state" destination="xwt-lH-fyW" id="YNc-qk-0gB"/> |
| | | <outlet property="img_cover" destination="HZS-Oe-5LR" id="jhE-JJ-jDa"/> |
| | | <outlet property="label_coin" destination="nMG-SO-H2Z" id="weP-sJ-QLG"/> |
| | | <outlet property="label_goodsName" destination="UdI-oe-WSO" id="o9d-iH-BCJ"/> |
| | | <outlet property="label_goodsNum" destination="PlF-D7-xZD" id="1mj-HF-LGA"/> |
| | |
| | | // |
| | | |
| | | import UIKit |
| | | import JQTools |
| | | |
| | | class Home_1_TCell: UITableViewCell { |
| | | |
| | |
| | | |
| | | var studyGamesRecordModel:StudyGamesRecordModel!{ |
| | | didSet{ |
| | | |
| | | label_1.text = studyGamesRecordModel.createTime |
| | | label_2.text = studyGamesRecordModel.gameName |
| | | let date = Date.JQ_secondToDate(interval: studyGamesRecordModel.useTime) |
| | | var emuple = [String]() |
| | | if date.hour > 0{emuple.append("\(date.hour)小时")} |
| | | if date.minute > 0{emuple.append("\(date.minute)分钟")} |
| | | label_3.text = emuple.joined(separator: "") |
| | | label_4.text = "\(studyGamesRecordModel.accuracy)%" |
| | | } |
| | | } |
| | | |
| | |
| | | tableView.register(UINib(nibName: "GoodsItemTCell", bundle: nil), forCellReuseIdentifier: "_GoodsItemTCell") |
| | | view.addSubview(tableView) |
| | | tableView.snp.makeConstraints { make in |
| | | make.left.equalTo(239 * Config.RatioW) |
| | | make.right.equalTo(-239 * Config.RatioW) |
| | | make.left.equalTo(159 * Config.RatioW) |
| | | make.right.equalTo(-159 * Config.RatioW) |
| | | make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(27 * Config.RatioW) |
| | | make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom).offset(-5) |
| | | } |
| | |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | | return 221 * Config.RatioH |
| | | return 241 * Config.RatioH |
| | | } |
| | | |
| | | |
| | |
| | | // |
| | | |
| | | import UIKit |
| | | import JQTools |
| | | |
| | | class StudyVC: BaseVC { |
| | | |
| | | @IBOutlet weak var label_currentProcess: UILabel! |
| | | @IBOutlet weak var label_surplusProcess: UILabel! |
| | | @IBOutlet weak var label_studyTotalTimes: UILabel! |
| | | @IBOutlet weak var label_studyWeekTotalTimes: UILabel! |
| | | @IBOutlet weak var view_menu: UIView! |
| | | @IBOutlet weak var tableView: UITableView! |
| | | |
| | | private var gamesRecordModel:StudyGamesModel?{ |
| | | didSet{ |
| | | self.tableView.reloadData() |
| | | |
| | | label_currentProcess.text = "当前进度:周目\(gamesRecordModel?.record?.week.jq_cn ?? "")" |
| | | label_surplusProcess.text = "剩余进度:周目\(gamesRecordModel?.record?.surplus.jq_cn ?? "")" |
| | | |
| | | label_studyTotalTimes.attributedText = AttributedStringbuilder.build().add(string: "学习总时长:", withFont: .systemFont(ofSize: 16), withColor: UIColor(hexString: "#2B3648")!).add(string: "\(gamesRecordModel?.record?.totalStudy ?? 0)小时", withFont: .systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexString: "#2B3648")!).add(string: "|今日学习:", withFont: .systemFont(ofSize: 16), withColor: UIColor(hexString: "#2B3648")!).add(string: "\(gamesRecordModel?.record?.todayStudy ?? 0)小时", withFont: .systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexString: "#2B3648")!).mutableAttributedString |
| | | |
| | | |
| | | label_studyWeekTotalTimes.attributedText = AttributedStringbuilder.build().add(string: "本周学习时长:", withFont: .systemFont(ofSize: 16), withColor: UIColor(hexString: "#2B3648")!).add(string: "\(gamesRecordModel?.record?.weekStudy ?? 0)小时", withFont: .systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexString: "#2B3648")!).add(string: "|本月学习时长:", withFont: .systemFont(ofSize: 16), withColor: UIColor(hexString: "#2B3648")!).add(string: "\(gamesRecordModel?.record?.monthStudy ?? 0)小时", withFont: .systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexString: "#2B3648")!).mutableAttributedString |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | Services.studyGamesRecord().subscribe(onNext: {result in |
| | | if let m = result.data{ |
| | | self.gamesRecordModel = m |
| | |
| | | if let m = gamesRecordModel?.gameRecordList[indexPath.row]{ |
| | | cell.studyGamesRecordModel = m |
| | | } |
| | | |
| | | |
| | | return cell |
| | | } |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="StudyVC" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="label_currentProcess" destination="6E8-Ab-gRb" id="70S-Tq-iJq"/> |
| | | <outlet property="label_studyTotalTimes" destination="crR-lR-Tnj" id="aM4-1l-jTW"/> |
| | | <outlet property="label_studyWeekTotalTimes" destination="r1z-jS-qK4" id="844-dB-a5N"/> |
| | | <outlet property="label_surplusProcess" destination="SYT-bU-Qar" id="z3n-Ny-Yfs"/> |
| | | <outlet property="tableView" destination="byc-YG-6j2" id="BDN-57-WDq"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | <outlet property="view_menu" destination="1HY-aY-obo" id="m6s-HL-ZwQ"/> |
| | |
| | | |
| | | import UIKit |
| | | import JQTools |
| | | import AVFoundation |
| | | |
| | | class StudyHandleView: UIView,JQNibView{ |
| | | @IBOutlet weak var btn_choose: UIButton! |
| | |
| | | |
| | | var listenType:ListenType? |
| | | private var clouse:((UIButton)->Void)? |
| | | private var playComplete:(()->Void)? |
| | | private var playAtClouse:((Int)->Void)? |
| | | |
| | | private var voicePlayer = VoicePlayer.share() |
| | | var vioceSoundUrl:String? |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | btn_state.alpha = 0 |
| | | view_choose.alpha = 0 |
| | | |
| | | voicePlayer.playEnd {[weak self] in |
| | | self?.reset() |
| | | } |
| | | } |
| | | |
| | | func chooseClouse(callback:@escaping (UIButton)->Void){ |
| | | clouse = callback |
| | | } |
| | | |
| | | func playAt(_ clouse:@escaping(Int)->Void){ |
| | | self.playAtClouse = clouse |
| | | } |
| | | |
| | | func copyView()->StudyHandleView{ |
| | |
| | | return copyV |
| | | } |
| | | |
| | | @IBAction func payAction(_ sender: UIButton) { |
| | | func reset(){ |
| | | switch listenType { |
| | | case .lesson1: |
| | | case .lesson1,.lesson5: |
| | | btn_state.setImage(UIImage(named: "icon_play"), for: .normal) |
| | | btn_voice.alpha = 1 |
| | | btn_pay.alpha = 1 |
| | | btn_state.alpha = 0 |
| | | case .lesson2: |
| | | view_choose.alpha = 1 |
| | | default:break |
| | | } |
| | | self.superview?.layoutIfNeeded() |
| | | } |
| | | |
| | | @IBAction func payAction(_ sender: UIButton) { |
| | | guard let v = vioceSoundUrl else {return} |
| | | voicePlayer.playerAt(url: v) |
| | | playAtClouse?(self.tag) |
| | | switch listenType { |
| | | case .lesson1,.lesson5: |
| | | btn_state.setImage(UIImage(named: "icon_playing"), for: .normal) |
| | | btn_voice.alpha = 0 |
| | | btn_pay.alpha = 0 |
| | |
| | | default:break |
| | | } |
| | | } |
| | | |
| | | |
| | | @IBAction func chooseAction(_ sender: UIButton) { |
| | | sender.isSelected = !sender.isSelected |
| | | clouse?(sender) |
| | |
| | | // |
| | | // } |
| | | // ob.onError(NetRequestError.InvaildSession) |
| | | case 401: |
| | | case 401,505,600: |
| | | if !ignoreAlert{ |
| | | alertError(msg: "登录失效,请重新登录");ob.onError(NetRequestError.InvaildSession) |
| | | } |
| | |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/weekList") |
| | | params.append(key: "quarter", value: quarter) |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | |
| | | /// 自主学习1-听音选图 |
| | | class func listenSelectPicture(day:Int,quarter:Int,week:Int)->Observable<BaseResponse<Listen1Model>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/listenSelectPicture") |
| | | params.append(key: "quarter", value: quarter) |
| | | params.append(key: "day", value: day) |
| | | params.append(key: "week", value: week) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | |
| | | /// 自主学习2-看图选音 |
| | | class func pictureSelectVoice(day:Int,quarter:Int,week:Int)->Observable<BaseResponse<Listen1Model>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/pictureSelectVoice") |
| | | params.append(key: "quarter", value: quarter) |
| | | params.append(key: "day", value: day) |
| | | params.append(key: "week", value: week) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | /// 自主学习3-归纳排除 |
| | | class func induceExclude(day:Int,quarter:Int,week:Int)->Observable<BaseResponse<Listen1Model>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/induceExclude") |
| | | params.append(key: "quarter", value: quarter) |
| | | params.append(key: "day", value: day) |
| | | params.append(key: "week", value: week) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | /// 自主学习4-有问有答 |
| | | class func questionsAndAnswers(day:Int,quarter:Int,week:Int)->Observable<BaseResponse<Listen4Model>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/questionsAndAnswers") |
| | | params.append(key: "quarter", value: quarter) |
| | | params.append(key: "day", value: day) |
| | | params.append(key: "week", value: week) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | /// 自主学习5-音图相配 |
| | | class func pictureMateVoice(day:Int,quarter:Int,week:Int)->Observable<BaseResponse<Listen1Model>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/pictureMateVoice") |
| | | params.append(key: "quarter", value: quarter) |
| | | params.append(key: "day", value: day) |
| | | params.append(key: "week", value: week) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | /// 完成学习 |
| | | class func completeLearing(type:Int,studyTime:Int,studyIds:[Int],isComplete:Bool)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/completeLearning") |
| | | .append(key: "type", value: type) |
| | | .append(key: "studyTime", value: studyTime) |
| | | .append(key: "studyIds", value: studyIds.map({"\($0)"})) |
| | | .append(key: "isComplete", value: isComplete) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding.default, progress: true) |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | class func studyGamesRecord()->Observable<BaseResponse<StudyGamesModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/record") |
| | | params.interface(url: "/study/base/study/studyRecord") |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | |
| | | struct UserInfoModel:HandyJSON,Identifiable,Codable{ |
| | | static let idKey = \UserInfoModel.id |
| | | var id: Int = 0 |
| | | var user:UserInfoUserModel? |
| | | var userStudy:UserInfoStudyModel? |
| | | |
| | | } |
| | | |
| | | struct UserInfoUserModel:HandyJSON,Codable{ |
| | | var account: String = "" |
| | | var birthday: String = "" |
| | | var createBy: String = "" |
| | |
| | | var updateTime: String = "" |
| | | var vipEndTime: String = "" |
| | | var vipPayTime: String = "" |
| | | } |
| | | |
| | | struct UserInfoStudyModel:HandyJSON,Codable{ |
| | | var answer: Int = 0 |
| | | var day: Int = 0 |
| | | var id: Int = 0 |
| | | var induction: Int = 0 |
| | | var listen: Int = 0 |
| | | var look: Int = 0 |
| | | var monthStudy: Int = 0 |
| | | var pair: Int = 0 |
| | | var surplus: Int = 0 |
| | | var todayStudy: Int = 0 |
| | | var totalStudy: Int = 0 |
| | | var updateBy: String? |
| | | var updateTime: String? |
| | | var userId: Int = 0 |
| | | var week: Int = 0 |
| | | var weekStudy: Int = 0 |
| | | } |
| | | |
| | | class UserViewModel{ |