fix
无故事王国
2024-06-18 c1862d736587c9a5c10a368dabaeb72be2df4bcb
fix
29个文件已修改
1个文件已添加
790 ■■■■■ 已修改文件
DolphinEnglishLearnStudent.xcodeproj/project.pbxproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Base/BaseNav.swift 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Base/BaseVC.swift 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Config/Config.swift 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Config/LaunchImageHelper.swift 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Config/VoicePlayer.swift 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Info.plist 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Models/CommonModel.swift 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/HomeListenFight_lesson_1_VC.swift 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/HomeVC.swift 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/HomeVC.xib 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.xib 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFightVC.swift 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_2_VC.swift 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_3_VC.swift 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_4_VC.swift 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenFight_lesson_5_VC.swift 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_1_VC.swift 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenGame_2_VC.swift 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenMenuVC.swift 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_1_VC.swift 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenStory_2_VC.swift 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenSubVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/Listen/VC/HomeListenVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Home/VC/HomeStudyCompleteVC.swift 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Moudle/Me/VC/AddressManageHandleVC.xib 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/SceneDelegate.swift 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Services/NetworkRequest.swift 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DolphinEnglishLearnStudent/Services/Services.swift 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 */,
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
                }
}
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(){
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
                                                                });
                                                }
                                                time -= 1
                                });
DolphinEnglishLearnStudent/Config/LaunchImageHelper.swift
New file
@@ -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
    }
}
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,16 +53,14 @@
                                guard let u = url else {return}
                                if player?.isPlaying ?? false{
                                                player?.stop()
                                                self.playComplete?() //先通知完成播放
                                }
                                //文件存在:直接播放缓存路径的语音
                                let fileURL = voiceCacheDirectory.appendingPathComponent(URL(fileURLWithPath: u).lastPathComponent).droppedScheme()
                                                let fileURL = self.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()
                                                                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
@@ -89,9 +88,90 @@
                                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: successVoice)!) { 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("SuccessPromote.\(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()
                                }
                                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()
                                }
                                group.notify(queue: .main){
                                                UserDefaults.standard.setValue(updateTime, forKey: "promptVoiceDate")
                                                UserDefaults.standard.synchronize()
                                }
                }
}
extension VoicePlayer:AVAudioPlayerDelegate{
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>
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 = ""
}
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().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
                                                }
                                }
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)
    }
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>
DolphinEnglishLearnStudent/Moudle/Home/Listen/CCell/ListenFight_lesson_3_CCell.swift
@@ -14,6 +14,8 @@
                @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)?
@@ -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)
                }
}
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>
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)
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)
//                                                }
//                                }
                }
}
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() {
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()
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()
                                }
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:
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) {
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)
                }
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 {
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)
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)
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
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() {
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"/>
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()
                }
}
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,8 +248,10 @@
                                                                                                                                sceneDelegate?.needLogin()
                                                                                                                default:
                                                                                                                                if !ignoreAlert{
                                                                                                                                                DispatchQueue.main.async {
                                                                                                                                                alertError(msg: "\(next.msg)")
                                                                                                                                }
                                                                                                                                }
                                                                                                                                ob.onError(NetRequestError.Other(next.code,next.msg))
                                                                                                }
                                                                                }
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: -- 登录部分