//
|
// HomeListenFightVC.swift
|
// DolphinEnglishLearnStudent
|
//
|
// Created by 无故事王国 on 2024/5/23.
|
//
|
|
import UIKit
|
import FFPage
|
import RxRelay
|
|
let NextLession_Noti = Notification.Name.init("NextLession_Noti")
|
//let Reload_Noti = Notification.Name.init("Reload_Noti")
|
|
enum ListenType:Int{
|
case lesson1 = 1 //自主学习-听音选图
|
case lesson2 = 2 //自主学习-看图选音
|
case lesson3 = 3 //自主学习-归纳排除
|
case lesson4 = 4 //自主学习-有问有答
|
case lesson5 = 5 //自主学习-音图相配
|
case game1 = 6 //游戏类型-超级听力
|
case game2 = 7 //游戏类型-超级记忆
|
case story1 = 8 //故事类型-自主故事1-看图配音
|
case story2 = 9 //故事类型-自主故事2-框架记忆
|
|
var rawTitle:String{
|
switch self {
|
case .lesson1:return "自主学习1-听音选图"
|
case .lesson2:return "自主学习2-看图选音"
|
case .lesson3:return "自主学习3-归纳排除"
|
case .lesson4:return "自主学习4-有问有答"
|
case .lesson5:return "自主学习5-音图相配"
|
case .game1:return "游戏类型1-超级听力"
|
case .game2:return "游戏类型2-超级记忆"
|
case .story1:return "自主故事1-看图配音"
|
case .story2:return "自主故事2-框架记忆"
|
}
|
}
|
}
|
|
enum ListenFightLine{
|
case before
|
case next
|
case none
|
}
|
|
|
//中途退出所需要
|
class ExitLearnModel{
|
var topicsIds = Set<Int>()
|
}
|
|
class HomeListenFightViewModel{
|
|
/// 当前页数
|
var currentPage = BehaviorRelay<Int>(value: 0)
|
var subPage = BehaviorRelay<Int>(value: 1) //小题目角标
|
var maxPage = BehaviorRelay<Int>(value: 5)
|
var listenType = BehaviorRelay<ListenType>(value:.lesson1)
|
var times:Int = 0
|
var quarter = BehaviorRelay<Int?>(value: 0)
|
var week = BehaviorRelay<Int?>(value: 0)
|
var day = BehaviorRelay<Int?>(value: 0)
|
|
//游戏专属,游戏等级
|
var gameLevel = BehaviorRelay<Int>(value:0)
|
|
//回答错误数量
|
var correctNum:Int = 0{
|
didSet{
|
print("回答正确:\(correctNum)")
|
}
|
}
|
|
var errorNum:Int = 0{
|
didSet{
|
print("回答错误:\(correctNum)")
|
}
|
}
|
|
//所有回答的
|
var answerItems = Dictionary<Int,Any>() //{page:0,data:String,currectAt:0}
|
var answerCount = BehaviorRelay<Int>(value: 1)
|
|
var answerItems_1 = Dictionary<String,Set<Int>>()
|
|
//回答正确的题
|
func insertCorrectAnswer(teamId:String?,answerId:Int){
|
guard teamId != nil else {return}
|
if answerItems_1[teamId!] == nil{
|
answerItems_1[teamId!] = Set<Int>()
|
}
|
answerItems_1[teamId!]!.insert(answerId)
|
}
|
}
|
|
class HomeListenFightVC: BaseVC {
|
private var viewModel = HomeListenFightViewModel()
|
var studyScheduleModel:StudyScheduleModel? //学习进度(上级传递)
|
var listenFightLine:ListenFightLine = .none
|
var data:Any?
|
|
private lazy var label_pageNum:UILabel = {
|
let label = UILabel()
|
label.font = .systemFont(ofSize: 14, weight: .medium)
|
label.textColor = .black.withAlphaComponent(0.81)
|
label.textAlignment = .center
|
label.text = "已完成:0/0"
|
return label
|
}()
|
|
private lazy var btn_forward:UIButton = {
|
let btn = UIButton(type: .custom)
|
btn.setTitle("上一题", for: .normal)
|
btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium)
|
btn.setTitleColor(Config.ThemeColor, for: .normal)
|
btn.jq_borderColor = Config.ThemeColor
|
btn.backgroundColor = .white
|
btn.jq_borderWidth = 1
|
btn.jq_cornerRadius = 4
|
return btn
|
}()
|
|
private lazy var btn_next:UIButton = {
|
let btn = UIButton(type: .custom)
|
btn.setTitle("下一题", for: .normal)
|
btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium)
|
btn.setTitleColor(Config.ThemeColor, for: .normal)
|
btn.jq_borderColor = Config.ThemeColor
|
btn.backgroundColor = .white
|
btn.jq_borderWidth = 1
|
btn.jq_cornerRadius = 4
|
return btn
|
}()
|
|
private lazy var btn_exit:UIButton = {
|
let btn = UIButton(type: .custom)
|
btn.setTitle("退出", for: .normal)
|
btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium)
|
btn.setTitleColor(.white, for: .normal)
|
btn.backgroundColor = Config.ThemeColor
|
btn.jq_cornerRadius = 4
|
return btn
|
}()
|
|
private lazy var pageVC:FFPageViewController = {
|
let vc = FFPageViewController()
|
vc.scrollview.isScrollEnabled = false
|
return vc
|
}()
|
|
private var timer:Timer!
|
|
|
init(listenType:ListenType,quarter:Int? = nil,week:Int? = nil,day:Int? = nil) {
|
super.init(nibName: nil, bundle: nil)
|
self.viewModel.listenType.accept(listenType)
|
self.viewModel.week.accept(week)
|
self.viewModel.day.accept(day)
|
self.viewModel.quarter.accept(quarter)
|
|
if listenType == .game1 || listenType == .game2{
|
self.viewModel.maxPage.accept(1)
|
}
|
}
|
|
required init?(coder: NSCoder) {
|
fatalError("init(coder:) has not been implemented")
|
}
|
|
override func viewDidLoad() {
|
super.viewDidLoad()
|
|
yy_popBlock = {[weak self] in
|
self?.quitAction()
|
}
|
|
btn_exit.addTarget(self, action: #selector(quitAction), for: .touchUpInside)
|
btn_forward.addTarget(self, action: #selector(beforeAction), for: .touchUpInside)
|
btn_next.addTarget(self, action: #selector(nextAction), for: .touchUpInside)
|
|
setPages()
|
pageVC.reloadData()
|
|
timer = Timer(fire: .distantPast, interval: 1.0, repeats: true, block: {[weak self] _ in
|
self?.viewModel.times += 1
|
})
|
|
timer.fire()
|
RunLoop.current.add(timer, forMode: .common)
|
}
|
|
override func setUI() {
|
super.setUI()
|
craeteFootFuncView()
|
|
pageVC.delegate = self
|
view.addSubview(pageVC.view)
|
pageVC.view.snp.makeConstraints { make in
|
make.left.right.equalToSuperview()
|
make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top)
|
if self.viewModel.listenType.value == .lesson3 || self.viewModel.listenType.value == .lesson4{
|
make.bottom.equalTo(self.label_pageNum.snp.top).offset(-18)
|
}else{
|
make.bottom.equalTo(self.label_pageNum.snp.top).offset(-32)
|
}
|
}
|
}
|
|
|
private func showGameLevel(canLevel:Int){
|
ChooseLevelView.show(canLevel: canLevel) {[weak self] level in
|
guard let weakSelf = self else { return }
|
weakSelf.viewModel.gameLevel.accept(level)
|
Services.gameHearing(difficulty: level, quarter: weakSelf.viewModel.quarter.value!, week: weakSelf.viewModel.week.value!).subscribe(onNext: {result in
|
GameBeginTipView.show {
|
if let data = result.data{
|
weakSelf.data = data
|
weakSelf.pageVC.reloadData()
|
}
|
}
|
},onError: {[weak self] _ in
|
self?.navigationController?.popViewController(animated: true)
|
}).disposed(by: weakSelf.disposeBag)
|
} cancelClouse: { [weak self] in
|
self?.navigationController?.popViewController(animated: true)
|
}
|
}
|
|
private func craeteFootFuncView(){
|
|
view.addSubview(label_pageNum)
|
|
view.addSubview(btn_forward)
|
btn_forward.snp.makeConstraints { make in
|
make.height.equalTo(40)
|
make.width.equalTo(124)
|
}
|
|
view.addSubview(btn_exit)
|
btn_exit.snp.makeConstraints { make in
|
make.height.equalTo(40)
|
make.width.equalTo(124)
|
}
|
|
let stackView = UIStackView(arrangedSubviews: [btn_forward,label_pageNum,btn_exit])
|
if viewModel.listenType.value == .story2{
|
btn_next.snp.makeConstraints { make in
|
make.height.equalTo(40)
|
make.width.equalTo(124)
|
}
|
stackView.insertArrangedSubview(btn_next, at: 2)
|
}
|
|
stackView.spacing = 22
|
view.addSubview(stackView)
|
stackView.snp.makeConstraints { make in
|
make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom).offset(-22)
|
make.centerX.equalToSuperview()
|
make.height.equalTo(40)
|
}
|
}
|
|
override func setRx() {
|
NotificationCenter.default.rx.notification(NextLession_Noti).take(until: self.rx.deallocated).subscribe(onNext: {[weak self] noti in
|
guard let weakSelf = self else { return }
|
let nextPage = weakSelf.viewModel.currentPage.value + 1
|
var asComplete:Bool = false
|
switch weakSelf.viewModel.listenType.value {
|
case .lesson1,.lesson2,.lesson3,.lesson4,.lesson5:asComplete = nextPage >= (weakSelf.data as! ListenNewModel).subjectList.count
|
case .game1,.game2:asComplete = true
|
case .story1,.story2: asComplete = nextPage >= (weakSelf.data as! Listen1Model).storyList.count
|
}
|
|
if asComplete{
|
switch weakSelf.viewModel.listenType.value {
|
case .lesson1,.lesson2,.lesson3,.lesson4,.lesson5:
|
weakSelf.studyComplete()
|
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 .story1,.story2:
|
if let dict = noti.object as? Dictionary<String,Any>{
|
weakSelf.storyComplete(storyId: dict["storyId"] as! Int, integral: dict["storyIntegral"] as! Int)
|
}
|
}
|
return
|
}
|
|
if weakSelf.viewModel.listenType.value == .story2{
|
weakSelf.btn_next.isHidden = (nextPage + 1) == weakSelf.viewModel.maxPage.value
|
if weakSelf.btn_next.isHidden{
|
weakSelf.btn_exit.setTitle("完成", for: .normal)
|
}
|
}
|
|
weakSelf.listenFightLine = .next
|
weakSelf.pageVC.scroll(toPage: nextPage, animation: true)
|
weakSelf.viewModel.currentPage.accept(nextPage)
|
}).disposed(by: disposeBag)
|
|
viewModel.currentPage.subscribe(onNext: {[weak self]currentPage in
|
guard let weakSelf = self else { return }
|
self?.btn_forward.isHidden = currentPage <= 0
|
self?.setPages()
|
}).disposed(by: disposeBag)
|
|
viewModel.answerCount.subscribe(onNext: {[weak self] count in
|
self?.setPages()
|
}).disposed(by: disposeBag)
|
}
|
|
private func setPages(){
|
switch viewModel.listenType.value{
|
case .lesson1,.lesson2,.lesson5:
|
label_pageNum.text = "已完成:\(viewModel.answerCount.value)/\((data as! ListenNewModel).subjectList.flatMap({$0}).count)"
|
case .lesson3:
|
label_pageNum.text = "已完成:\(viewModel.currentPage.value + 1)/\((data as! ListenNewModel).subjectList.count)"
|
case .lesson4:
|
//两题为一组:需要/2
|
label_pageNum.text = "已完成:\(viewModel.answerCount.value)/\((data as! ListenNewModel).subjectList.flatMap({$0}).count / 2)"
|
case .game1,.game2:
|
btn_forward.isHidden = true
|
label_pageNum.isHidden = true
|
|
if viewModel.listenType.value == .game1{
|
showGameLevel(canLevel: studyScheduleModel?.gameDifficulty ?? 0)
|
}
|
case .story1,.story2:
|
let count = (data as! Listen1Model).storyList.count
|
viewModel.maxPage.accept(count)
|
label_pageNum.text = "已完成:\(viewModel.currentPage.value + 1)/\(count)"
|
default:break
|
}
|
}
|
|
|
/// 学习类完成
|
/// - Parameter ignorePush: 是否忽略跳转(未完成答题 :true)
|
private func studyComplete(){
|
var toalIntegral:Int = 0
|
var ids:String = ""
|
|
switch viewModel.listenType.value {
|
case .lesson1,.lesson2,.lesson3,.lesson4,.lesson5:
|
let data = (data as! ListenNewModel).data
|
toalIntegral = data?.integral ?? 0
|
default:break
|
}
|
|
//正确率
|
let accracy = Int(Double(viewModel.correctNum) / Double(viewModel.correctNum + viewModel.errorNum) * 100)
|
|
Services.completeLearing(type: viewModel.listenType.value.rawValue, studyTime: viewModel.times, studyIds: ids, quarter: viewModel.quarter.value!, week: viewModel.week.value!, day: viewModel.day.value!, accracy: accracy).subscribe(onNext: {data in
|
NotificationCenter.default.post(name: Refresh_ListenSchedule_Noti, object: nil)
|
}).disposed(by: disposeBag)
|
|
timer.invalidate()
|
|
let vc = HomeStudyCompleteVC(correctNum: viewModel.correctNum, errorNum: viewModel.errorNum, totalCoin: toalIntegral, listenType: viewModel.listenType.value)
|
vc.title = viewModel.listenType.value.rawTitle
|
push(vc: vc)
|
}
|
|
//游戏类完成
|
private func gamesComplete(gameId:Int,integral:Int){
|
|
var name = ""
|
if viewModel.listenType.value == .game1{
|
name = "超级听力"
|
}else{
|
name = "超级记忆"
|
}
|
|
let accuracy = Int(Double(viewModel.correctNum) / Double(viewModel.correctNum + viewModel.errorNum) * 100)
|
|
Services.completeGames(gameId: gameId, gameName: name, difficulty: viewModel.gameLevel.value, accuracy: accuracy, useTime: viewModel.times).subscribe(onNext: {data in
|
NotificationCenter.default.post(name: Refresh_ListenSchedule_Noti, object: nil)
|
}).disposed(by: disposeBag)
|
|
timer.invalidate()
|
|
let vc = HomeStudyCompleteVC(correctNum: viewModel.correctNum, errorNum: viewModel.errorNum, totalCoin: integral, listenType: viewModel.listenType.value)
|
vc.title = viewModel.listenType.value.rawTitle
|
push(vc: vc)
|
}
|
|
private func storyComplete(storyId:Int,integral:Int){
|
timer.invalidate()
|
|
Services.completeStory(storyId: storyId, integral: integral).subscribe(onNext: {data in
|
NotificationCenter.default.post(name: Refresh_ListenSchedule_Noti, object: nil)
|
}).disposed(by: disposeBag)
|
|
let vc = HomeStudyCompleteVC(correctNum: viewModel.correctNum, errorNum: viewModel.errorNum, totalCoin: integral, listenType: viewModel.listenType.value)
|
vc.title = viewModel.listenType.value.rawTitle
|
push(vc: vc)
|
}
|
|
deinit{
|
timer.invalidate()
|
}
|
|
@objc func quitAction(){
|
if btn_exit.titleLabel?.text == "完成"{
|
if viewModel.listenType.value == .story2{
|
let v = data as! Listen1Model
|
storyComplete(storyId: v.data!.id, integral: v.data!.lookIntegral)
|
}
|
}else{
|
CommonAlertView.show(content: "未完成全部答题,确认退出吗?") {[weak self] () in
|
guard let weakSelf = self else { return }
|
|
let topicIds = weakSelf.viewModel.answerItems_1.keys.sorted()
|
let temIds = weakSelf.viewModel.answerItems_1.values.flatMap({$0}).map({"\($0)"})
|
|
switch weakSelf.viewModel.listenType.value{
|
case .lesson1,.lesson2,.lesson3,.lesson4,.lesson5:
|
if temIds.count > 0 && topicIds.count > 0{
|
let totalNum = weakSelf.viewModel.correctNum + weakSelf.viewModel.errorNum
|
Services.exitLearning(type:weakSelf.viewModel.listenType.value.rawValue,week: weakSelf.viewModel.week.value!, day: weakSelf.viewModel.day.value!, teamIds: temIds, topicIds: topicIds,answerNumber: totalNum,correctNumber:weakSelf.viewModel.correctNum,studyTime:weakSelf.viewModel.times).subscribe(onNext: { data in
|
|
}).disposed(by: weakSelf.disposeBag)
|
}
|
default:break
|
}
|
weakSelf.navigationController?.popViewController(animated: true)
|
}
|
}
|
}
|
|
@objc func nextAction(){
|
listenFightLine = .next
|
if viewModel.listenType.value == .story2{
|
let v = data as! Listen1Model
|
var dict = Dictionary<String,Any>()
|
dict["storyId"] = v.data?.id ?? 0
|
dict["storyIntegral"] = v.data?.lookIntegral ?? 0
|
NotificationCenter.default.post(name: NextLession_Noti, object: data)
|
}
|
}
|
|
@objc func beforeAction(){
|
listenFightLine = .before
|
let beforePage = max(0, viewModel.currentPage.value - 1)
|
switch viewModel.listenType.value {
|
case .lesson1,.lesson2:
|
let temp = (beforePage * 4) + 1
|
viewModel.answerCount.accept(max(1,temp))
|
default:break
|
}
|
|
|
pageVC.scroll(toPage: beforePage, animation: true)
|
viewModel.currentPage.accept(beforePage)
|
|
if viewModel.listenType.value == .story2{
|
btn_next.isHidden = false
|
}
|
|
btn_exit.setTitle("退出", for: .normal)
|
}
|
}
|
|
extension HomeListenFightVC:FFPageViewControllerDelegate{
|
func totalPagesOfpageViewController(_ pageViewConteoller: FFPageViewController) -> UInt {
|
|
switch viewModel.listenType.value {
|
case .lesson1,.lesson2,.lesson3,.lesson4,.lesson5:return UInt((data as! ListenNewModel).subjectList.count)
|
case .story1,.story2:
|
return UInt((data as! Listen1Model).storyList.count)
|
default:break
|
}
|
|
|
//超级听力,只有一页
|
if viewModel.listenType.value == .game1 || viewModel.listenType.value == .game2{
|
return 1
|
}
|
return UInt(viewModel.maxPage.value)
|
}
|
|
func pageViewController(_ pageViewController: FFPageViewController, currentPageChanged currentPage: Int) {
|
|
if listenFightLine == .before{
|
if let vc = pageViewController.currentController as? HomeListenFight_lesson_1_VC{
|
vc.restore()
|
}
|
if let vc = pageViewController.currentController as? HomeListenFight_lesson_2_VC{
|
vc.restore()
|
}
|
if let vc = pageViewController.currentController as? HomeListenFight_lesson_3_VC{
|
vc.restore()
|
}
|
if let vc = pageViewController.currentController as? HomeListenFight_lesson_4_VC{
|
vc.restore()
|
}
|
if let vc = pageViewController.currentController as? HomeListenFight_lesson_5_VC{
|
vc.restore()
|
}
|
|
if let vc = pageViewController.currentController as? HomeListenStory_1_VC{
|
vc.restore()
|
}
|
if let vc = pageViewController.currentController as? HomeListenStory_2_VC{
|
vc.restore()
|
}
|
}
|
}
|
|
func pageViewController(_ pageViewConteoller: FFPageViewController, controllerForPage page: Int) -> UIViewController {
|
if viewModel.listenType.value == .lesson1{
|
let vc = HomeListenFight_lesson_1_VC(page: page,listenNewModel:data as! ListenNewModel)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .lesson2{
|
let vc = HomeListenFight_lesson_2_VC(page: page,listenNewModel:data as! ListenNewModel)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .lesson3{
|
let vc = HomeListenFight_lesson_3_VC(page: page, listenNewModel: data as! ListenNewModel)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .lesson4{
|
let vc = HomeListenFight_lesson_4_VC(page: page, listenNewModel: data as! ListenNewModel)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .lesson5{
|
let vc = HomeListenFight_lesson_5_VC(page: page, listenNewModel: data as! ListenNewModel)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .game1{
|
if data == nil{return UIViewController()}
|
let vc = HomeListenGame_1_VC(listen1Model: data as! Listen1Model)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .game2{
|
let vc = HomeListenGame_2_VC(listen1Model: data as! Listen1Model)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .story1{
|
let vc = HomeListenStory_1_VC(page: page, listen1Model: data as! Listen1Model)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
if viewModel.listenType.value == .story2{
|
let vc = HomeListenStory_2_VC(page: page, listen1Model: data as! Listen1Model)
|
vc.rootViewModel = viewModel
|
return vc
|
}
|
|
let vc = UIViewController()
|
return vc
|
}
|
}
|