From c1862d736587c9a5c10a368dabaeb72be2df4bcb Mon Sep 17 00:00:00 2001 From: 无故事王国 <841720330@qq.com> Date: 星期二, 18 六月 2024 16:26:23 +0800 Subject: [PATCH] fix --- DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenSubVC.swift | 2 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFightVC.swift | 38 -- DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_1_VC.swift | 4 DolphinEnglishLearnStudent/Config/VoicePlayer.swift | 124 +++++++- DolphinEnglishLearnStudent/Config/LaunchImageHelper.swift | 253 ++++++++++++++++++ DolphinEnglishLearnStudent/Moudle/Home/VC/HomeStudyCompleteVC.swift | 2 DolphinEnglishLearnStudent/Moudle/Home/HomeVC.xib | 2 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_2_VC.swift | 17 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_5_VC.swift | 9 DolphinEnglishLearnStudent/Moudle/Home/HomeVC.swift | 26 + DolphinEnglishLearnStudent/Services/Services.swift | 18 + DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift | 12 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenMenuVC.swift | 7 DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.xib | 8 DolphinEnglishLearnStudent/SceneDelegate.swift | 3 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_2_VC.swift | 3 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_1_VC.swift | 3 DolphinEnglishLearnStudent/Info.plist | 5 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenVC.swift | 2 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_4_VC.swift | 3 DolphinEnglishLearnStudent/Services/NetworkRequest.swift | 16 DolphinEnglishLearnStudent/Base/BaseVC.swift | 19 - DolphinEnglishLearnStudent/Config/Config.swift | 8 DolphinEnglishLearnStudent/Moudle/Me/VC/AddressManageHandleVC.xib | 2 DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_2_VC.swift | 25 - DolphinEnglishLearnStudent/Models/CommonModel.swift | 17 + DolphinEnglishLearnStudent/Base/BaseNav.swift | 83 ----- DolphinEnglishLearnStudent.xcodeproj/project.pbxproj | 4 DolphinEnglishLearnStudent/Moudle/Home/HomeListenFight_lesson_1_VC.swift | 18 + DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_3_VC.swift | 99 ++++-- 30 files changed, 571 insertions(+), 261 deletions(-) diff --git a/DolphinEnglishLearnStudent.xcodeproj/project.pbxproj b/DolphinEnglishLearnStudent.xcodeproj/project.pbxproj index 18f94fb..b49925a 100644 --- a/DolphinEnglishLearnStudent.xcodeproj/project.pbxproj +++ b/DolphinEnglishLearnStudent.xcodeproj/project.pbxproj @@ -98,6 +98,7 @@ 13CDF44F2C05756C00E8D4FD /* Lesson_4_AnswerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CDF44E2C05756C00E8D4FD /* Lesson_4_AnswerView.swift */; }; 13CDF4512C05757400E8D4FD /* Lesson_4_AnswerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13CDF4502C05757400E8D4FD /* Lesson_4_AnswerView.xib */; }; 13E07DF12BFDF1E600B7F5FB /* ExchangeRecordHistoryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13E07DF02BFDF1E600B7F5FB /* ExchangeRecordHistoryVC.swift */; }; + 13E99EFA2C1FD1A9004F52D4 /* LaunchImageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13E99EF92C1FD1A9004F52D4 /* LaunchImageHelper.swift */; }; 13EEB8912BFED3F3002996FC /* AwardListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EEB8902BFED3F3002996FC /* AwardListView.swift */; }; 13EEB8932BFED3FA002996FC /* AwardListView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13EEB8922BFED3FA002996FC /* AwardListView.xib */; }; 13EEB8972BFF1531002996FC /* AwardListCCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EEB8952BFF1531002996FC /* AwardListCCell.swift */; }; @@ -208,6 +209,7 @@ 13CDF44E2C05756C00E8D4FD /* Lesson_4_AnswerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lesson_4_AnswerView.swift; sourceTree = "<group>"; }; 13CDF4502C05757400E8D4FD /* Lesson_4_AnswerView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Lesson_4_AnswerView.xib; sourceTree = "<group>"; }; 13E07DF02BFDF1E600B7F5FB /* ExchangeRecordHistoryVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExchangeRecordHistoryVC.swift; sourceTree = "<group>"; }; + 13E99EF92C1FD1A9004F52D4 /* LaunchImageHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchImageHelper.swift; sourceTree = "<group>"; }; 13EEB8902BFED3F3002996FC /* AwardListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AwardListView.swift; sourceTree = "<group>"; }; 13EEB8922BFED3FA002996FC /* AwardListView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AwardListView.xib; sourceTree = "<group>"; }; 13EEB8952BFF1531002996FC /* AwardListCCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AwardListCCell.swift; sourceTree = "<group>"; }; @@ -291,6 +293,7 @@ 130278402BFD978900DDCE81 /* Config */ = { isa = PBXGroup; children = ( + 13E99EF92C1FD1A9004F52D4 /* LaunchImageHelper.swift */, 1302783E2BFD978900DDCE81 /* Config.swift */, 1302783F2BFD978900DDCE81 /* Enums.swift */, 13812B9B2C0F02B600905CCE /* VoicePlayer.swift */, @@ -794,6 +797,7 @@ 133386382C007E91002EE788 /* HomeListenFight_lesson_2_VC.swift in Sources */, 13812B9C2C0F02B700905CCE /* VoicePlayer.swift in Sources */, 1302787B2BFD9ED600DDCE81 /* MarketContentVC.swift in Sources */, + 13E99EFA2C1FD1A9004F52D4 /* LaunchImageHelper.swift in Sources */, 13649E9C2C00304C001B04E2 /* ListenFight_lesson_1_CCell.swift in Sources */, 13EEB8A02BFF28A7002996FC /* HomeListenVC.swift in Sources */, 130278492BFD979200DDCE81 /* BaseTabBarVC.swift in Sources */, diff --git a/DolphinEnglishLearnStudent/Base/BaseNav.swift b/DolphinEnglishLearnStudent/Base/BaseNav.swift index fc3e54b..fe5cbce 100644 --- a/DolphinEnglishLearnStudent/Base/BaseNav.swift +++ b/DolphinEnglishLearnStudent/Base/BaseNav.swift @@ -11,7 +11,7 @@ class BaseNav: UINavigationController,UINavigationControllerDelegate { /// 需要透明Nav的VC - private var lucencyVCs = [HomeVC.self] + private var lucencyVCs = [HomeVC.self,LoginVC.self,CommonWebVC.self] private let img = UIImage.jq_gradient(["#B6E0FF","#FFFFFF"],size: CGSize(width: JQ_ScreenW, height: 90),direction: GradientDirection.vertical) @@ -51,17 +51,6 @@ navigationBar.setBackgroundImage(UIImage(), for: .default) navigationBar.shadowImage = UIImage() } - -// let titleV = UIView() -// titleV.sizeToFit() -// let imgV = UIImageView(image: UIImage(named: "bg_logo")) -// imgV.contentMode = .scaleAspectFit -// titleV.addSubview(imgV) -// imgV.snp.makeConstraints { make in -// make.edges.equalToSuperview() -// } -// -// navigationItem.titleView = titleV } open func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { @@ -106,74 +95,4 @@ override var preferredStatusBarStyle: UIStatusBarStyle{ return .lightContent } - -} - - -class LoginNav: UINavigationController,UINavigationControllerDelegate { - - private var popDelegate: UIGestureRecognizerDelegate? - - open override func viewDidLoad() { - super.viewDidLoad() - self.navigationBar.barTintColor = .white - self.navigationBar.titleTextAttributes = [.font:UIFont.systemFont(ofSize: 18, weight: .medium), .foregroundColor:UIColor.black] - self.navigationBar.tintColor = UIColor.black - self.navigationBar.shadowImage = UIImage() - self.navigationBar.isTranslucent = true - self.delegate = self - self.popDelegate = self.interactivePopGestureRecognizer?.delegate - - - if #available(iOS 15.0, *) { - - let scrollBar = UINavigationBarAppearance() - scrollBar.configureWithOpaqueBackground() - scrollBar.backgroundEffect = nil - scrollBar.shadowColor = nil - scrollBar.titleTextAttributes = [.foregroundColor:Config.ThemeColor,.font:Config.NavFont] - scrollBar.backgroundColor = UIColor.clear - // scrollBar.backgroundImage = img - - - let standardBar = UINavigationBarAppearance() - standardBar.configureWithOpaqueBackground() - standardBar.backgroundEffect = nil - standardBar.shadowColor = nil - standardBar.shadowImage = nil - standardBar.titleTextAttributes = [.foregroundColor:Config.ThemeColor,.font:Config.NavFont] - standardBar.backgroundColor = UIColor.clear - // standardBar.backgroundImage = img - - navigationBar.scrollEdgeAppearance = scrollBar //顶部透明 - navigationBar.standardAppearance = standardBar - - - }else { - navigationBar.titleTextAttributes = [.foregroundColor:Config.ThemeColor,.font:Config.NavFont] - } - } - - open func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { - - - } - - //侧滑 - public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { - if viewController == self.viewControllers[0] { - self.interactivePopGestureRecognizer!.delegate = self.popDelegate - }else{ - self.interactivePopGestureRecognizer!.delegate = nil - } - } - - open override var childForStatusBarHidden: UIViewController? { - return self.topViewController - } - - open override var childForStatusBarStyle: UIViewController? { - return self.topViewController - } - } diff --git a/DolphinEnglishLearnStudent/Base/BaseVC.swift b/DolphinEnglishLearnStudent/Base/BaseVC.swift index 2de1e45..a87805d 100644 --- a/DolphinEnglishLearnStudent/Base/BaseVC.swift +++ b/DolphinEnglishLearnStudent/Base/BaseVC.swift @@ -33,15 +33,6 @@ override func viewDidLoad() { super.viewDidLoad() -// let bgGradientImg = UIImageView(image: UIImage.jq_gradient(["#B6E0FF","#FFFFFF"],size: CGSize(width: JQ_ScreenW, height: JQ_ScreenH), direction: .vertical)) -// -// view.addSubview(bgGradientImg) -// bgGradientImg.snp.makeConstraints { make in -// make.top.left.right.equalToSuperview() -// make.height.equalTo(JQ_ScreenW * 0.46) -// } -// view.sendSubviewToBack(bgGradientImg) -// view.backgroundColor = .white disposeBag = DisposeBag() setUI() @@ -60,9 +51,9 @@ navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backButton) } - if !self.isKind(of: HomeVC.self) && !self.isKind(of: HomeListenSubVC.self) && !self.isKind(of: HomeListenFight_lesson_1_VC.self) && !self.isKind(of: HomeListenFight_lesson_2_VC.self) && !self.isKind(of: HomeListenFight_lesson_3_VC.self) && !self.isKind(of: HomeListenFight_lesson_4_VC.self) && !self.isKind(of: HomeListenFight_lesson_5_VC.self) && !self.isKind(of: HomeListenGame_1_VC.self) && !self.isKind(of: HomeListenGame_2_VC.self) && !self.isKind(of: HomeListenStory_1_VC.self) && !self.isKind(of: HomeListenStory_2_VC.self){ + if !self.isKind(of: HomeVC.self) && !self.isKind(of: HomeListenSubVC.self) && !self.isKind(of: HomeListenFight_lesson_1_VC.self) && !self.isKind(of: HomeListenFight_lesson_2_VC.self) && !self.isKind(of: HomeListenFight_lesson_3_VC.self) && !self.isKind(of: HomeListenFight_lesson_4_VC.self) && !self.isKind(of: HomeListenFight_lesson_5_VC.self) && !self.isKind(of: HomeListenGame_1_VC.self) && !self.isKind(of: HomeListenGame_2_VC.self) && !self.isKind(of: HomeListenStory_1_VC.self) && !self.isKind(of: HomeListenStory_2_VC.self) && !self.isKind(of: LoginVC.self){ let titleV = UIView() - titleV.bounds = CGRect(x: 0, y: 0, width: 156, height: 63) +// titleV.bounds = CGRect(x: 0, y: 0, width: 156, height: 24) titleV.sizeToFit() let imgV = UIImageView(image: UIImage(named: "bg_logo")) imgV.contentMode = .scaleAspectFit @@ -73,15 +64,11 @@ view.addSubview(titleV) titleV.snp.makeConstraints { make in - make.top.equalToSuperview().offset(18) - make.centerX.equalToSuperview() + make.center.equalToSuperview() } navigationItem.titleView = titleV - } - - } func setRx(){ diff --git a/DolphinEnglishLearnStudent/Config/Config.swift b/DolphinEnglishLearnStudent/Config/Config.swift index f37c501..11177b3 100644 --- a/DolphinEnglishLearnStudent/Config/Config.swift +++ b/DolphinEnglishLearnStudent/Config/Config.swift @@ -118,11 +118,9 @@ self.isUserInteractionEnabled = true }); }else { - DispatchQueue.main.async(execute: { - self.setTitle("\(time)s", for: .normal) - self.setTitleColor(unenableColor, for: .normal) - self.isUserInteractionEnabled = false - }); + self.setTitle("\(time)s", for: .normal) + self.setTitleColor(unenableColor, for: .normal) + self.isUserInteractionEnabled = false } time -= 1 }); diff --git a/DolphinEnglishLearnStudent/Config/LaunchImageHelper.swift b/DolphinEnglishLearnStudent/Config/LaunchImageHelper.swift new file mode 100644 index 0000000..e92fc06 --- /dev/null +++ b/DolphinEnglishLearnStudent/Config/LaunchImageHelper.swift @@ -0,0 +1,253 @@ +// +// LaunchImageHelper.swift +// WanPai +// +// Created by 无故事王国 on 2023/10/19. +// + +import Foundation + +class LaunchImageHelper { + static func snapshotStoryboard(sbName: String, isPortrait: Bool) -> UIImage? { + if sbName.isEmpty { + return nil + } + + let storyboard = UIStoryboard(name: sbName, bundle: nil) + guard let vc = storyboard.instantiateInitialViewController() else { + return nil + } + + vc.view.frame = UIScreen.main.bounds + if isPortrait { + if vc.view.frame.size.width > vc.view.frame.size.height { + vc.view.frame = CGRect(x: 0, y: 0, width: vc.view.frame.size.height, height: vc.view.frame.size.width) + } + } else { + if vc.view.frame.size.width < vc.view.frame.size.height { + vc.view.frame = CGRect(x: 0, y: 0, width: vc.view.frame.size.height, height: vc.view.frame.size.width) + } + } + + vc.view.setNeedsLayout() + vc.view.layoutIfNeeded() + + UIGraphicsBeginImageContextWithOptions(vc.view.frame.size, false, UIScreen.main.scale) + vc.view.layer.render(in: UIGraphicsGetCurrentContext()!) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return image + } + + static func snapshotStoryboardForPortrait(sbName: String) -> UIImage? { + return snapshotStoryboard(sbName: sbName, isPortrait: true) + } + + static func snapshotStoryboardForLandscape(sbName: String) -> UIImage? { + return snapshotStoryboard(sbName: sbName, isPortrait: false) + } + + static func changeAllLaunchImageToPortrait(_ image: UIImage?) { + guard let image = image else { + return + } + // 全部替换为竖屏启动图 + let resizedImage = resizeImage(image, toPortraitScreenSize: true) + BBADynamicLaunchImage.replaceLaunchImage(resizedImage) + } + + static func changeAllLaunchImageToLandscape(_ image: UIImage?) { + guard let image = image else { + return + } + // 全部替换为横屏启动图 + let resizedImage = resizeImage(image, toPortraitScreenSize: false) + BBADynamicLaunchImage.replaceLaunchImage(resizedImage) + } + + static func changePortraitLaunchImage(_ p: UIImage) { + // Implementation for this function is missing + } + + static func resizeImage(_ image: UIImage, toPortraitScreenSize: Bool) -> UIImage { + // Implementation for this function is missing + return image + } +} + + +private class BBADynamicLaunchImage { + static func launchImageCacheDirectory() -> String? { + let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String + let fm = FileManager.default + + // iOS13之前 + if var cachesDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first { + cachesDirectory.append(contentsOf: "Snapshots") + cachesDirectory.append(contentsOf: bundleID!) + if fm.fileExists(atPath: cachesDirectory) { + return cachesDirectory + } + } + + // iOS13 + if let libraryDirectory = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first { + let snapshotsPath = String(format: "%@/SplashBoard/Snapshots/%@ - {DEFAULT GROUP}", libraryDirectory, bundleID ?? "") + if fm.fileExists(atPath: snapshotsPath) { + return snapshotsPath + } + } + + return nil + } + + static func isSnapShotName(_ name: String) -> Bool { + // 新系统后缀 + let snapshotSuffixs = ".ktx" + if name.hasSuffix(snapshotSuffixs) { + return true + } + + // 老系统后缀 + let snapshotSuffixs2 = ".png" + if name.hasSuffix(snapshotSuffixs2) { + return true + } + + return false + } + + @discardableResult + static func replaceLaunchImage(_ replacementImage: UIImage?) -> Bool { + guard let image = replacementImage else {return false} + return self.replaceLaunchImage(replacementImage: image, compressionQuality: 0.8, customValidation: nil) + } + + @discardableResult + static func replaceLaunchImage(_ replacementImage: UIImage?, compressionQuality: CGFloat) -> Bool { + guard let image = replacementImage else {return false} + return self.replaceLaunchImage(replacementImage: image, compressionQuality: compressionQuality, customValidation: nil) + } + + static func replaceLaunchImage(replacementImage: UIImage, compressionQuality: CGFloat, customValidation: ((UIImage,UIImage) -> Bool)?) -> Bool { + + let data = replacementImage.jpegData(compressionQuality: compressionQuality) + if data == nil { + return false + } + + // if !checkImageMatchScreenSize(image: replacementImage) { + // return false + // } + + guard let cacheDir = launchImageCacheDirectory() else { + return false + } + + let cachesParentDir = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0] + let tmpDir = (cachesParentDir as NSString).appendingPathComponent("_tmpLaunchImageCaches") + + let fm = FileManager.default + if fm.fileExists(atPath: tmpDir) { + do { + try fm.removeItem(atPath: tmpDir) + } catch { + return false + } + } + + do { + try fm.moveItem(atPath: cacheDir, toPath: tmpDir) + } catch { + return false + } + + var cacheImageNames = [String]() + if let contents = try? fm.contentsOfDirectory(atPath: tmpDir) { + for name in contents { + if isSnapShotName(name) { + cacheImageNames.append(name) + } + } + } + + for name in cacheImageNames { + let filePath = (tmpDir as NSString).appendingPathComponent(name) + var result = true + + if customValidation != nil{ + if let cachedImageData = try? Data(contentsOf: URL(string: filePath)!),let cachedImage = imageFromData(data: cachedImageData as NSData){ + result = customValidation!(cachedImage,replacementImage) + } + } + + if result { + do { + try data?.write(to: URL(fileURLWithPath: filePath), options: .atomic) + } catch { + return false + } + } + } + + + try? fm.moveItem(atPath: tmpDir, toPath: cacheDir) + if fm.fileExists(atPath: tmpDir) { + do { + try fm.removeItem(atPath: tmpDir) + } catch { + return false + } + } + + return true + } + + + + static func imageFromData(data: NSData) -> UIImage? { + guard let source = CGImageSourceCreateWithData(data, nil) else { + return nil + } + + if let imageRef = CGImageSourceCreateImageAtIndex(source, 0, nil) { + let originImage = UIImage(cgImage: imageRef) + return originImage + } + + return nil + } + + func getImageSize(imageData: NSData) -> CGSize { + guard let source = CGImageSourceCreateWithData(imageData, nil) else { + return CGSize.zero + } + + if let imageRef = CGImageSourceCreateImageAtIndex(source, 0, nil) { + let width = CGFloat(imageRef.width) + let height = CGFloat(imageRef.height) + return CGSize(width: width, height: height) + } + + return CGSize.zero + } + + + /// 检查图片大小 + static func checkImageMatchScreenSize(image: UIImage) -> Bool { + let screenSize = CGSize(width: UIScreen.main.bounds.size.width * UIScreen.main.scale, + height: UIScreen.main.bounds.size.height * UIScreen.main.scale) + let imageSize = CGSize(width: image.size.width * image.scale, + height: image.size.height * image.scale) + + if imageSize.equalTo(screenSize) { + return true + } + + if imageSize.equalTo(CGSize(width: screenSize.height, height: screenSize.width)) { + return true + } + + return false + } +} diff --git a/DolphinEnglishLearnStudent/Config/VoicePlayer.swift b/DolphinEnglishLearnStudent/Config/VoicePlayer.swift index dfea953..c64fbab 100644 --- a/DolphinEnglishLearnStudent/Config/VoicePlayer.swift +++ b/DolphinEnglishLearnStudent/Config/VoicePlayer.swift @@ -20,6 +20,7 @@ private let voiceCacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("voices") private static var _sharedInstance: VoicePlayer? private var player:AVAudioPlayer? + private var tempPlayer:AVAudioPlayer? var delegate:VoicePlayerDelegate? @@ -52,27 +53,89 @@ guard let u = url else {return} if player?.isPlaying ?? false{ player?.stop() - self.playComplete?() //先通知完成播放 } + //文件存在:直接播放缓存路径的语音 + let fileURL = self.voiceCacheDirectory.appendingPathComponent(URL(fileURLWithPath: u).lastPathComponent).droppedScheme() + if FileManager.default.fileExists(atPath: fileURL!.absoluteString){ + self.player = try? AVAudioPlayer(contentsOf: fileURL!) + self.player?.delegate = self + self.player?.play() + self.delegate?.playing() + }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() + self.delegate?.playing() + } catch { + print("视频缓存失败:catch") + } + } else { + print("视频缓存失败:\(error?.localizedDescription ?? "")") + } + } + downloadTask.resume() + } + } - //文件存在:直接播放缓存路径的语音 - 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() - delegate?.playing() - }else{ + func playerEnd(){ + player?.stop() + playComplete?() + } + + //打断播放未完全播放 + func playerInterrupt(){ + player?.stop() + } + + func playEnd(course:@escaping ()->Void){ + self.playComplete = course + } + + func playSuccessVoice(){ + let list = try? FileManager.default.contentsOfDirectory(atPath: voiceCacheDirectory.droppedScheme()!.absoluteString) + var promoteName:String? + for v in list ?? []{ + if v.contains("SuccessPromote"){promoteName = v;break} + } + guard let url = promoteName else { return } + let promote = self.voiceCacheDirectory.appendingPathComponent(url) + tempPlayer = try? AVAudioPlayer(contentsOf: promote) + tempPlayer?.play() + } + + func playFailVoice(){ + let list = try? FileManager.default.contentsOfDirectory(atPath: voiceCacheDirectory.droppedScheme()!.absoluteString) + var promoteName:String? + for v in list ?? []{ + if v.contains("FailPromote"){promoteName = v;break} + } + guard let url = promoteName else { return } + let promote = self.voiceCacheDirectory.appendingPathComponent(url) + tempPlayer = try? AVAudioPlayer(contentsOf: promote) + tempPlayer?.play() + } + + func donwloadPromoteVoice(successVoice:String,failVoice:String,updateTime:String){ + print("-->\(VoicePlayer.share().voiceCacheDirectory)") + let group = DispatchGroup() + let promoteQueue = DispatchQueue(label: "promoteVoice") + promoteQueue.async(group: group){ //文件不存在:执行下载 - let downloadTask = URLSession.shared.downloadTask(with: URL(string: u)!) { tempLocalUrl, response, error in + let downloadTask = URLSession.shared.downloadTask(with: URL(string: successVoice)!) { tempLocalUrl, response, error in if let tempLocalUrl = tempLocalUrl, error == nil { do { - let finalCacheUrl = self.voiceCacheDirectory.appendingPathComponent(URL(fileURLWithPath: u).lastPathComponent) + let fileType = URL(fileURLWithPath: successVoice).lastPathComponent.components(separatedBy: ".").last ?? "mp3" + let finalCacheUrl = self.voiceCacheDirectory.appendingPathComponent("SuccessPromote.\(fileType)") + if FileManager.default.fileExists(atPath: finalCacheUrl.droppedScheme()!.absoluteString){ + try? FileManager.default.removeItem(at: finalCacheUrl) + } try FileManager.default.moveItem(at: tempLocalUrl, to: finalCacheUrl) - self.player = try? AVAudioPlayer(contentsOf: finalCacheUrl) - self.player?.delegate = self - self.player?.play() - self.delegate?.playing() } catch { print("视频缓存失败:catch") } @@ -82,15 +145,32 @@ } downloadTask.resume() } - } - func playerEnd(){ - player?.stop() - playComplete?() - } + promoteQueue.async(group: group){ + //文件不存在:执行下载 + let downloadTask = URLSession.shared.downloadTask(with: URL(string: failVoice)!) { tempLocalUrl, response, error in + if let tempLocalUrl = tempLocalUrl, error == nil { + do { + let fileType = URL(fileURLWithPath: successVoice).lastPathComponent.components(separatedBy: ".").last ?? "mp3" + let finalCacheUrl = self.voiceCacheDirectory.appendingPathComponent("FailPromote.\(fileType)") + if FileManager.default.fileExists(atPath: finalCacheUrl.droppedScheme()!.absoluteString){ + try? FileManager.default.removeItem(at: finalCacheUrl) + } + try FileManager.default.moveItem(at: tempLocalUrl, to: finalCacheUrl) + } catch { + print("视频缓存失败:catch") + } + } else { + print("视频缓存失败:\(error?.localizedDescription ?? "")") + } + } + downloadTask.resume() + } - func playEnd(course:@escaping ()->Void){ - self.playComplete = course + group.notify(queue: .main){ + UserDefaults.standard.setValue(updateTime, forKey: "promptVoiceDate") + UserDefaults.standard.synchronize() + } } } diff --git a/DolphinEnglishLearnStudent/Info.plist b/DolphinEnglishLearnStudent/Info.plist index dd3c9af..c0ae0b4 100644 --- a/DolphinEnglishLearnStudent/Info.plist +++ b/DolphinEnglishLearnStudent/Info.plist @@ -2,6 +2,11 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSAllowsArbitraryLoads</key> + <true/> + </dict> <key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> diff --git a/DolphinEnglishLearnStudent/Models/CommonModel.swift b/DolphinEnglishLearnStudent/Models/CommonModel.swift index 3319ed7..5d57ffd 100644 --- a/DolphinEnglishLearnStudent/Models/CommonModel.swift +++ b/DolphinEnglishLearnStudent/Models/CommonModel.swift @@ -386,3 +386,20 @@ var isOpen:Bool = false var type = 0 // 1:图片 2:音频 } + +struct PromptVoiceModel:HandyJSON{ + var correct: String = "" + var createBy: String = "" + var createTime: String = "" + var disabled: Bool = false + var error: String = "" + var id: Int = 0 + var img: String = "" + var integral: String = "" + var integralShare: String = "" + var phone: String = "" + var time: String = "" + var title: String = "" + var updateBy: String = "" + var updateTime: String = "" +} diff --git a/DolphinEnglishLearnStudent/Moudle/Home/HomeListenFight_lesson_1_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/HomeListenFight_lesson_1_VC.swift index 7b6fb4f..7da2182 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/HomeListenFight_lesson_1_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/HomeListenFight_lesson_1_VC.swift @@ -77,6 +77,7 @@ override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) VoicePlayer.share().delegate = nil + VoicePlayer.share().playerInterrupt() } @@ -91,6 +92,7 @@ } private func getNextAnswer(){ + isListen = false if isAnsterModel.count == 4{ print("答题答满了");return } @@ -109,6 +111,12 @@ viewModel.answerType.accept(.none) collectionView.reloadData() setUI() + + //自动播放下一题语音 + DispatchQueue.main.asyncAfter(deadline: .now()+2) { + VoicePlayer.share().playerAt(url: self.randomElement?.correct) + self.menuView?.playing() + } } override func setUI() { @@ -158,13 +166,20 @@ var answer:Fight_lessonType = .none if self?.randomElement?.id == weakSelf.listenNewModel.subjectList[weakSelf.page][index.row].id{ answer = .success + self?.isListen = false if self?.isAnsterComplete == false{ self?.rootViewModel.correctNum += 1 } self?.isAnsterComplete = true - VoicePlayer.share().playerAt(url: weakSelf.listenNewModel.subjectList[weakSelf.page][index.row].correct) + + VoicePlayer.share().playSuccessVoice() + DispatchQueue.main.asyncAfter(deadline: .now()+2) { + VoicePlayer.share().playerAt(url: weakSelf.listenNewModel.subjectList[weakSelf.page][index.row].correct) + } }else{ answer = .fail + VoicePlayer.share().playFailVoice() + self?.isListen = false if self?.isAnsterComplete == false{ self?.rootViewModel.errorNum += 1 } @@ -256,6 +271,7 @@ weakSelf.viewModel.answerType.accept(.none) weakSelf.viewModel.selectIndex.accept(nil) weakSelf.rootViewModel.answerItems[weakSelf.page] = weakSelf.listenNewModel.subjectList[weakSelf.page] + weakSelf.isListen = false } } diff --git a/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.swift b/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.swift index 6e0ab31..c968cbf 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.swift @@ -6,19 +6,29 @@ // import UIKit +import SDWebImage class HomeVC: BaseVC { override func viewDidLoad() { super.viewDidLoad() - Services.goodRecommend().subscribe(onNext: { data in - 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) + + Services.parentPage().subscribe(onNext: {data in + if let img = data.data{ + SDWebImageDownloader.shared.downloadImage(with: URL(string: img)) { image, _, _, _ in + if let img = image{ + LaunchImageHelper.changeAllLaunchImageToLandscape(img) + } + } + } + }).disposed(by: disposeBag) + + Services.promptVoice().subscribe(onNext: {data in + if let model = data.data{ + let voice = UserDefaults.standard.object(forKey: "promptVoiceDate") as? String + if model.updateTime != voice{ + VoicePlayer.share().donwloadPromoteVoice(successVoice: model.correct, failVoice: model.error,updateTime: model.updateTime) + } } }).disposed(by: disposeBag) } diff --git a/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.xib b/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.xib index 11cfa86..daa6c96 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.xib +++ b/DolphinEnglishLearnStudent/Moudle/Home/HomeVC.xib @@ -172,7 +172,7 @@ </view> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="听" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rYc-7O-AJr"> <rect key="frame" x="99" y="0.0" width="281" height="88"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="24"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift index 8815877..a075c81 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift @@ -14,7 +14,9 @@ @IBOutlet weak var view_container: UIView! @IBOutlet weak var btn_play: UIButton! @IBOutlet weak var btn_playing: UIButton! - + @IBOutlet weak var view_playHandle: UIView! + @IBOutlet weak var img_playing: UIImageView! + private var model:Listen1SubModel! private var playAtClouse:((IndexPath)->Void)? var indexPath:IndexPath! @@ -28,15 +30,21 @@ func setModel(_ model:Listen1SubModel,isplaying:Bool){ self.model = model self.btn_play.alpha = (isplaying ? 0:1) + self.btn_playing.alpha = (isplaying ? 0:1) + self.img_playing.alpha = (isplaying ? 1:0) } func palyVoiceAt(_ clouse:@escaping(IndexPath)->Void){ self.playAtClouse = clouse } + func canClick(_ state:Bool){ + btn_play.isEnabled = state + view_playHandle.backgroundColor = state == true ? UIColor(hexString: "#41A2EB") : .gray + } + @IBAction func playAction(_ sender: Any) { - VoicePlayer.share().playerAt(url: model.correct) playAtClouse?(indexPath) } } diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.xib b/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.xib index fce015d..e73fe3f 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.xib +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.xib @@ -33,15 +33,20 @@ <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_playing" translatesAutoresizingMaskIntoConstraints="NO" id="vMh-x4-Y7a"> + <rect key="frame" x="57" y="10.5" width="45" height="31"/> + </imageView> </subviews> <color key="backgroundColor" red="0.25490196078431371" green="0.63529411764705879" blue="0.92156862745098034" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="9Dc-Ns-SMP" firstAttribute="centerY" secondItem="vtr-2e-B5C" secondAttribute="centerY" id="C8e-Iq-OaB"/> <constraint firstItem="7yc-PU-RgV" firstAttribute="centerY" secondItem="vtr-2e-B5C" secondAttribute="centerY" id="EUe-pu-sAP"/> + <constraint firstItem="vMh-x4-Y7a" firstAttribute="centerX" secondItem="vtr-2e-B5C" secondAttribute="centerX" id="ObG-a0-OcJ"/> <constraint firstAttribute="trailing" secondItem="7yc-PU-RgV" secondAttribute="trailing" constant="23" id="Rms-9S-fkG"/> <constraint firstAttribute="height" constant="52" id="Y2Z-EL-K2n"/> <constraint firstAttribute="width" constant="159" id="oI7-Oh-ubD"/> <constraint firstItem="9Dc-Ns-SMP" firstAttribute="leading" secondItem="vtr-2e-B5C" secondAttribute="leading" constant="25" id="xRi-cc-X9V"/> + <constraint firstItem="vMh-x4-Y7a" firstAttribute="centerY" secondItem="vtr-2e-B5C" secondAttribute="centerY" id="xql-kz-i8e"/> </constraints> <userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="boolean" keyPath="ld_maskToBoundsXIB" value="YES"/> @@ -81,7 +86,9 @@ <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="img_playing" destination="vMh-x4-Y7a" id="jWd-mt-qFI"/> <outlet property="view_container" destination="qxz-6s-e5b" id="Ikx-kW-UkZ"/> + <outlet property="view_playHandle" destination="vtr-2e-B5C" id="I10-7z-6kl"/> </connections> <point key="canvasLocation" x="352.6829268292683" y="263.38983050847457"/> </collectionViewCell> @@ -89,6 +96,7 @@ <resources> <image name="icon_play" width="32" height="32"/> <image name="icon_play_1" width="27" height="27"/> + <image name="icon_playing" width="45" height="31"/> <systemColor name="systemBackgroundColor"> <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> </systemColor> diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFightVC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFightVC.swift index e84e90e..7e3e4a6 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFightVC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFightVC.swift @@ -164,21 +164,6 @@ setPages() pageVC.reloadData() -// if viewModel.listenType.value == .game1 || viewModel.listenType.value == .game2{ -// btn_forward.isHidden = true -// label_pageNum.isHidden = true -// -// if viewModel.listenType.value == .game1{ -// showGameLevel() -// } -// }else if viewModel.listenType.value == .story1 || viewModel.listenType.value == .story2{ -// let count = (data as! Listen1Model).storyList.count -// viewModel.maxPage.accept(count) -// label_pageNum.text = "已完成:\(viewModel.currentPage.value + 1)/\(viewModel.maxPage.value)" -// }else{ -// pageVC.reloadData() -// } - timer = Timer(fire: .distantPast, interval: 1.0, repeats: true, block: {[weak self] _ in self?.viewModel.times += 1 }) @@ -290,27 +275,6 @@ weakSelf.btn_exit.setTitle("完成", for: .normal) } } - - - //以下无效代码 -// -// -// //完成 -// if nextPage >= weakSelf.viewModel.maxPage.value{ -// switch weakSelf.viewModel.listenType.value { -// case .game1,.game2: -// if let dict = noti.object as? Dictionary<String,Any>{ -// weakSelf.gamesComplete(gameId: dict["gameId"] as! Int,integral: dict["gameIntegral"] as! Int) -// } -// case .lesson1,.lesson2,.lesson3,.lesson4,.lesson5: -// weakSelf.studyComplete() -// case .story1,.story2: -// if let dict = noti.object as? Dictionary<String,Any>{ -// weakSelf.storyComplete(storyId: dict["storyId"] as! Int, integral: dict["storyIntegral"] as! Int) -// } -// } -// return -// } weakSelf.listenFightLine = .next weakSelf.pageVC.scroll(toPage: nextPage, animation: true) @@ -476,7 +440,7 @@ @objc func beforeAction(){ listenFightLine = .before - let beforePage = max(0, viewModel.currentPage.value - 1) + var beforePage = max(0, viewModel.currentPage.value - 1) pageVC.scroll(toPage: beforePage, animation: true) viewModel.currentPage.accept(beforePage) diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_2_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_2_VC.swift index 97029d0..2a23445 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_2_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_2_VC.swift @@ -11,9 +11,7 @@ class HomeListenFight_lesson_2_VC: BaseVC { private var viewModel = FightAnswerViewModel() - private var listenNewModel:ListenNewModel! -// private var randomElement:Listen1SubModel? private var page:Int! var rootViewModel:HomeListenFightViewModel! private var tempViews = [StudyHandleView]() @@ -21,9 +19,6 @@ private var playedIndex = Set<Int>() //已经播放过的view private var voicePlayer = VoicePlayer.share() private var isAnsterModel = Set<Listen1SubModel>() - -// private var isAnsterComplete:Bool = false //是否已经回答完成[小题] -// private var isAnsterDone:Bool = false //是否已经回答完成[大题] private lazy var stackView:UIStackView = { let stackView = UIStackView() @@ -68,6 +63,7 @@ override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) VoicePlayer.share().delegate = nil + VoicePlayer.share().playerInterrupt() } func restore(){ @@ -160,9 +156,11 @@ var lessionType:Fight_lessonType = .none if handleView.vioceSoundUrl == weakSelf.listenNewModel.subjectList[weakSelf.page][row].correct{ lessionType = .success - weakSelf.voicePlayer.playerEnd() + weakSelf.voicePlayer.playSuccessVoice() +// weakSelf.voicePlayer.playerInterrupt() }else{ lessionType = .fail + weakSelf.voicePlayer.playFailVoice() } switch lessionType { @@ -313,12 +311,5 @@ } } -// if isAnsterComplete{ -//// getNextAnswer() -// if !isAnsterDone{ -// let v = rootViewModel.answerCount.value -// rootViewModel.answerCount.accept(v + 1) -// } -// } } } diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_3_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_3_VC.swift index 0148c28..7d0270c 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_3_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_3_VC.swift @@ -36,12 +36,13 @@ private var answterCount:Int = 0 //回答计数,用于确定角标 var rootViewModel:HomeListenFightViewModel! private var voicePlayer = VoicePlayer.share() + private var playIndex = Set<IndexPath>() //顺序播放 + private var isPlayingIndex:IndexPath? //正在播放中 required init(page:Int,listenNewModel:ListenNewModel){ super.init(nibName: nil, bundle: nil) self.page = page self.listenNewModel = listenNewModel -// self.listen1Model.subjectList.shuffle() } required init?(coder: NSCoder) { @@ -56,16 +57,14 @@ override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) voicePlayer.delegate = nil + VoicePlayer.share().playerInterrupt() } - - override func viewDidLoad() { super.viewDidLoad() navigationItem.titleView = UIView() -// viewModel.selectIndex.accept(IndexPath(row: 0, section: 0)) - - setAnswerStackView() + playIndex.insert(IndexPath(row: 0, section: 0)) +// setAnswerStackView() } func restore(){ @@ -99,23 +98,7 @@ } 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_3_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) } private func setAnswerStackView(){ @@ -127,7 +110,6 @@ tempImageArray.append(listenNewModel.subjectList[page][2].img) tempImageArray.append(listenNewModel.subjectList[page][4].img) tempImageArray.append(listenNewModel.subjectList[page][5].img) -// tempImageArray.shuffle() view.addSubview(stackView) stackView.snp.makeConstraints { make in @@ -135,6 +117,8 @@ make.centerY.equalToSuperview() make.height.equalTo(52) } + + var tempAnswerViews = [Lesson_3_AnswerView]() for i in 0...2{ let answerView = Lesson_3_AnswerView.jq_loadNibView() answerView.alpha = 0 @@ -153,20 +137,36 @@ UIView.animate(withDuration: 0.05 + Double(i)) { answerView.alpha = 1 } - - stackView.insertArrangedSubview(answerView, at: 0) + tempAnswerViews.append(answerView) } + tempAnswerViews.shuffle() + stackView.addArrangedSubviews(tempAnswerViews) } @objc private func chooseAnswerAction(btn:UIButton){ - if viewModel.selectIndex.value == nil{alertError(msg: "请先听题");return} - let index = btn.tag - 10 + if isPlayingIndex != nil { + alertError(msg: "请先听题");return + } + + if rootViewModel.correctNum == 0 && !playIndex.contains(IndexPath(row: 2, section: 0)){ + alertError(msg: "请先听题");return + } + + if rootViewModel.correctNum == 1 && !playIndex.contains(IndexPath(row: 1, section: 1)){ + alertError(msg: "请先听题");return + } + + if rootViewModel.correctNum == 2 && !playIndex.contains(IndexPath(row: 2, section: 1)){ + alertError(msg: "请先听题");return + } var subV:Lesson_3_AnswerView? - for (i,v) in stackView.arrangedSubviews.reversed().enumerated(){ - if index == i{subV = v as? Lesson_3_AnswerView;break} + for (_,v) in (stackView.arrangedSubviews as! [Lesson_3_AnswerView]).enumerated(){ + if v.btn_choose.tag == btn.tag{ + subV = v;break + } } var answerType:Fight_lessonType = .none @@ -181,8 +181,10 @@ if subV?.imageUrl == listenNewModel.subjectList[page][valueIndex].img{ answerType = .success + voicePlayer.playSuccessVoice() }else{ answerType = .fail + voicePlayer.playFailVoice() } switch answerType { @@ -200,10 +202,12 @@ var ansterIndePath:IndexPath? if viewModel.selectIndex.value?.section == 0{ ansterIndePath = IndexPath(row: 2, section: 0) + playIndex.insert(IndexPath(row: 0, section: 1)) //下一个准备播放 } if viewModel.selectIndex.value?.section == 1 && (viewModel.selectIndex.value?.row == 0 || viewModel.selectIndex.value?.row == 1){ ansterIndePath = IndexPath(row: 1, section: 1) + playIndex.insert(IndexPath(row: 2, section: 1)) //下一个准备播放 } if viewModel.selectIndex.value?.section == 1 && viewModel.selectIndex.value?.row == 2{ @@ -227,6 +231,7 @@ self.viewModel.selectIndex.accept(nil) let v = self.rootViewModel.answerCount.value + 1 self.rootViewModel.answerCount.accept(v) + self.collectionView.reloadData() } } } @@ -272,11 +277,19 @@ cell.backgroundColor = .clear cell.indexPath = indexPath cell.contentView.backgroundColor = .clear + cell.canClick(playIndex.contains(indexPath)) cell.palyVoiceAt {[weak self] index in - self?.viewModel.selectIndex.accept(index) + guard let weakSelf = self else { return } + weakSelf.isPlayingIndex = index + + weakSelf.voicePlayer.playerEnd() + weakSelf.voicePlayer.playerAt(url: weakSelf.listenNewModel.subjectList[weakSelf.page][indexPath.row].correct) + + weakSelf.viewModel.selectIndex.accept(index) + //点击答案,就显示 if (index.section == 0 && index.row == 2) || (index.section == 1 && index.row > 0){ - self?.viewModel.selectIndex.accept(index) - self?.setAnswerStackView() + weakSelf.viewModel.selectIndex.accept(index) + weakSelf.setAnswerStackView() } collectionView.reloadItems(at: [index]) @@ -289,7 +302,7 @@ }else{ cell.img_cover.image = nil } - cell.setModel(model,isplaying: viewModel.selectIndex.value == indexPath) + cell.setModel(model,isplaying: isPlayingIndex == indexPath) } if indexPath.section == 1{ @@ -299,7 +312,7 @@ }else{ cell.img_cover.image = nil } - cell.setModel(model,isplaying: viewModel.selectIndex.value == indexPath) + cell.setModel(model,isplaying: isPlayingIndex == indexPath) } return cell } @@ -321,14 +334,28 @@ extension HomeListenFight_lesson_3_VC:VoicePlayerDelegate{ func playComplete() { - collectionView.reloadData() + isPlayingIndex = nil + + var nextRow = (viewModel.selectIndex.value?.row ?? 0) + 1 + var section = (viewModel.selectIndex.value?.section ?? 0) + 0 + + if nextRow >= 3{ + nextRow = 0;section = 1 + } + if self.answterCount == 3{ self.rootViewModel.answerItems[self.page] = self.listenNewModel.subjectList[self.page] NotificationCenter.default.post(name: NextLession_Noti, object: nil) - VoicePlayer.share().playerEnd() return } + + if (viewModel.selectIndex.value?.section == 0 && viewModel.selectIndex.value?.row == 2) || (viewModel.selectIndex.value?.section == 1 && viewModel.selectIndex.value?.row == 1){ + collectionView.reloadData() + return + } + playIndex.insert(IndexPath(row: nextRow, section: section)) //下一个准备播放 + collectionView.reloadData() } func playing() { diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_4_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_4_VC.swift index 1f988ac..e98b8eb 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_4_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_4_VC.swift @@ -83,6 +83,7 @@ override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) voicePlayer.delegate = nil + VoicePlayer.share().playerInterrupt() } @@ -184,12 +185,14 @@ var answerType:Fight_lessonType = .none if tempSubV?.voiceUrl == answerModel?.correct{ answerType = .success + voicePlayer.playSuccessVoice() answerCount += 1 rootViewModel.correctNum += 1 let v = rootViewModel.answerCount.value + 1 rootViewModel.answerCount.accept(v) }else{ answerType = .fail + voicePlayer.playFailVoice() rootViewModel.errorNum += 1 } voicePlayer.playerEnd() diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_5_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_5_VC.swift index e4c1d55..edefa6e 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_5_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_5_VC.swift @@ -17,6 +17,7 @@ private var playVoiceRealAt:Int? //播放声音的View -被乱序后,真实Index var rootViewModel:HomeListenFightViewModel! private var voicePlayer = VoicePlayer.share() + private var isListen:Bool = false private lazy var collectionView:UICollectionView = { let flowLayout = UICollectionViewFlowLayout() @@ -75,6 +76,7 @@ override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) voicePlayer.delegate = nil + VoicePlayer.share().playerInterrupt() } override func setUI() { @@ -196,9 +198,10 @@ extension HomeListenFight_lesson_5_VC:UICollectionViewDelegate{ func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - if playVoiceAt == nil{ + if isListen == false{ alertError(msg: "请先听题");return } + isListen = false viewModel.selectIndex.accept(indexPath) @@ -206,11 +209,12 @@ let selectAnswer = listenNewModel.subjectList[page][indexPath.row] var answerType:Fight_lessonType = .none - if answer.id == selectAnswer.id{ answerType = .success + voicePlayer.playSuccessVoice() }else{ answerType = .fail + voicePlayer.playFailVoice() } let tempSubV = stackView.arrangedSubviews[self.playVoiceRealAt!] as! VoiceHandleView @@ -299,6 +303,7 @@ extension HomeListenFight_lesson_5_VC:VoicePlayerDelegate{ func playComplete() { + isListen = true for subV in stackView.arrangedSubviews as! [VoiceHandleView]{ subV.resetView() } diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_1_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_1_VC.swift index 296eef7..79b74c8 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_1_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_1_VC.swift @@ -89,7 +89,7 @@ super.viewDidDisappear(animated) timer?.invalidate() voicePlayer.delegate = nil - voicePlayer.playerEnd() + voicePlayer.playerInterrupt() } override func viewDidLoad() { @@ -212,8 +212,10 @@ if currentAnswer?.id == listen1Model?.subjectList[row].id{ answerType = .success + voicePlayer.playSuccessVoice() }else{ answerType = .fail + voicePlayer.playFailVoice() } switch answerType { case .success: diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_2_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_2_VC.swift index c2d3e52..fcfbd10 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_2_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_2_VC.swift @@ -80,6 +80,7 @@ super.viewDidDisappear(animated) voicePlayer.delegate = nil timer?.invalidate() + voicePlayer.playerInterrupt() } override func viewDidLoad() { @@ -159,10 +160,12 @@ switch answerType { case .success: + voicePlayer.playSuccessVoice() viewModel.answerType.accept(.success) collectionView.reloadData() case .fail: + voicePlayer.playFailVoice() viewModel.answerType.accept(.fail) collectionView.reloadData() DispatchQueue.main.asyncAfter(wallDeadline: .now()+2.5) { diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenMenuVC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenMenuVC.swift index 93f03ff..43ab46c 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenMenuVC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenMenuVC.swift @@ -22,6 +22,13 @@ override func viewDidLoad() { super.viewDidLoad() getData() + Services.goodRecommend().subscribe(onNext: { data in + AwardListView.show(items: data.data ?? []) { _ in + + }closeClouse: { () in + + } + }).disposed(by: disposeBag) } diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_1_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_1_VC.swift index a391dfa..d1e0594 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_1_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_1_VC.swift @@ -53,6 +53,7 @@ override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) voicePlayer.delegate = nil + voicePlayer.playerInterrupt() } required init?(coder: NSCoder) { @@ -106,8 +107,10 @@ var lessionType:Fight_lessonType = .none if weakSelf.listen1Model.storyList[weakSelf.page].correct == handleView.vioceSoundUrl{ lessionType = .success + weakSelf.voicePlayer.playSuccessVoice() }else{ lessionType = .fail + weakSelf.voicePlayer.playFailVoice() } switch lessionType { diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_2_VC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_2_VC.swift index 7bd884d..da55616 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_2_VC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_2_VC.swift @@ -50,6 +50,11 @@ } + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + voicePlayer.playerInterrupt() + } + override func setUI() { super.setUI() @@ -84,26 +89,6 @@ DispatchQueue.main.asyncAfter(wallDeadline: .now()+2){ handleView.playUrl = self.listen1Model.storyList[self.page].correct } -// handleView.chooseClouse {[weak self] btn in -//// guard let weakSelf = self else { return } -// var lessionType:Fight_lessonType = .none -// lessionType = .success -// switch lessionType { -// case .success: -// handleView.btn_choose.isSelected = true -// handleView.btn_state.setImage(UIImage(named: "icon_success_small"), for: .normal) -// UIView.animate(withDuration: 0.5) { -// handleView.btn_state.alpha = 1 -// } -// case .fail: -// handleView.btn_state.setImage(UIImage(named: "icon_waring_small"), for: .normal) -// UIView.animate(withDuration: 0.5) { -// handleView.btn_state.alpha = 1 -// } -// default: -// handleView.btn_state.setImage(nil, for: .normal) -// } -// } handleView.snp.makeConstraints { make in make.height.equalTo(52) diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenSubVC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenSubVC.swift index cd92118..bbc6477 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenSubVC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenSubVC.swift @@ -56,7 +56,7 @@ } private func getData(){ - Services.studySchedule(week: week, day: page + 1).subscribe(onNext: {data in + Services.studySchedule(week: week).subscribe(onNext: {data in self.studyScheduleModel = data.data self.tableView.reloadData() }).disposed(by: disposeBag) diff --git a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenVC.swift b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenVC.swift index af119d2..cfe7a1b 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenVC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenVC.swift @@ -50,7 +50,7 @@ override func viewDidLoad() { super.viewDidLoad() - Services.studySchedule(week: week, day: 1).subscribe(onNext: {data in + Services.studySchedule(week: week).subscribe(onNext: {data in self.limitDay = data.data?.day ?? 0 #if DEBUG diff --git a/DolphinEnglishLearnStudent/Moudle/Home/VC/HomeStudyCompleteVC.swift b/DolphinEnglishLearnStudent/Moudle/Home/VC/HomeStudyCompleteVC.swift index d28f2be..9f7b9a3 100644 --- a/DolphinEnglishLearnStudent/Moudle/Home/VC/HomeStudyCompleteVC.swift +++ b/DolphinEnglishLearnStudent/Moudle/Home/VC/HomeStudyCompleteVC.swift @@ -53,6 +53,8 @@ stackView.isHidden = listenType == .story2 label_ratioNum.isHidden = listenType == .story2 + + NotificationCenter.default.post(name: Refresh_ListenSchedule_Noti, object: nil) } override func setUI() { diff --git a/DolphinEnglishLearnStudent/Moudle/Me/VC/AddressManageHandleVC.xib b/DolphinEnglishLearnStudent/Moudle/Me/VC/AddressManageHandleVC.xib index b97b7a9..82c7c28 100644 --- a/DolphinEnglishLearnStudent/Moudle/Me/VC/AddressManageHandleVC.xib +++ b/DolphinEnglishLearnStudent/Moudle/Me/VC/AddressManageHandleVC.xib @@ -165,7 +165,7 @@ <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="9Rg-uR-zdR" customClass="QMUITextField"> <rect key="frame" x="90.5" y="0.0" width="778.5" height="54"/> <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/> - <textInputTraits key="textInputTraits" keyboardType="phonePad"/> + <textInputTraits key="textInputTraits"/> <userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="number" keyPath="maximumTextLength"> <integer key="value" value="11"/> diff --git a/DolphinEnglishLearnStudent/SceneDelegate.swift b/DolphinEnglishLearnStudent/SceneDelegate.swift index c32eecd..45c8605 100644 --- a/DolphinEnglishLearnStudent/SceneDelegate.swift +++ b/DolphinEnglishLearnStudent/SceneDelegate.swift @@ -11,6 +11,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? + private var disposeBag = JQ_disposeBag func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } @@ -81,6 +82,8 @@ func needLogin(){ sceneDelegate?.window?.rootViewController = BaseNav(rootViewController: LoginVC()) sceneDelegate?.window?.makeKeyAndVisible() + LoginTokenModel.clearToken() + } } diff --git a/DolphinEnglishLearnStudent/Services/NetworkRequest.swift b/DolphinEnglishLearnStudent/Services/NetworkRequest.swift index 03a8cf5..2a4a26f 100644 --- a/DolphinEnglishLearnStudent/Services/NetworkRequest.swift +++ b/DolphinEnglishLearnStudent/Services/NetworkRequest.swift @@ -231,15 +231,11 @@ switch next.code{ case 200:ob.onNext(next) case 504: //登录设备最大限制 - let attribute = AttributedStringbuilder.build().add(string:next.msg, withFont: .systemFont(ofSize: 14, weight: .medium), withColor: .black.withAlphaComponent(0.6)).mutableAttributedString -// CommonAlertView.show(title: "提示", attribute: attribute, cancelStr: "关闭", completeStr: "关闭", isSingle: true, customBtnWidth: JQ_ScreenW - 170) { _ in -// -// } + break case 503: //登录被冻结 - let attribute = AttributedStringbuilder.build().add(string:next.msg, withFont: .systemFont(ofSize: 14, weight: .medium), withColor: .black.withAlphaComponent(0.6)).mutableAttributedString -// CommonAlertView.show(title: "提示", attribute: attribute, cancelStr: "关闭", completeStr: "关闭", isSingle: true, customBtnWidth: JQ_ScreenW - 170) { _ in -// -// } + DispatchQueue.main.async { + alert(msg: next.msg) + } // case 501: // CommonAlertView.show(title: "提示", content: next.msg,isSingle: true) { _ in // @@ -252,7 +248,9 @@ sceneDelegate?.needLogin() default: if !ignoreAlert{ - alertError(msg: "\(next.msg)") + DispatchQueue.main.async { + alertError(msg: "\(next.msg)") + } } ob.onError(NetRequestError.Other(next.code,next.msg)) } diff --git a/DolphinEnglishLearnStudent/Services/Services.swift b/DolphinEnglishLearnStudent/Services/Services.swift index 918b535..b804c5e 100644 --- a/DolphinEnglishLearnStudent/Services/Services.swift +++ b/DolphinEnglishLearnStudent/Services/Services.swift @@ -13,8 +13,9 @@ #if DEBUG let All_Url = "http://192.168.110.237:9000" +//let All_Url = "http://1.95.15.237:9000" #else -let All_Url = "http://192.168.110.237:9000" +let All_Url = "http://1.95.15.237:9000" #endif class Services: NSObject { @@ -145,13 +146,24 @@ return NetworkRequest.request(params: params, method: .get, progress: true) } - class func studySchedule(week:Int,day:Int)->Observable<BaseResponse<StudyScheduleModel>>{ + class func studySchedule(week:Int)->Observable<BaseResponse<StudyScheduleModel>>{ let params = ParamsAppender.build(url: All_Url) params.interface(url: "/study/base/study/studySchedule") params.append(key: "week", value: week) - params.append(key: "day", value: day) return NetworkRequest.request(params: params, method: .get, progress: true) } + + class func parentPage()->Observable<BaseResponse<String>>{ + let params = ParamsAppender.build(url: All_Url) + params.interface(url: "/study/base/user/parentPage") + return NetworkRequest.request(params: params, method: .post, progress: false) + } + + class func promptVoice()->Observable<BaseResponse<PromptVoiceModel>>{ + let params = ParamsAppender.build(url: All_Url) + params.interface(url: "/study/base/study/promptVoice") + return NetworkRequest.request(params: params, method: .get, progress: false) + } } // MARK: -- 登录部分 -- Gitblit v1.7.1