Sfoglia il codice sorgente

模拟考试--录播模拟

Steven 4 anni fa
parent
commit
af93428d18
60 ha cambiato i file con 1935 aggiunte e 208 eliminazioni
  1. 162 102
      MusicGradeExam/MusicGradeExam.xcodeproj/project.pbxproj
  2. 22 0
      MusicGradeExam/MusicGradeExam/Assets.xcassets/Home/home_SExam.imageset/Contents.json
  3. BIN
      MusicGradeExam/MusicGradeExam/Assets.xcassets/Home/home_SExam.imageset/home_SExam@2x.png
  4. BIN
      MusicGradeExam/MusicGradeExam/Assets.xcassets/Home/home_SExam.imageset/home_SExam@3x.png
  5. 23 2
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZAssetCell.m
  6. 5 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZAssetModel.h
  7. 6 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZAssetModel.m
  8. 31 24
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImageManager.m
  9. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ar.lproj/Localizable.strings
  10. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/bg.lproj/Localizable.strings
  11. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/cs-CZ.lproj/Localizable.strings
  12. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/de.lproj/Localizable.strings
  13. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/el.lproj/Localizable.strings
  14. BIN
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings
  15. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/es.lproj/Localizable.strings
  16. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/fr.lproj/Localizable.strings
  17. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/he.lproj/Localizable.strings
  18. BIN
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/iCloudError@2x.png
  19. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/it.lproj/Localizable.strings
  20. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ja.lproj/Localizable.strings
  21. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ko-KP.lproj/Localizable.strings
  22. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ko.lproj/Localizable.strings
  23. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/nl.lproj/Localizable.strings
  24. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/pl.lproj/Localizable.strings
  25. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/pt.lproj/Localizable.strings
  26. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ro.lproj/Localizable.strings
  27. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ru.lproj/Localizable.strings
  28. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/sk.lproj/Localizable.strings
  29. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/sv.lproj/Localizable.strings
  30. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/th.lproj/Localizable.strings
  31. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/tr.lproj/Localizable.strings
  32. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/uk.lproj/Localizable.strings
  33. 1 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/vi.lproj/Localizable.strings
  34. BIN
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings
  35. BIN
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings
  36. 8 1
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.h
  37. 35 3
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.m
  38. 3 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZLocationManager.h
  39. 4 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZLocationManager.m
  40. 81 39
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPickerController.m
  41. 7 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPreviewCell.h
  42. 64 9
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPreviewCell.m
  43. 42 5
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPreviewController.m
  44. 24 0
      MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZVideoPlayerController.m
  45. 1 1
      MusicGradeExam/MusicGradeExam/UI/Exam/Controller/WaitExamViewController.m
  46. 25 1
      MusicGradeExam/MusicGradeExam/UI/Home/Controller/HomeViewController.m
  47. 20 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamConfigController.h
  48. 234 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamConfigController.m
  49. 22 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamRecordController.h
  50. 432 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamRecordController.m
  51. 23 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationWaitExamController.h
  52. 289 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationWaitExamController.m
  53. 34 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/View/SimulationExamConfigView.h
  54. 62 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/View/SimulationExamConfigView.m
  55. 176 0
      MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/View/SimulationExamConfigView.xib
  56. 1 0
      MusicGradeExam/MusicGradeExam/UI/Home/View/HomeBodyView.h
  57. 64 16
      MusicGradeExam/MusicGradeExam/UI/Home/View/HomeBodyView.xib
  58. 1 1
      MusicGradeExam/MusicGradeExam/UI/RecordExam/Controller/RecordExamViewController.m
  59. 2 0
      MusicGradeExam/MusicGradeExam/UI/RecordExam/View/RecordBodyView.h
  60. 9 4
      MusicGradeExam/MusicGradeExam/UI/RecordExam/View/RecordBodyView.xib

+ 162 - 102
MusicGradeExam/MusicGradeExam.xcodeproj/project.pbxproj

@@ -57,22 +57,6 @@
 		2747718C24BC0C0500181362 /* FastForwardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F8724BC0BFF00181362 /* FastForwardView.m */; };
 		2747718D24BC0C0500181362 /* WMPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F8824BC0BFF00181362 /* WMPlayer.m */; };
 		2747718E24BC0C0500181362 /* UIView+ShowProgress.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F8924BC0BFF00181362 /* UIView+ShowProgress.m */; };
-		2747718F24BC0C0500181362 /* TZImageCropManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F8E24BC0BFF00181362 /* TZImageCropManager.m */; };
-		2747719024BC0C0500181362 /* TZAssetCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9024BC0BFF00181362 /* TZAssetCell.m */; };
-		2747719124BC0C0500181362 /* TZVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9124BC0BFF00181362 /* TZVideoPlayerController.m */; };
-		2747719224BC0C0500181362 /* TZAssetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9224BC0BFF00181362 /* TZAssetModel.m */; };
-		2747719324BC0C0500181362 /* NSBundle+TZImagePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9324BC0BFF00181362 /* NSBundle+TZImagePicker.m */; };
-		2747719424BC0C0500181362 /* UIView+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9624BC0BFF00181362 /* UIView+Layout.m */; };
-		2747719524BC0C0500181362 /* TZPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9724BC0BFF00181362 /* TZPhotoPreviewController.m */; };
-		2747719624BC0C0500181362 /* TZImagePickerController.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 27476F9824BC0BFF00181362 /* TZImagePickerController.bundle */; };
-		2747719724BC0C0500181362 /* TZProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9924BC0BFF00181362 /* TZProgressView.m */; };
-		2747719824BC0C0500181362 /* TZImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9D24BC0BFF00181362 /* TZImageManager.m */; };
-		2747719924BC0C0500181362 /* TZPhotoPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476F9F24BC0BFF00181362 /* TZPhotoPickerController.m */; };
-		2747719A24BC0C0500181362 /* TZPhotoPreviewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FA024BC0BFF00181362 /* TZPhotoPreviewCell.m */; };
-		2747719B24BC0C0500181362 /* TZImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FA624BC0BFF00181362 /* TZImagePickerController.m */; };
-		2747719C24BC0C0500181362 /* TZLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FA724BC0BFF00181362 /* TZLocationManager.m */; };
-		2747719D24BC0C0500181362 /* TZGifPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FA824BC0BFF00181362 /* TZGifPhotoPreviewController.m */; };
-		2747719E24BC0C0500181362 /* TZImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FA924BC0BFF00181362 /* TZImageRequestOperation.m */; };
 		2747719F24BC0C0500181362 /* SCIndexViewConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FAC24BC0BFF00181362 /* SCIndexViewConfiguration.m */; };
 		274771A024BC0C0500181362 /* SCIndexView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FAE24BC0BFF00181362 /* SCIndexView.m */; };
 		274771A124BC0C0500181362 /* UITableView+SCIndexView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27476FB024BC0BFF00181362 /* UITableView+SCIndexView.m */; };
@@ -297,6 +281,27 @@
 		2748F8F624C138A0003F8E11 /* ExamLibraryListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2748F8F424C1389F003F8E11 /* ExamLibraryListCell.xib */; };
 		27544CF824BC337D00EF58AF /* ExamTicketViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27544CF724BC337D00EF58AF /* ExamTicketViewController.m */; };
 		27544CFB24BC338900EF58AF /* UserCenterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27544CFA24BC338900EF58AF /* UserCenterViewController.m */; };
+		2774F24225184AB4003473A2 /* SimulationExamConfigController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F24125184AB4003473A2 /* SimulationExamConfigController.m */; };
+		2774F2DB251877E0003473A2 /* TZImageCropManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2BE251877DF003473A2 /* TZImageCropManager.m */; };
+		2774F2DC251877E0003473A2 /* TZAssetCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C0251877DF003473A2 /* TZAssetCell.m */; };
+		2774F2DD251877E0003473A2 /* TZVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C1251877DF003473A2 /* TZVideoPlayerController.m */; };
+		2774F2DE251877E0003473A2 /* TZAssetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C2251877DF003473A2 /* TZAssetModel.m */; };
+		2774F2DF251877E0003473A2 /* NSBundle+TZImagePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C3251877DF003473A2 /* NSBundle+TZImagePicker.m */; };
+		2774F2E0251877E0003473A2 /* UIView+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C6251877DF003473A2 /* UIView+Layout.m */; };
+		2774F2E1251877E0003473A2 /* TZPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C7251877DF003473A2 /* TZPhotoPreviewController.m */; };
+		2774F2E2251877E0003473A2 /* TZImagePickerController.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 2774F2C8251877DF003473A2 /* TZImagePickerController.bundle */; };
+		2774F2E3251877E0003473A2 /* TZProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2C9251877DF003473A2 /* TZProgressView.m */; };
+		2774F2E4251877E0003473A2 /* TZImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2CD251877DF003473A2 /* TZImageManager.m */; };
+		2774F2E5251877E0003473A2 /* TZPhotoPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2CF251877DF003473A2 /* TZPhotoPickerController.m */; };
+		2774F2E6251877E0003473A2 /* TZPhotoPreviewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2D0251877DF003473A2 /* TZPhotoPreviewCell.m */; };
+		2774F2E7251877E0003473A2 /* TZImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2D6251877DF003473A2 /* TZImagePickerController.m */; };
+		2774F2E8251877E0003473A2 /* TZLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2D7251877DF003473A2 /* TZLocationManager.m */; };
+		2774F2E9251877E0003473A2 /* TZGifPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2D8251877DF003473A2 /* TZGifPhotoPreviewController.m */; };
+		2774F2EA251877E0003473A2 /* TZImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2D9251877DF003473A2 /* TZImageRequestOperation.m */; };
+		2774F2F325187B18003473A2 /* SimulationWaitExamController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2F225187B18003473A2 /* SimulationWaitExamController.m */; };
+		2774F2FC25189EFB003473A2 /* SimulationExamConfigView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F2FB25189EFA003473A2 /* SimulationExamConfigView.m */; };
+		2774F30125189F09003473A2 /* SimulationExamConfigView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2774F30025189F09003473A2 /* SimulationExamConfigView.xib */; };
+		2774F3072518B1D4003473A2 /* SimulationExamRecordController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2774F3062518B1D4003473A2 /* SimulationExamRecordController.m */; };
 		278D113424CA8E4D00599421 /* ExamDisplayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 278D113324CA8E4D00599421 /* ExamDisplayViewController.m */; };
 		278D113624CADC4800599421 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278D113524CADC4800599421 /* Photos.framework */; };
 		278D113924CFBACA00599421 /* ExamGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 278D113824CFBACA00599421 /* ExamGuideViewController.m */; };
@@ -481,37 +486,6 @@
 		27476F8824BC0BFF00181362 /* WMPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WMPlayer.m; sourceTree = "<group>"; };
 		27476F8924BC0BFF00181362 /* UIView+ShowProgress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ShowProgress.m"; sourceTree = "<group>"; };
 		27476F8A24BC0BFF00181362 /* KSPickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSPickerView.h; sourceTree = "<group>"; };
-		27476F8C24BC0BFF00181362 /* TZPhotoPreviewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewCell.h; sourceTree = "<group>"; };
-		27476F8D24BC0BFF00181362 /* TZPhotoPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPickerController.h; sourceTree = "<group>"; };
-		27476F8E24BC0BFF00181362 /* TZImageCropManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageCropManager.m; sourceTree = "<group>"; };
-		27476F8F24BC0BFF00181362 /* TZImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageManager.h; sourceTree = "<group>"; };
-		27476F9024BC0BFF00181362 /* TZAssetCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetCell.m; sourceTree = "<group>"; };
-		27476F9124BC0BFF00181362 /* TZVideoPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZVideoPlayerController.m; sourceTree = "<group>"; };
-		27476F9224BC0BFF00181362 /* TZAssetModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetModel.m; sourceTree = "<group>"; };
-		27476F9324BC0BFF00181362 /* NSBundle+TZImagePicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+TZImagePicker.m"; sourceTree = "<group>"; };
-		27476F9424BC0BFF00181362 /* TZLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZLocationManager.h; sourceTree = "<group>"; };
-		27476F9524BC0BFF00181362 /* TZImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImagePickerController.h; sourceTree = "<group>"; };
-		27476F9624BC0BFF00181362 /* UIView+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Layout.m"; sourceTree = "<group>"; };
-		27476F9724BC0BFF00181362 /* TZPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewController.m; sourceTree = "<group>"; };
-		27476F9824BC0BFF00181362 /* TZImagePickerController.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TZImagePickerController.bundle; sourceTree = "<group>"; };
-		27476F9924BC0BFF00181362 /* TZProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZProgressView.m; sourceTree = "<group>"; };
-		27476F9A24BC0BFF00181362 /* TZGifPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZGifPhotoPreviewController.h; sourceTree = "<group>"; };
-		27476F9B24BC0BFF00181362 /* TZImageRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageRequestOperation.h; sourceTree = "<group>"; };
-		27476F9C24BC0BFF00181362 /* TZAssetCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetCell.h; sourceTree = "<group>"; };
-		27476F9D24BC0BFF00181362 /* TZImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageManager.m; sourceTree = "<group>"; };
-		27476F9E24BC0BFF00181362 /* TZImageCropManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageCropManager.h; sourceTree = "<group>"; };
-		27476F9F24BC0BFF00181362 /* TZPhotoPickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPickerController.m; sourceTree = "<group>"; };
-		27476FA024BC0BFF00181362 /* TZPhotoPreviewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewCell.m; sourceTree = "<group>"; };
-		27476FA124BC0BFF00181362 /* NSBundle+TZImagePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+TZImagePicker.h"; sourceTree = "<group>"; };
-		27476FA224BC0BFF00181362 /* TZAssetModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetModel.h; sourceTree = "<group>"; };
-		27476FA324BC0BFF00181362 /* TZVideoPlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZVideoPlayerController.h; sourceTree = "<group>"; };
-		27476FA424BC0BFF00181362 /* TZPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewController.h; sourceTree = "<group>"; };
-		27476FA524BC0BFF00181362 /* UIView+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Layout.h"; sourceTree = "<group>"; };
-		27476FA624BC0BFF00181362 /* TZImagePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerController.m; sourceTree = "<group>"; };
-		27476FA724BC0BFF00181362 /* TZLocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZLocationManager.m; sourceTree = "<group>"; };
-		27476FA824BC0BFF00181362 /* TZGifPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZGifPhotoPreviewController.m; sourceTree = "<group>"; };
-		27476FA924BC0BFF00181362 /* TZImageRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageRequestOperation.m; sourceTree = "<group>"; };
-		27476FAA24BC0BFF00181362 /* TZProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZProgressView.h; sourceTree = "<group>"; };
 		27476FAC24BC0BFF00181362 /* SCIndexViewConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCIndexViewConfiguration.m; sourceTree = "<group>"; };
 		27476FAD24BC0BFF00181362 /* UITableView+SCIndexView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+SCIndexView.h"; sourceTree = "<group>"; };
 		27476FAE24BC0BFF00181362 /* SCIndexView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCIndexView.m; sourceTree = "<group>"; };
@@ -946,6 +920,46 @@
 		27544CF724BC337D00EF58AF /* ExamTicketViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExamTicketViewController.m; sourceTree = "<group>"; };
 		27544CF924BC338900EF58AF /* UserCenterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserCenterViewController.h; sourceTree = "<group>"; };
 		27544CFA24BC338900EF58AF /* UserCenterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UserCenterViewController.m; sourceTree = "<group>"; };
+		2774F24025184AB4003473A2 /* SimulationExamConfigController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimulationExamConfigController.h; sourceTree = "<group>"; };
+		2774F24125184AB4003473A2 /* SimulationExamConfigController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SimulationExamConfigController.m; sourceTree = "<group>"; };
+		2774F2BC251877DF003473A2 /* TZPhotoPreviewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewCell.h; sourceTree = "<group>"; };
+		2774F2BD251877DF003473A2 /* TZPhotoPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPickerController.h; sourceTree = "<group>"; };
+		2774F2BE251877DF003473A2 /* TZImageCropManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageCropManager.m; sourceTree = "<group>"; };
+		2774F2BF251877DF003473A2 /* TZImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageManager.h; sourceTree = "<group>"; };
+		2774F2C0251877DF003473A2 /* TZAssetCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetCell.m; sourceTree = "<group>"; };
+		2774F2C1251877DF003473A2 /* TZVideoPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZVideoPlayerController.m; sourceTree = "<group>"; };
+		2774F2C2251877DF003473A2 /* TZAssetModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetModel.m; sourceTree = "<group>"; };
+		2774F2C3251877DF003473A2 /* NSBundle+TZImagePicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+TZImagePicker.m"; sourceTree = "<group>"; };
+		2774F2C4251877DF003473A2 /* TZLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZLocationManager.h; sourceTree = "<group>"; };
+		2774F2C5251877DF003473A2 /* TZImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImagePickerController.h; sourceTree = "<group>"; };
+		2774F2C6251877DF003473A2 /* UIView+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Layout.m"; sourceTree = "<group>"; };
+		2774F2C7251877DF003473A2 /* TZPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewController.m; sourceTree = "<group>"; };
+		2774F2C8251877DF003473A2 /* TZImagePickerController.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TZImagePickerController.bundle; sourceTree = "<group>"; };
+		2774F2C9251877DF003473A2 /* TZProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZProgressView.m; sourceTree = "<group>"; };
+		2774F2CA251877DF003473A2 /* TZGifPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZGifPhotoPreviewController.h; sourceTree = "<group>"; };
+		2774F2CB251877DF003473A2 /* TZImageRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageRequestOperation.h; sourceTree = "<group>"; };
+		2774F2CC251877DF003473A2 /* TZAssetCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetCell.h; sourceTree = "<group>"; };
+		2774F2CD251877DF003473A2 /* TZImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageManager.m; sourceTree = "<group>"; };
+		2774F2CE251877DF003473A2 /* TZImageCropManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageCropManager.h; sourceTree = "<group>"; };
+		2774F2CF251877DF003473A2 /* TZPhotoPickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPickerController.m; sourceTree = "<group>"; };
+		2774F2D0251877DF003473A2 /* TZPhotoPreviewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewCell.m; sourceTree = "<group>"; };
+		2774F2D1251877DF003473A2 /* NSBundle+TZImagePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+TZImagePicker.h"; sourceTree = "<group>"; };
+		2774F2D2251877DF003473A2 /* TZAssetModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetModel.h; sourceTree = "<group>"; };
+		2774F2D3251877DF003473A2 /* TZVideoPlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZVideoPlayerController.h; sourceTree = "<group>"; };
+		2774F2D4251877DF003473A2 /* TZPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewController.h; sourceTree = "<group>"; };
+		2774F2D5251877DF003473A2 /* UIView+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Layout.h"; sourceTree = "<group>"; };
+		2774F2D6251877DF003473A2 /* TZImagePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerController.m; sourceTree = "<group>"; };
+		2774F2D7251877DF003473A2 /* TZLocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZLocationManager.m; sourceTree = "<group>"; };
+		2774F2D8251877DF003473A2 /* TZGifPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZGifPhotoPreviewController.m; sourceTree = "<group>"; };
+		2774F2D9251877DF003473A2 /* TZImageRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageRequestOperation.m; sourceTree = "<group>"; };
+		2774F2DA251877DF003473A2 /* TZProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZProgressView.h; sourceTree = "<group>"; };
+		2774F2F125187B18003473A2 /* SimulationWaitExamController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimulationWaitExamController.h; sourceTree = "<group>"; };
+		2774F2F225187B18003473A2 /* SimulationWaitExamController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SimulationWaitExamController.m; sourceTree = "<group>"; };
+		2774F2FA25189EFA003473A2 /* SimulationExamConfigView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimulationExamConfigView.h; sourceTree = "<group>"; };
+		2774F2FB25189EFA003473A2 /* SimulationExamConfigView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SimulationExamConfigView.m; sourceTree = "<group>"; };
+		2774F30025189F09003473A2 /* SimulationExamConfigView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SimulationExamConfigView.xib; sourceTree = "<group>"; };
+		2774F3052518B1D4003473A2 /* SimulationExamRecordController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimulationExamRecordController.h; sourceTree = "<group>"; };
+		2774F3062518B1D4003473A2 /* SimulationExamRecordController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SimulationExamRecordController.m; sourceTree = "<group>"; };
 		278D113224CA8E4D00599421 /* ExamDisplayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExamDisplayViewController.h; sourceTree = "<group>"; };
 		278D113324CA8E4D00599421 /* ExamDisplayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExamDisplayViewController.m; sourceTree = "<group>"; };
 		278D113524CADC4800599421 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; };
@@ -1299,6 +1313,7 @@
 		27476F7B24BC0BFF00181362 /* ThirdPart */ = {
 			isa = PBXGroup;
 			children = (
+				2774F2BB251877DF003473A2 /* TZImagePickerController */,
 				27476FE124BC0BFF00181362 /* ALCalendarPicker */,
 				27476FD524BC0BFF00181362 /* DZNSegmentedControl.h */,
 				27476F7D24BC0BFF00181362 /* DZNSegmentedControl.m */,
@@ -1312,7 +1327,6 @@
 				27476FDD24BC0BFF00181362 /* QWNavigationBar */,
 				27476FAB24BC0BFF00181362 /* SCIndexView */,
 				27476FD624BC0BFF00181362 /* TYCyclePagerView */,
-				27476F8B24BC0BFF00181362 /* TZImagePickerController */,
 				27476FF424BC0BFF00181362 /* UIView+Animation.h */,
 				27476FCE24BC0BFF00181362 /* UIView+Animation.m */,
 				27476FDF24BC0BFF00181362 /* UIView+ShowProgress.h */,
@@ -1339,44 +1353,6 @@
 			path = WMPlayer;
 			sourceTree = "<group>";
 		};
-		27476F8B24BC0BFF00181362 /* TZImagePickerController */ = {
-			isa = PBXGroup;
-			children = (
-				27476FA124BC0BFF00181362 /* NSBundle+TZImagePicker.h */,
-				27476F9324BC0BFF00181362 /* NSBundle+TZImagePicker.m */,
-				27476F9C24BC0BFF00181362 /* TZAssetCell.h */,
-				27476F9024BC0BFF00181362 /* TZAssetCell.m */,
-				27476FA224BC0BFF00181362 /* TZAssetModel.h */,
-				27476F9224BC0BFF00181362 /* TZAssetModel.m */,
-				27476F9A24BC0BFF00181362 /* TZGifPhotoPreviewController.h */,
-				27476FA824BC0BFF00181362 /* TZGifPhotoPreviewController.m */,
-				27476F9E24BC0BFF00181362 /* TZImageCropManager.h */,
-				27476F8E24BC0BFF00181362 /* TZImageCropManager.m */,
-				27476F8F24BC0BFF00181362 /* TZImageManager.h */,
-				27476F9D24BC0BFF00181362 /* TZImageManager.m */,
-				27476F9824BC0BFF00181362 /* TZImagePickerController.bundle */,
-				27476F9524BC0BFF00181362 /* TZImagePickerController.h */,
-				27476FA624BC0BFF00181362 /* TZImagePickerController.m */,
-				27476F9B24BC0BFF00181362 /* TZImageRequestOperation.h */,
-				27476FA924BC0BFF00181362 /* TZImageRequestOperation.m */,
-				27476F9424BC0BFF00181362 /* TZLocationManager.h */,
-				27476FA724BC0BFF00181362 /* TZLocationManager.m */,
-				27476F8D24BC0BFF00181362 /* TZPhotoPickerController.h */,
-				27476F9F24BC0BFF00181362 /* TZPhotoPickerController.m */,
-				27476F8C24BC0BFF00181362 /* TZPhotoPreviewCell.h */,
-				27476FA024BC0BFF00181362 /* TZPhotoPreviewCell.m */,
-				27476FA424BC0BFF00181362 /* TZPhotoPreviewController.h */,
-				27476F9724BC0BFF00181362 /* TZPhotoPreviewController.m */,
-				27476FAA24BC0BFF00181362 /* TZProgressView.h */,
-				27476F9924BC0BFF00181362 /* TZProgressView.m */,
-				27476FA324BC0BFF00181362 /* TZVideoPlayerController.h */,
-				27476F9124BC0BFF00181362 /* TZVideoPlayerController.m */,
-				27476FA524BC0BFF00181362 /* UIView+Layout.h */,
-				27476F9624BC0BFF00181362 /* UIView+Layout.m */,
-			);
-			path = TZImagePickerController;
-			sourceTree = "<group>";
-		};
 		27476FAB24BC0BFF00181362 /* SCIndexView */ = {
 			isa = PBXGroup;
 			children = (
@@ -1517,6 +1493,7 @@
 		2747700424BC0C0100181362 /* Home */ = {
 			isa = PBXGroup;
 			children = (
+				2774F23C25184A48003473A2 /* SimulationExam */,
 				2747700524BC0C0100181362 /* Controller */,
 				2747700824BC0C0100181362 /* Model */,
 				2747700924BC0C0100181362 /* View */,
@@ -2457,6 +2434,84 @@
 			path = View;
 			sourceTree = "<group>";
 		};
+		2774F23C25184A48003473A2 /* SimulationExam */ = {
+			isa = PBXGroup;
+			children = (
+				2774F23D25184A48003473A2 /* Controller */,
+				2774F23E25184A48003473A2 /* Model */,
+				2774F23F25184A48003473A2 /* View */,
+			);
+			path = SimulationExam;
+			sourceTree = "<group>";
+		};
+		2774F23D25184A48003473A2 /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+				2774F24025184AB4003473A2 /* SimulationExamConfigController.h */,
+				2774F24125184AB4003473A2 /* SimulationExamConfigController.m */,
+				2774F2F125187B18003473A2 /* SimulationWaitExamController.h */,
+				2774F2F225187B18003473A2 /* SimulationWaitExamController.m */,
+				2774F3052518B1D4003473A2 /* SimulationExamRecordController.h */,
+				2774F3062518B1D4003473A2 /* SimulationExamRecordController.m */,
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		2774F23E25184A48003473A2 /* Model */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Model;
+			sourceTree = "<group>";
+		};
+		2774F23F25184A48003473A2 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				2774F2FA25189EFA003473A2 /* SimulationExamConfigView.h */,
+				2774F2FB25189EFA003473A2 /* SimulationExamConfigView.m */,
+				2774F30025189F09003473A2 /* SimulationExamConfigView.xib */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
+		2774F2BB251877DF003473A2 /* TZImagePickerController */ = {
+			isa = PBXGroup;
+			children = (
+				2774F2D1251877DF003473A2 /* NSBundle+TZImagePicker.h */,
+				2774F2C3251877DF003473A2 /* NSBundle+TZImagePicker.m */,
+				2774F2CC251877DF003473A2 /* TZAssetCell.h */,
+				2774F2C0251877DF003473A2 /* TZAssetCell.m */,
+				2774F2D2251877DF003473A2 /* TZAssetModel.h */,
+				2774F2C2251877DF003473A2 /* TZAssetModel.m */,
+				2774F2CA251877DF003473A2 /* TZGifPhotoPreviewController.h */,
+				2774F2D8251877DF003473A2 /* TZGifPhotoPreviewController.m */,
+				2774F2CE251877DF003473A2 /* TZImageCropManager.h */,
+				2774F2BE251877DF003473A2 /* TZImageCropManager.m */,
+				2774F2BF251877DF003473A2 /* TZImageManager.h */,
+				2774F2CD251877DF003473A2 /* TZImageManager.m */,
+				2774F2C8251877DF003473A2 /* TZImagePickerController.bundle */,
+				2774F2C5251877DF003473A2 /* TZImagePickerController.h */,
+				2774F2D6251877DF003473A2 /* TZImagePickerController.m */,
+				2774F2CB251877DF003473A2 /* TZImageRequestOperation.h */,
+				2774F2D9251877DF003473A2 /* TZImageRequestOperation.m */,
+				2774F2C4251877DF003473A2 /* TZLocationManager.h */,
+				2774F2D7251877DF003473A2 /* TZLocationManager.m */,
+				2774F2BD251877DF003473A2 /* TZPhotoPickerController.h */,
+				2774F2CF251877DF003473A2 /* TZPhotoPickerController.m */,
+				2774F2BC251877DF003473A2 /* TZPhotoPreviewCell.h */,
+				2774F2D0251877DF003473A2 /* TZPhotoPreviewCell.m */,
+				2774F2D4251877DF003473A2 /* TZPhotoPreviewController.h */,
+				2774F2C7251877DF003473A2 /* TZPhotoPreviewController.m */,
+				2774F2DA251877DF003473A2 /* TZProgressView.h */,
+				2774F2C9251877DF003473A2 /* TZProgressView.m */,
+				2774F2D3251877DF003473A2 /* TZVideoPlayerController.h */,
+				2774F2C1251877DF003473A2 /* TZVideoPlayerController.m */,
+				2774F2D5251877DF003473A2 /* UIView+Layout.h */,
+				2774F2C6251877DF003473A2 /* UIView+Layout.m */,
+			);
+			path = TZImagePickerController;
+			sourceTree = "<group>";
+		};
 		27A0089924BD96C50002452B /* Networking */ = {
 			isa = PBXGroup;
 			children = (
@@ -2819,6 +2874,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				27A008ED24BDA7100002452B /* AboutBodyView.xib in Resources */,
+				2774F30125189F09003473A2 /* SimulationExamConfigView.xib in Resources */,
 				274771AE24BC0C0500181362 /* mss_browseLoading@2x.png in Resources */,
 				27A008CE24BD9E950002452B /* SettingBodyView.xib in Resources */,
 				2794D1BF24BD4D0C00BAF6F3 /* FSBodyView.xib in Resources */,
@@ -2848,7 +2904,6 @@
 				2729F7F124C8379D00E1F3C4 /* RecordListCell.xib in Resources */,
 				2794D1BA24BC69A400BAF6F3 /* RegisterBodyView.xib in Resources */,
 				27DBF9D824DAAE7500202145 /* WaitExamBottomView.xib in Resources */,
-				2747719624BC0C0500181362 /* TZImagePickerController.bundle in Resources */,
 				27A008DE24BDA6950002452B /* PhoneCheckBodyView.xib in Resources */,
 				27476F5324BBFB5C00181362 /* Assets.xcassets in Resources */,
 				27A008AE24BD96E50002452B /* DeviceCheckView.xib in Resources */,
@@ -2856,6 +2911,7 @@
 				278D114324CFD59B00599421 /* GuideNextPageView.xib in Resources */,
 				27476F5124BBFB5900181362 /* Main.storyboard in Resources */,
 				2729F7D324C8175E00E1F3C4 /* FileNameView.xib in Resources */,
+				2774F2E2251877E0003473A2 /* TZImagePickerController.bundle in Resources */,
 				273EFB4C24DCF5920069DB4D /* ExamSearchView.xib in Resources */,
 				273EFB6224DD36420069DB4D /* RCConfig.plist in Resources */,
 				27EF3EF324BEE885002068A2 /* NotifyMessageCell.xib in Resources */,
@@ -3008,18 +3064,19 @@
 			files = (
 				2729F7F924C8425E00E1F3C4 /* RecordTipsView.m in Sources */,
 				2747722A24BC0C0500181362 /* KSHoldButton.m in Sources */,
-				2747719A24BC0C0500181362 /* TZPhotoPreviewCell.m in Sources */,
 				274771E324BC0C0500181362 /* KSIMService.m in Sources */,
 				2747721D24BC0C0500181362 /* UIButton+Property.m in Sources */,
 				27EF3F2024C02B68002068A2 /* KSTipsView.m in Sources */,
 				27A008B824BD98170002452B /* AudioPlayManager.m in Sources */,
 				2747725224BC0C0500181362 /* JXCategoryBaseCell.m in Sources */,
 				2747723824BC0C0500181362 /* JXCategoryIndicatorImageView.m in Sources */,
+				2774F2E4251877E0003473A2 /* TZImageManager.m in Sources */,
 				2747725024BC0C0500181362 /* UIColor+JXAdd.m in Sources */,
 				2747723924BC0C0500181362 /* JXCategoryIndicatorBallView.m in Sources */,
 				2747721724BC0C0500181362 /* UIImageView+CornerRadius.m in Sources */,
 				2747722E24BC0C0500181362 /* KSAudioRecordManager.m in Sources */,
 				274771B024BC0C0500181362 /* UIView+Animation.m in Sources */,
+				2774F2E1251877E0003473A2 /* TZPhotoPreviewController.m in Sources */,
 				274771CA24BC0C0500181362 /* RoomLoginHelper.m in Sources */,
 				27EF3F0924C02B3F002068A2 /* LocalRenderManager.m in Sources */,
 				2794D1C724BD62FB00BAF6F3 /* ModifyBodyView.m in Sources */,
@@ -3030,6 +3087,7 @@
 				2747721424BC0C0500181362 /* NSDate+Transform.m in Sources */,
 				27EF3F2324C02B68002068A2 /* ClassVideoListView.m in Sources */,
 				27A008DD24BDA6950002452B /* PhoneCheckBodyView.m in Sources */,
+				2774F2E6251877E0003473A2 /* TZPhotoPreviewCell.m in Sources */,
 				2747724824BC0C0500181362 /* JXCategoryImageView.m in Sources */,
 				2747723424BC0C0500181362 /* JXPagerView.m in Sources */,
 				274771A524BC0C0500181362 /* MSSBrowseModel.m in Sources */,
@@ -3041,24 +3099,22 @@
 				2748F8F524C138A0003F8E11 /* ExamLibraryListCell.m in Sources */,
 				274771E524BC0C0500181362 /* FirstSettingViewController.m in Sources */,
 				27A008DC24BDA6950002452B /* PhoneChangeBodyView.m in Sources */,
-				2747719024BC0C0500181362 /* TZAssetCell.m in Sources */,
 				2747718824BC0C0500181362 /* DZNSegmentedControl.m in Sources */,
-				2747719B24BC0C0500181362 /* TZImagePickerController.m in Sources */,
 				2747726024BC0C0500181362 /* NSDate+KSBaseDatePicker.m in Sources */,
 				2747722C24BC0C0500181362 /* UIView+KSAdditions.m in Sources */,
-				2747719524BC0C0500181362 /* TZPhotoPreviewController.m in Sources */,
 				2747720324BC0C0500181362 /* UIViewController+zhStatusBarStyle.m in Sources */,
 				274771DF24BC0C0500181362 /* RoomMember.m in Sources */,
 				2747720624BC0C0500181362 /* NSMutableAttributedString+CZHExtention.m in Sources */,
 				2747720F24BC0C0500181362 /* NSDictionary+Extension.m in Sources */,
 				2747720824BC0C0500181362 /* UILabel+Extension.m in Sources */,
 				274771D924BC0C0500181362 /* DeviceMessage.m in Sources */,
-				2747719124BC0C0500181362 /* TZVideoPlayerController.m in Sources */,
 				2747721E24BC0C0500181362 /* UIDevice+TFDevice.m in Sources */,
 				2747721624BC0C0500181362 /* CALayer+KSLayout.m in Sources */,
 				2747721524BC0C0500181362 /* UIScreen+Extend.m in Sources */,
+				2774F2EA251877E0003473A2 /* TZImageRequestOperation.m in Sources */,
 				274771A324BC0C0500181362 /* MSSBrowseLocalViewController.m in Sources */,
 				2747723024BC0C0500181362 /* KSFullDatePicker.m in Sources */,
+				2774F2FC25189EFB003473A2 /* SimulationExamConfigView.m in Sources */,
 				278D113C24CFC6A200599421 /* ExamDeviceCheckView.m in Sources */,
 				2794D1B824BC699700BAF6F3 /* RegisterBodyView.m in Sources */,
 				2747720A24BC0C0500181362 /* UIColor+Extend.m in Sources */,
@@ -3078,6 +3134,7 @@
 				2747725524BC0C0500181362 /* UITextField_Toolbar.m in Sources */,
 				274771C924BC0C0500181362 /* ClassroomViewController.m in Sources */,
 				2747726524BC0C0500181362 /* LLCollectionViewCell.m in Sources */,
+				2774F2DD251877E0003473A2 /* TZVideoPlayerController.m in Sources */,
 				274771BF24BC0C0500181362 /* UIView+ALFrame.m in Sources */,
 				2747722624BC0C0500181362 /* MBProgressHUD+KSShow.m in Sources */,
 				2747722124BC0C0500181362 /* UIImage+ResizeImage.m in Sources */,
@@ -3116,12 +3173,16 @@
 				2729F7E324C8244100E1F3C4 /* ExamListCell.m in Sources */,
 				2747721224BC0C0500181362 /* NSDate+Extension.m in Sources */,
 				2747720924BC0C0500181362 /* UIAlertController+Extend.m in Sources */,
+				2774F2E7251877E0003473A2 /* TZImagePickerController.m in Sources */,
 				27A008C624BD99BD0002452B /* UserViewController.m in Sources */,
 				27A008EE24BDA7100002452B /* AboutBodyView.m in Sources */,
 				2729F7F424C8395300E1F3C4 /* RecordBottomView.m in Sources */,
+				2774F24225184AB4003473A2 /* SimulationExamConfigController.m in Sources */,
+				2774F3072518B1D4003473A2 /* SimulationExamRecordController.m in Sources */,
 				27476F4E24BBFB5900181362 /* ViewController.m in Sources */,
 				274771DC24BC0C0500181362 /* TurnPageMessage.m in Sources */,
 				2747721124BC0C0500181362 /* NSArray+ks_SafeAccess.m in Sources */,
+				2774F2DF251877E0003473A2 /* NSBundle+TZImagePicker.m in Sources */,
 				2747722924BC0C0500181362 /* KSChoosePicker.m in Sources */,
 				274771B224BC0C0500181362 /* ZKCycleScrollViewFlowLayout.m in Sources */,
 				274771BB24BC0C0500181362 /* ALCalendarDate.m in Sources */,
@@ -3132,10 +3193,11 @@
 				2747724C24BC0C0500181362 /* JXCategoryNumberCell.m in Sources */,
 				274771B824BC0C0500181362 /* ALCalendarCell.m in Sources */,
 				2747723F24BC0C0500181362 /* JXCategoryDotCell.m in Sources */,
+				2774F2E3251877E0003473A2 /* TZProgressView.m in Sources */,
 				274771F224BC0C0500181362 /* KSNetworking+RequestOperation.m in Sources */,
+				2774F2DB251877E0003473A2 /* TZImageCropManager.m in Sources */,
 				2747720E24BC0C0500181362 /* NSString+CZHSizeExtension.m in Sources */,
 				2747720024BC0C0500181362 /* UIControl+ButtonAction.m in Sources */,
-				2747719924BC0C0500181362 /* TZPhotoPickerController.m in Sources */,
 				274771E924BC0C0500181362 /* ModifyViewController.m in Sources */,
 				2747725D24BC0C0500181362 /* KSMessageInputView.m in Sources */,
 				274771CB24BC0C0500181362 /* RTCService.m in Sources */,
@@ -3152,7 +3214,6 @@
 				274771A224BC0C0500181362 /* MSSBrowseLoadingImageView.m in Sources */,
 				274771CE24BC0C0500181362 /* HTTPUtility.m in Sources */,
 				274771D324BC0C0500181362 /* ControlDeviceNotifyMessage.m in Sources */,
-				2747719324BC0C0500181362 /* NSBundle+TZImagePicker.m in Sources */,
 				27A008B524BD97FE0002452B /* AudioRecordManager.m in Sources */,
 				27DBF9D624DAAE6200202145 /* WaitExamBottomView.m in Sources */,
 				2747721924BC0C0500181362 /* UIImage+Color.m in Sources */,
@@ -3167,7 +3228,7 @@
 				274771BD24BC0C0500181362 /* ALCalendarHelper.m in Sources */,
 				274771B624BC0C0500181362 /* KSPickerView.m in Sources */,
 				274771B424BC0C0500181362 /* TYCyclePagerView.m in Sources */,
-				2747719824BC0C0500181362 /* TZImageManager.m in Sources */,
+				2774F2F325187B18003473A2 /* SimulationWaitExamController.m in Sources */,
 				27A008E924BDA7070002452B /* AboutUsViewController.m in Sources */,
 				27544CF824BC337D00EF58AF /* ExamTicketViewController.m in Sources */,
 				2794D1B024BC604800BAF6F3 /* VefiBodyView.m in Sources */,
@@ -3181,6 +3242,7 @@
 				274771B724BC0C0500181362 /* NSObject+ReadDocument.m in Sources */,
 				274771BE24BC0C0500181362 /* ALCalendarPicker.m in Sources */,
 				274771D824BC0C0500181362 /* InviteUpgradeMessage.m in Sources */,
+				2774F2E5251877E0003473A2 /* TZPhotoPickerController.m in Sources */,
 				2747725324BC0C0500181362 /* JXCategoryBaseCellModel.m in Sources */,
 				2748F8F124C05F4D003F8E11 /* ExamLibraryController.m in Sources */,
 				2747722324BC0C0500181362 /* NSObject+AutoProperty.m in Sources */,
@@ -3197,17 +3259,17 @@
 				2747725424BC0C0500181362 /* MBProgressHUD+NJ.m in Sources */,
 				27A008D324BDA67F0002452B /* ModifyPhoneChangeController.m in Sources */,
 				2747724A24BC0C0500181362 /* JXCategoryImageCellModel.m in Sources */,
+				2774F2DE251877E0003473A2 /* TZAssetModel.m in Sources */,
 				27EF3F0324BF0F12002068A2 /* TicketListModel.m in Sources */,
 				2747721C24BC0C0500181362 /* UrlDecode.m in Sources */,
 				2747724724BC0C0500181362 /* JXCategoryTitleView.m in Sources */,
 				274771F724BC0C0500181362 /* KSCacheManager.m in Sources */,
 				2747722224BC0C0500181362 /* UIButton+HasChooseImage.m in Sources */,
-				2747719E24BC0C0500181362 /* TZImageRequestOperation.m in Sources */,
 				2747725C24BC0C0500181362 /* NSString+MD5.m in Sources */,
+				2774F2E9251877E0003473A2 /* TZGifPhotoPreviewController.m in Sources */,
 				2747724124BC0C0500181362 /* JXCategoryDotCellModel.m in Sources */,
 				274771E224BC0C0500181362 /* KSRemoteUserManager.m in Sources */,
 				2747725B24BC0C0500181362 /* KSImageButton.m in Sources */,
-				2747719724BC0C0500181362 /* TZProgressView.m in Sources */,
 				274771AB24BC0C0500181362 /* MSSBrowseRemindView.m in Sources */,
 				274771A924BC0C0500181362 /* MSSBrowseBaseViewController.m in Sources */,
 				27A008A524BD96C50002452B /* NetworkingCheckController.m in Sources */,
@@ -3234,7 +3296,6 @@
 				2747725824BC0C0500181362 /* SkipTextView.m in Sources */,
 				2747725E24BC0C0500181362 /* KSInputView.m in Sources */,
 				27EF3F2224C02B68002068A2 /* ClassTitleView.m in Sources */,
-				2747719C24BC0C0500181362 /* TZLocationManager.m in Sources */,
 				2747720524BC0C0500181362 /* CALayer+Color.m in Sources */,
 				274771D124BC0C0500181362 /* ApplySpeechMessage.m in Sources */,
 				274771FF24BC0C0500181362 /* NSObject+AssociatedObject.m in Sources */,
@@ -3247,11 +3308,8 @@
 				27A008FC24BECDC40002452B /* HomeBodyView.m in Sources */,
 				2747722D24BC0C0500181362 /* KSRecordStatusView.m in Sources */,
 				27A008A824BD96C50002452B /* KSNetworkAlert.m in Sources */,
-				2747719224BC0C0500181362 /* TZAssetModel.m in Sources */,
 				274771DB24BC0C0500181362 /* ApplySpeechResultMessage.m in Sources */,
 				2747723624BC0C0500181362 /* JXCategoryIndicatorLineView.m in Sources */,
-				2747719424BC0C0500181362 /* UIView+Layout.m in Sources */,
-				2747719D24BC0C0500181362 /* TZGifPhotoPreviewController.m in Sources */,
 				2747724E24BC0C0500181362 /* JXCategoryFactory.m in Sources */,
 				27EF3F2524C02B68002068A2 /* ClassVideoListCell.m in Sources */,
 				2747722524BC0C0500181362 /* UIButton+EnlargeEdge.m in Sources */,
@@ -3264,6 +3322,7 @@
 				274771AD24BC0C0500181362 /* MSSBrowseActionSheetCell.m in Sources */,
 				274771EF24BC0C0500181362 /* KSRCIMDataSource.m in Sources */,
 				274771EB24BC0C0500181362 /* UserInfoManager.m in Sources */,
+				2774F2DC251877E0003473A2 /* TZAssetCell.m in Sources */,
 				2747723224BC0C0500181362 /* JXPagerListContainerView.m in Sources */,
 				2729F7F024C8379D00E1F3C4 /* RecordListCell.m in Sources */,
 				27A008C324BD99B10002452B /* SettingViewController.m in Sources */,
@@ -3271,7 +3330,6 @@
 				274771DA24BC0C0500181362 /* MemberChangeMessage.m in Sources */,
 				2747721824BC0C0500181362 /* NSObject+ReadDocument.m in Sources */,
 				27EF3F2624C02B68002068A2 /* MainToolView.m in Sources */,
-				2747718F24BC0C0500181362 /* TZImageCropManager.m in Sources */,
 				2729F7C724C6C87400E1F3C4 /* OpenFileViewController.m in Sources */,
 				2747725924BC0C0500181362 /* GRScanManager.m in Sources */,
 				2747724224BC0C0500181362 /* JXCategoryTitleImageView.m in Sources */,
@@ -3283,6 +3341,8 @@
 				274771B924BC0C0500181362 /* ALCalendarConfig.m in Sources */,
 				2747726324BC0C0500181362 /* LLFileManager.m in Sources */,
 				274771FE24BC0C0500181362 /* NSMutableString+KSSafe.m in Sources */,
+				2774F2E0251877E0003473A2 /* UIView+Layout.m in Sources */,
+				2774F2E8251877E0003473A2 /* TZLocationManager.m in Sources */,
 				2729F7CD24C6F3F300E1F3C4 /* SongListModel.m in Sources */,
 				27D4149B24CA757A000DBC0C /* SongModel.m in Sources */,
 				2747723D24BC0C0500181362 /* JXCategoryIndicatorCell.m in Sources */,

+ 22 - 0
MusicGradeExam/MusicGradeExam/Assets.xcassets/Home/home_SExam.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "home_SExam@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "home_SExam@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
MusicGradeExam/MusicGradeExam/Assets.xcassets/Home/home_SExam.imageset/home_SExam@2x.png


BIN
MusicGradeExam/MusicGradeExam/Assets.xcassets/Home/home_SExam.imageset/home_SExam@3x.png


+ 23 - 2
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZAssetCell.m

@@ -41,6 +41,7 @@
         // Set the cell's thumbnail image if it's still showing the same asset.
         if ([self.representedAssetIdentifier isEqualToString:model.asset.localIdentifier]) {
             self.imageView.image = photo;
+            [self setNeedsLayout];
         } else {
             // NSLog(@"this cell is showing other asset");
             [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
@@ -168,6 +169,12 @@
     }
     
     _bigImageRequestID = [[TZImageManager manager] requestImageDataForAsset:_model.asset completion:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
+        BOOL iCloudSyncFailed = !imageData && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
+        self.model.iCloudFailed = iCloudSyncFailed;
+        if (iCloudSyncFailed && self.didSelectPhotoBlock) {
+            self.didSelectPhotoBlock(YES);
+            self.selectImageView.image = self.photoDefImage;
+        }
         [self hideProgressView];
     } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
         if (self.model.isSelected) {
@@ -185,6 +192,18 @@
             [self cancelBigImageRequest];
         }
     }];
+    if (_model.type == TZAssetCellTypeVideo) {
+        [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
+            BOOL iCloudSyncFailed = !playerItem && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
+            self.model.iCloudFailed = iCloudSyncFailed;
+            if (iCloudSyncFailed && self.didSelectPhotoBlock) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    self.didSelectPhotoBlock(YES);
+                    self.selectImageView.image = self.photoDefImage;
+                });
+            }
+        }];
+    }
 }
 
 - (void)cancelBigImageRequest {
@@ -266,6 +285,7 @@
     if (_bottomView == nil) {
         UIView *bottomView = [[UIView alloc] init];
         static NSInteger rgb = 0;
+        bottomView.userInteractionEnabled = NO;
         bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8];
         [self.contentView addSubview:bottomView];
         _bottomView = bottomView;
@@ -341,8 +361,8 @@
         _selectImageView.contentMode = UIViewContentModeScaleAspectFit;
     }
     _indexLabel.frame = _selectImageView.frame;
-    _imageView.frame = CGRectMake(0, 0, self.tz_width, self.tz_height);
-    
+    _imageView.frame = self.bounds;
+
     static CGFloat progressWH = 20;
     CGFloat progressXY = (self.tz_width - progressWH) / 2;
     _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH);
@@ -394,6 +414,7 @@
     self.titleLabel.attributedText = nameString;
     [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) {
         self.posterImageView.image = postImage;
+        [self setNeedsLayout];
     }];
     if (model.selectedCount) {
         self.selectedCountButton.hidden = NO;

+ 5 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZAssetModel.h

@@ -8,6 +8,7 @@
 
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
+#import <Photos/Photos.h>
 
 typedef enum : NSUInteger {
     TZAssetModelMediaTypePhoto = 0,
@@ -24,6 +25,7 @@ typedef enum : NSUInteger {
 @property (nonatomic, assign) BOOL isSelected;      ///< The select status of a photo, default is No
 @property (nonatomic, assign) TZAssetModelMediaType type;
 @property (nonatomic, copy) NSString *timeLength;
+@property (nonatomic, assign) BOOL iCloudFailed;
 
 /// Init a photo dataModel With a PHAsset
 /// 用一个PHAsset实例,初始化一个照片模型
@@ -39,6 +41,8 @@ typedef enum : NSUInteger {
 @property (nonatomic, strong) NSString *name;        ///< The album name
 @property (nonatomic, assign) NSInteger count;       ///< Count of photos the album contain
 @property (nonatomic, strong) PHFetchResult *result;
+@property (nonatomic, strong) PHAssetCollection *collection;
+@property (nonatomic, strong) PHFetchOptions *options;
 
 @property (nonatomic, strong) NSArray *models;
 @property (nonatomic, strong) NSArray *selectedModels;
@@ -47,5 +51,6 @@ typedef enum : NSUInteger {
 @property (nonatomic, assign) BOOL isCameraRoll;
 
 - (void)setResult:(PHFetchResult *)result needFetchAssets:(BOOL)needFetchAssets;
+- (void)refreshFetchResult;
 
 @end

+ 6 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZAssetModel.m

@@ -43,6 +43,12 @@
     }
 }
 
+- (void)refreshFetchResult {
+    PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:self.collection options:self.options];
+    self.count = fetchResult.count;
+    [self setResult:fetchResult];
+}
+
 - (void)setSelectedModels:(NSArray *)selectedModels {
     _selectedModels = selectedModels;
     if (_models) {

+ 31 - 24
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImageManager.m

@@ -117,7 +117,7 @@ static dispatch_once_t onceToken;
         if (collection.estimatedAssetCount <= 0) continue;
         if ([self isCameraRollAlbum:collection]) {
             PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
-            model = [self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets];
+            model = [self modelWithResult:fetchResult collection:collection isCameraRoll:YES needFetchAssets:needFetchAssets options:option];
             if (completion) completion(model);
             break;
         }
@@ -159,9 +159,9 @@ static dispatch_once_t onceToken;
             if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumAllHidden) continue;
             if (collection.assetCollectionSubtype == 1000000201) continue; //『最近删除』相册
             if ([self isCameraRollAlbum:collection]) {
-                [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0];
+                [albumArr insertObject:[self modelWithResult:fetchResult collection:collection isCameraRoll:YES needFetchAssets:needFetchAssets options:option] atIndex:0];
             } else {
-                [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:NO needFetchAssets:needFetchAssets]];
+                [albumArr addObject:[self modelWithResult:fetchResult collection:collection isCameraRoll:NO needFetchAssets:needFetchAssets options:option]];
             }
         }
     }
@@ -364,17 +364,13 @@ static dispatch_once_t onceToken;
         imageSize = CGSizeMake(pixelWidth, pixelHeight);
     }
     
-    __block UIImage *image;
     // 修复获取图片时出现的瞬间内存过高问题
     // 下面两行代码,来自hsjcom,他的github是:https://github.com/hsjcom 表示感谢
     PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
     option.resizeMode = PHImageRequestOptionsResizeModeFast;
     int32_t imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
-        if (result) {
-            image = result;
-        }
-        BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
-        if (downloadFinined && result) {
+        BOOL cancelled = [[info objectForKey:PHImageCancelledKey] boolValue];
+        if (!cancelled && result) {
             result = [self fixOrientation:result];
             if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
         }
@@ -395,8 +391,8 @@ static dispatch_once_t onceToken;
                 if (![TZImagePickerConfig sharedInstance].notScaleImage) {
                     resultImage = [self scaleImage:resultImage toSize:imageSize];
                 }
-                if (!resultImage) {
-                    resultImage = image;
+                if (!resultImage && result) {
+                    resultImage = result;
                 }
                 resultImage = [self fixOrientation:resultImage];
                 if (completion) completion(resultImage,info,NO);
@@ -441,8 +437,8 @@ static dispatch_once_t onceToken;
     }
     option.resizeMode = PHImageRequestOptionsResizeModeFast;
     return [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage *result, NSDictionary *info) {
-        BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
-        if (downloadFinined && result) {
+        BOOL cancelled = [[info objectForKey:PHImageCancelledKey] boolValue];
+        if (!cancelled && result) {
             result = [self fixOrientation:result];
             BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue];
             if (completion) completion(result,info,isDegraded);
@@ -464,8 +460,8 @@ static dispatch_once_t onceToken;
     [option setProgressHandler:progressHandler];
     option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
     return [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
-        BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
-        if (downloadFinined && imageData) {
+        BOOL cancelled = [[info objectForKey:PHImageCancelledKey] boolValue];
+        if (!cancelled && imageData) {
             if (completion) completion(imageData,info,NO);
         }
     }];
@@ -489,8 +485,7 @@ static dispatch_once_t onceToken;
     } completionHandler:^(BOOL success, NSError *error) {
         dispatch_async(dispatch_get_main_queue(), ^{
             if (success && completion) {
-                PHAsset *asset = [[PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
-                completion(asset, nil);
+                [self fetchAssetByIocalIdentifier:localIdentifier retryCount:10 completion:completion];
             } else if (error) {
                 NSLog(@"保存照片出错:%@",error.localizedDescription);
                 if (completion) {
@@ -526,8 +521,7 @@ static dispatch_once_t onceToken;
         [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
         dispatch_async(dispatch_get_main_queue(), ^{
             if (success && completion) {
-                PHAsset *asset = [[PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
-                completion(asset, nil);
+                [self fetchAssetByIocalIdentifier:localIdentifier retryCount:10 completion:completion];
             } else if (error) {
                 NSLog(@"保存照片出错:%@",error.localizedDescription);
                 if (completion) {
@@ -538,6 +532,19 @@ static dispatch_once_t onceToken;
     }];
 }
 
+- (void)fetchAssetByIocalIdentifier:(NSString *)localIdentifier retryCount:(NSInteger)retryCount completion:(void (^)(PHAsset *asset, NSError *error))completion {
+    PHAsset *asset = [[PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
+    if (asset || retryCount <= 0) {
+        if (completion) {
+            completion(asset, nil);
+        }
+        return;
+    }
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        [self fetchAssetByIocalIdentifier:localIdentifier retryCount:retryCount - 1 completion:completion];
+    });
+}
+
 #pragma mark - Save video
 
 - (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(PHAsset *asset, NSError *error))completion {
@@ -556,8 +563,7 @@ static dispatch_once_t onceToken;
     } completionHandler:^(BOOL success, NSError *error) {
         dispatch_async(dispatch_get_main_queue(), ^{
             if (success && completion) {
-                PHAsset *asset = [[PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
-                completion(asset, nil);
+                [self fetchAssetByIocalIdentifier:localIdentifier retryCount:10 completion:completion];
             } else if (error) {
                 NSLog(@"保存视频出错:%@",error.localizedDescription);
                 if (completion) {
@@ -599,7 +605,6 @@ static dispatch_once_t onceToken;
 
 - (void)getVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
     PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
-    options.version = PHVideoRequestOptionsVersionOriginal;
     options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
     options.networkAccessAllowed = YES;
     [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
@@ -732,10 +737,12 @@ static dispatch_once_t onceToken;
 
 #pragma mark - Private Method
 
-- (TZAlbumModel *)modelWithResult:(PHFetchResult *)result name:(NSString *)name isCameraRoll:(BOOL)isCameraRoll needFetchAssets:(BOOL)needFetchAssets {
+- (TZAlbumModel *)modelWithResult:(PHFetchResult *)result collection:(PHAssetCollection *)collection isCameraRoll:(BOOL)isCameraRoll needFetchAssets:(BOOL)needFetchAssets options:(PHFetchOptions *)options {
     TZAlbumModel *model = [[TZAlbumModel alloc] init];
     [model setResult:result needFetchAssets:needFetchAssets];
-    model.name = name;
+    model.name = collection.localizedTitle;
+    model.collection = collection;
+    model.options = options;
     model.isCameraRoll = isCameraRoll;
     model.count = result.count;
     return model;

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ar.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "معالجة...";
 "No Photos or Videos"     = "لا توجد صور أو مقاطع فيديو";
 "Synchronizing photos from iCloud" = "مزامنة الصور من iCloud";
+"iCloud sync failed"    = "iCloud فشلت المزامنة";
 "Can not use camera"      = "لا يمكن استخدام الكاميرا";
 "Can not choose both video and photo" = "لا يمكن اختيار كل من الفيديو والصور";
 "Can not choose both photo and GIF" = "لا يمكن اختيار كل من الصور و GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/bg.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Обработка ...";
 "No Photos or Videos"     = "Няма снимки или видеоклипове";
 "Synchronizing photos from iCloud" = "Синхронизиране на снимки от iCloud";
+"iCloud sync failed"    = "iCloud синхронизирането не бе успешно";
 "Can not use camera"      = "Не може да се използва камера";
 "Can not choose both video and photo" = "Не можете да изберете видео и снимка";
 "Can not choose both photo and GIF" = "Не може да се избере снимка и GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/cs-CZ.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Zpracovává se...";
 "No Photos or Videos"     = "Žádné fotky nebo videa";
 "Synchronizing photos from iCloud" = "Synchronizace fotografií z iCloud";
+"iCloud sync failed"    = "iCloud synchronizace selhala";
 "Can not use camera"      = "Nelze použít fotoaparát";
 "Can not choose both video and photo" = "Nelze vybrat video ani fotografii";
 "Can not choose both photo and GIF" = "Nelze vybrat fotografie a GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/de.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Wird bearbeitet...";
 "No Photos or Videos"     = "Keine Fotos oder Videos";
 "Synchronizing photos from iCloud" = "Fotos aus iCloud synchronisieren";
+"iCloud sync failed"    = "iCloud Synchronisierung fehlgeschlagen";
 "Can not use camera"      = "Kann die Kamera nicht benutzen";
 "Can not choose both video and photo" = "Video und Foto können nicht ausgewählt werden";
 "Can not choose both photo and GIF" = "Foto und GIF können nicht ausgewählt werden";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/el.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Επεξεργασία...";
 "No Photos or Videos"     = "Δεν υπάρχουν φωτογραφίες ή βίντεο";
 "Synchronizing photos from iCloud" = "Συγχρονισμός φωτογραφιών από το iCloud";
+"iCloud sync failed"    = "iCloud Ο συγχρονισμός απέτυχε";
 "Can not use camera"      = "Δεν είναι δυνατή η χρήση της κάμερας";
 "Can not choose both video and photo" = "Δεν είναι δυνατή η επιλογή του βίντεο και της φωτογραφίας";
 "Can not choose both photo and GIF" = "Δεν είναι δυνατή η επιλογή φωτογραφίας και GIF";

BIN
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings


+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/es.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Tratamiento...";
 "No Photos or Videos"     = "No hay fotos o videos";
 "Synchronizing photos from iCloud" = "Sincronizando fotos desde iCloud";
+"iCloud sync failed"    = "la sincronización falló";
 "Can not use camera"      = "No puedo usar la camara";
 "Can not choose both video and photo" = "No se puede elegir tanto el video como la foto.";
 "Can not choose both photo and GIF" = "No se puede elegir tanto foto como GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/fr.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "En traitement...";
 "No Photos or Videos"     = "Aucune photo ou vidéo";
 "Synchronizing photos from iCloud" = "Synchroniser des photos depuis iCloud";
+"iCloud sync failed"    = "iCloud échec de la synchronisation";
 "Can not use camera"      = "Impossible d'utiliser la caméra";
 "Can not choose both video and photo" = "Impossible de choisir à la fois la vidéo et la photo";
 "Can not choose both photo and GIF" = "Impossible de choisir à la fois photo et GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/he.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "מעבד...";
 "No Photos or Videos"     = "אין תמונות או סרטונים";
 "Synchronizing photos from iCloud" = "סנכרון תמונות מ - iCloud";
+"iCloud sync failed"    = "iCloud הסנכרון נכשל";
 "Can not use camera"      = "לא ניתן להשתמש במצלמה";
 "Can not choose both video and photo" = "לא ניתן לבחור הן בסרטון והן בתמונה";
 "Can not choose both photo and GIF" = "לא ניתן לבחור גם תמונה וגם קובץ GIF";

BIN
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/iCloudError@2x.png


+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/it.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "In lavorazione...";
 "No Photos or Videos"     = "Nessuna foto o video";
 "Synchronizing photos from iCloud" = "Sincronizzazione delle foto da iCloud";
+"iCloud sync failed"    = "iCloud sincronizzazione non riuscita";
 "Can not use camera"      = "Non è possibile utilizzare la fotocamera";
 "Can not choose both video and photo" = "Non è possibile scegliere sia video che foto";
 "Can not choose both photo and GIF" = "Non è possibile scegliere sia foto che GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ja.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "処理...";
 "No Photos or Videos"     = "写真やビデオはありません";
 "Synchronizing photos from iCloud" = "iCloudから写真を同期する";
+"iCloud sync failed"    = "iCloud同期に失敗しました";
 "Can not use camera"      = "カメラが使えない";
 "Can not choose both video and photo" = "ビデオと写真の両方を選択することはできません";
 "Can not choose both photo and GIF" = "写真とGIFの両方を選択することはできません";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ko-KP.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "처리...";
 "No Photos or Videos"     = "아무 사진이 나 동영상";
 "Synchronizing photos from iCloud" = "ICloud에서 사진을 동기화";
+"iCloud sync failed"    = "iCloud동기화 실패";
 "Can not use camera"      = "카메라를 사용할 수 없습니다.";
 "Can not choose both video and photo" = "비디오와 사진 둘 다를 선택할 수 없습니다.";
 "Can not choose both photo and GIF" = "사진 및 GIF를 선택할 수 없습니다.";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ko.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "처리 중 ...";
 "No Photos or Videos"     = "사진이나 동영상 없음";
 "Synchronizing photos from iCloud" = "iCloud에서 사진 동기화";
+"iCloud sync failed"    = "iCloud동기화 실패";
 "Can not use camera"      = "카메라를 사용할 수 없습니다.";
 "Can not choose both video and photo" = "동영상과 사진을 모두 선택할 수 없습니다.";
 "Can not choose both photo and GIF" = "사진과 GIF를 모두 선택할 수 없습니다.";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/nl.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Verwerken...";
 "No Photos or Videos"     = "Geen foto's of video's";
 "Synchronizing photos from iCloud" = "Foto's synchroniseren vanuit iCloud";
+"iCloud sync failed"    = "iCloud synchronisatie is mislukt";
 "Can not use camera"      = "Kan de camera niet gebruiken";
 "Can not choose both video and photo" = "Kan niet zowel video als foto kiezen";
 "Can not choose both photo and GIF" = "Kan niet zowel foto als GIF kiezen";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/pl.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Przetwarzanie...";
 "No Photos or Videos"     = "Brak zdjęć lub filmów";
 "Synchronizing photos from iCloud" = "Synchronizowanie zdjęć z iCloud";
+"iCloud sync failed"    = "iCloud synchronizacja nie powiodła się";
 "Can not use camera"      = "Nie można używać aparatu";
 "Can not choose both video and photo" = "Nie można wybrać zarówno wideo,jak i zdjęcia";
 "Can not choose both photo and GIF" = "Nie można wybrać zarówno zdjęcia,jak i GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/pt.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Em processamento...";
 "No Photos or Videos"     = "Sem fotos ou vídeos";
 "Synchronizing photos from iCloud" = "Sincronizando fotos do iCloud";
+"iCloud sync failed"    = "iCloud falha na sincronização";
 "Can not use camera"      = "Não pode usar a câmera";
 "Can not choose both video and photo" = "Não é possível escolher vídeo e foto";
 "Can not choose both photo and GIF" = "Não é possível escolher foto e GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ro.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Prelucrare...";
 "No Photos or Videos"     = "Nu există fotografii sau videoclipuri";
 "Synchronizing photos from iCloud" = "Sincronizarea fotografiilor cu iCloud";
+"iCloud sync failed"    = "iCloud sincronizarea a eșuat";
 "Can not use camera"      = "Nu pot folosi camera";
 "Can not choose both video and photo" = "Nu puteți alege atât videoclipul,cât și fotografia";
 "Can not choose both photo and GIF" = "Nu puteți alege atât fotografia,cât și GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/ru.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Обработка ...";
 "No Photos or Videos"     = "Нет фото или видео";
 "Synchronizing photos from iCloud" = "Синхронизация фотографий из iCloud";
+"iCloud sync failed"    = "iCloud сбой синхронизации";
 "Can not use camera"      = "Не могу использовать камеру";
 "Can not choose both video and photo" = "Не могу выбрать как видео,так и фото";
 "Can not choose both photo and GIF" = "Не могу выбрать фото и GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/sk.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Spracovanie ...";
 "No Photos or Videos"     = "Žiadne fotografie alebo videá";
 "Synchronizing photos from iCloud" = "Synchronizácia fotografií z iCloud";
+"iCloud sync failed"    = "iCloud synchronizácia zlyhala";
 "Can not use camera"      = "Fotoaparát nie je možné používať";
 "Can not choose both video and photo" = "Nie je možné vybrať video aj fotografiu";
 "Can not choose both photo and GIF" = "Nie je možné vybrať fotografie a obrázky GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/sv.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Bearbetning ...";
 "No Photos or Videos"     = "Inga foton eller videor";
 "Synchronizing photos from iCloud" = "Synkronisera foton från iCloud";
+"iCloud sync failed"    = "iCloud synkroniseringen misslyckades";
 "Can not use camera"      = "Kan inte använda kamera";
 "Can not choose both video and photo" = "Kan inte välja både video och foto";
 "Can not choose both photo and GIF" = "Kan inte välja både foto och GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/th.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "กำลังประมวลผล ...";
 "No Photos or Videos"     = "ไม่มีรูปภาพหรือวิดีโอ";
 "Synchronizing photos from iCloud" = "การซิงโครไนซ์ภาพถ่ายจาก iCloud";
+"iCloud sync failed"    = "iCloud การซิงค์ล้มเหลว";
 "Can not use camera"      = "ไม่สามารถใช้กล้องถ่ายรูป";
 "Can not choose both video and photo" = "ไม่สามารถเลือกได้ทั้งวิดีโอและภาพถ่าย";
 "Can not choose both photo and GIF" = "ไม่สามารถเลือกได้ทั้งภาพถ่ายและ GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/tr.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "İşleme...";
 "No Photos or Videos"     = "Fotoğraf veya Video Yok";
 "Synchronizing photos from iCloud" = "Fotoğrafları iCloud'dan senkronize etme";
+"iCloud sync failed"    = "iCloud senkronizasyon başarısız oldu";
 "Can not use camera"      = "Kamera kullanılamaz";
 "Can not choose both video and photo" = "Hem video hem de fotoğraf seçilemiyor";
 "Can not choose both photo and GIF" = "Hem fotoğraf hem de GIF seçilemiyor";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/uk.lproj/Localizable.strings

@@ -12,6 +12,7 @@
 "Processing..."           = "Обробка ...";
 "No Photos or Videos"     = "Немає фотографій або відео";
 "Synchronizing photos from iCloud" = "Синхронізація фотографій з iCloud";
+"iCloud sync failed"    = "iCloud помилка синхронізації";
 "Can not use camera"      = "Не можна використовувати камеру";
 "Can not choose both video and photo" = "Неможливо вибрати як відео,так і фото";
 "Can not choose both photo and GIF" = "Неможливо вибрати як фото,так і GIF";

+ 1 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/vi.lproj/Localizable.strings

@@ -13,6 +13,7 @@
 "No Photos or Videos"     = "Không có ảnh hoặc video";
 "Can not use camera" = "Máy chụp hình không khả dụng";
 "Synchronizing photos from iCloud" = "Đang đồng bộ hình ảnh từ ICloud";
+"iCloud sync failed"    = "iCloud đồng bộ hóa không thành công";
 "Can not choose both video and photo" = "Trong lúc chọn hình ảnh không cùng lúc chọn video";
 "Can not choose both photo and GIF" = "Trong lúc chọn hình ảnh không cùng lúc chọn hình GIF";
 "Select the video when in multi state, we will handle the video as a photo" = "Chọn hình ảnh cùng video, video sẽ bị mặc nhận thành hình ảnh và gửi đi.";

BIN
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings


BIN
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings


+ 8 - 1
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.h

@@ -4,7 +4,7 @@
 //
 //  Created by 谭真 on 15/12/24.
 //  Copyright © 2015年 谭真. All rights reserved.
-//  version 3.2.9 - 2019.12.20
+//  version 3.4.2 - 2020.08.17
 //  更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
 
 /*
@@ -48,6 +48,10 @@
 /// 最小照片必选张数,默认是0
 @property (nonatomic, assign) NSInteger minImagesCount;
 
+/// If the user does not select any pictures, the current picture is automatically selected when the Finish button is clicked,  Default is YES
+/// 如果用户未选择任何图片,在点击完成按钮时自动选中当前图片,默认YES
+@property (nonatomic, assign) BOOL autoSelectCurrentWhenDone;
+
 /// Always enale the done button, not require minimum 1 photo be picked
 /// 让完成按钮一直可以点击,无须最少选择一张图片
 @property (nonatomic, assign) BOOL alwaysEnableDoneBtn;
@@ -174,6 +178,7 @@
 @property (nonatomic, copy) void (^photoPreviewPageUIConfigBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel);
 @property (nonatomic, copy) void (^videoPreviewPageUIConfigBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton);
 @property (nonatomic, copy) void (^gifPreviewPageUIConfigBlock)(UIView *toolBar, UIButton *doneButton);
+@property (nonatomic, copy) void (^albumPickerPageUIConfigBlock)(UITableView *tableView);
 @property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
 @property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
 /// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等
@@ -181,6 +186,7 @@
 @property (nonatomic, copy) void (^photoPreviewPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel);
 @property (nonatomic, copy) void (^videoPreviewPageDidLayoutSubviewsBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton);
 @property (nonatomic, copy) void (^gifPreviewPageDidLayoutSubviewsBlock)(UIView *toolBar, UIButton *doneButton);
+@property (nonatomic, copy) void (^albumPickerPageDidLayoutSubviewsBlock)(UITableView *tableView);
 @property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
 @property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
 /// 自定义各页面/组件的frame】刷新底部状态(refreshNaviBarAndBottomBarState)使用的
@@ -305,6 +311,7 @@
 + (NSDictionary *)tz_getInfoDictionary;
 + (BOOL)tz_isRightToLeftLayout;
 + (void)configBarButtonItem:(UIBarButtonItem *)item tzImagePickerVc:(TZImagePickerController *)tzImagePickerVc;
++ (BOOL)isICloudSyncError:(NSError *)error;
 @end
 
 

+ 35 - 3
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZImagePickerController.m

@@ -4,7 +4,7 @@
 //
 //  Created by 谭真 on 15/12/24.
 //  Copyright © 2015年 谭真. All rights reserved.
-//  version 3.2.9 - 2019.12.20
+//  version 3.4.2 - 2020.08.17
 //  更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
 
 #import "TZImagePickerController.h"
@@ -33,6 +33,7 @@
 /// Default is 4, Use in photos collectionView in TZPhotoPickerController
 /// 默认4列, TZPhotoPickerController中的照片collectionView
 @property (nonatomic, assign) NSInteger columnNumber;
+@property (nonatomic, assign) NSInteger HUDTimeoutCount; ///< 超时隐藏HUD计数
 @end
 
 @implementation TZImagePickerController
@@ -262,6 +263,7 @@
 }
 
 - (void)configDefaultSetting {
+    self.autoSelectCurrentWhenDone = YES;
     self.timeout = 15;
     self.photoWidth = 828.0;
     self.photoPreviewMaxWidth = 600;
@@ -447,10 +449,15 @@
     [self.view setNeedsLayout];
     
     // if over time, dismiss HUD automatic
+    self.HUDTimeoutCount++;
     __weak typeof(self) weakSelf = self;
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
         __strong typeof(weakSelf) strongSelf = weakSelf;
-        [strongSelf hideProgressHUD];
+        strongSelf.HUDTimeoutCount--;
+        if (strongSelf.HUDTimeoutCount <= 0) {
+            strongSelf.HUDTimeoutCount = 0;
+            [strongSelf hideProgressHUD];
+        }
     });
 }
 
@@ -700,7 +707,7 @@
 @end
 
 
-@interface TZAlbumPickerController ()<UITableViewDataSource,UITableViewDelegate> {
+@interface TZAlbumPickerController ()<UITableViewDataSource, UITableViewDelegate, PHPhotoLibraryChangeObserver> {
     UITableView *_tableView;
 }
 @property (nonatomic, strong) NSMutableArray *albumArr;
@@ -710,6 +717,7 @@
 
 - (void)viewDidLoad {
     [super viewDidLoad];
+    [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
     self.isFirstAppear = YES;
     self.view.backgroundColor = [UIColor whiteColor];
     
@@ -770,6 +778,9 @@
                     self->_tableView.delegate = self;
                     [self->_tableView registerClass:[TZAlbumCell class] forCellReuseIdentifier:@"TZAlbumCell"];
                     [self.view addSubview:self->_tableView];
+                    if (imagePickerVc.albumPickerPageUIConfigBlock) {
+                        imagePickerVc.albumPickerPageUIConfigBlock(self->_tableView);
+                    }
                 } else {
                     [self->_tableView reloadData];
                 }
@@ -779,6 +790,7 @@
 }
 
 - (void)dealloc {
+    [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
     // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
 }
 
@@ -790,6 +802,14 @@
     return [super preferredStatusBarStyle];
 }
 
+#pragma mark - PHPhotoLibraryChangeObserver
+
+- (void)photoLibraryDidChange:(PHChange *)changeInstance {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self configTableView];
+    });
+}
+
 #pragma mark - Layout
 
 - (void)viewDidLayoutSubviews {
@@ -808,6 +828,10 @@
         tableViewHeight = self.view.tz_height;
     }
     _tableView.frame = CGRectMake(0, top, self.view.tz_width, tableViewHeight);
+    TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
+    if (imagePickerVc.albumPickerPageDidLayoutSubviewsBlock) {
+        imagePickerVc.albumPickerPageDidLayoutSubviewsBlock(_tableView);
+    }
 }
 
 #pragma mark - UITableViewDataSource && Delegate
@@ -907,6 +931,14 @@
     [item setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
 }
 
++ (BOOL)isICloudSyncError:(NSError *)error {
+    if (!error) return NO;
+    if ([error.domain isEqualToString:@"CKErrorDomain"] || [error.domain isEqualToString:@"CloudPhotoLibraryErrorDomain"]) {
+        return YES;
+    }
+    return NO;
+}
+
 @end
 
 

+ 3 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZLocationManager.h

@@ -20,5 +20,8 @@
 - (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
 - (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
 
+/// 结束定位
+- (void)stopUpdatingLocation;
+
 @end
 

+ 4 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZLocationManager.m

@@ -52,6 +52,10 @@
     _failureBlock = failureBlock;
 }
 
+- (void)stopUpdatingLocation {
+    [self.locationManager stopUpdatingLocation];
+}
+
 #pragma mark - CLLocationManagerDelegate
 
 /// 地理位置发生改变时触发

+ 81 - 39
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPickerController.m

@@ -19,7 +19,7 @@
 #import <MobileCoreServices/MobileCoreServices.h>
 #import "TZImageRequestOperation.h"
 
-@interface TZPhotoPickerController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIAlertViewDelegate> {
+@interface TZPhotoPickerController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate, PHPhotoLibraryChangeObserver> {
     NSMutableArray *_models;
     
     UIView *_bottomToolBar;
@@ -44,6 +44,7 @@
 @property (nonatomic, strong) UIImagePickerController *imagePickerVc;
 @property (strong, nonatomic) CLLocation *location;
 @property (nonatomic, strong) NSOperationQueue *operationQueue;
+@property (nonatomic, assign) BOOL isSavingMedia;
 @end
 
 static CGSize AssetGridThumbnailSize;
@@ -76,6 +77,7 @@ static CGFloat itemMargin = 5;
 
 - (void)viewDidLoad {
     [super viewDidLoad];
+    [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
     self.isFirstAppear = YES;
     TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
     _isSelectOriginalPhoto = tzImagePickerVc.isSelectOriginalPhoto;
@@ -116,16 +118,14 @@ static CGFloat itemMargin = 5;
                 self->_models = [NSMutableArray arrayWithArray:self->_model.models];
                 [self initSubviews];
             }];
-        } else {
-            if (self->_showTakePhotoBtn || self->_isFirstAppear) {
-                [[TZImageManager manager] getAssetsFromFetchResult:self->_model.result completion:^(NSArray<TZAssetModel *> *models) {
-                    self->_models = [NSMutableArray arrayWithArray:models];
-                    [self initSubviews];
-                }];
-            } else {
-                self->_models = [NSMutableArray arrayWithArray:self->_model.models];
+        } else if (self->_showTakePhotoBtn || self->_isFirstAppear || !self.model.models) {
+            [[TZImageManager manager] getAssetsFromFetchResult:self->_model.result completion:^(NSArray<TZAssetModel *> *models) {
+                self->_models = [NSMutableArray arrayWithArray:models];
                 [self initSubviews];
-            }
+            }];
+        } else {
+            self->_models = [NSMutableArray arrayWithArray:self->_model.models];
+            [self initSubviews];
         }
     });
 }
@@ -163,13 +163,20 @@ static CGFloat itemMargin = 5;
 }
 
 - (void)configCollectionView {
-    _layout = [[UICollectionViewFlowLayout alloc] init];
-    _collectionView = [[TZCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout];
-    _collectionView.backgroundColor = [UIColor whiteColor];
-    _collectionView.dataSource = self;
-    _collectionView.delegate = self;
-    _collectionView.alwaysBounceHorizontal = NO;
-    _collectionView.contentInset = UIEdgeInsetsMake(itemMargin, itemMargin, itemMargin, itemMargin);
+    if (!_collectionView) {
+        _layout = [[UICollectionViewFlowLayout alloc] init];
+        _collectionView = [[TZCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout];
+        _collectionView.backgroundColor = [UIColor whiteColor];
+        _collectionView.dataSource = self;
+        _collectionView.delegate = self;
+        _collectionView.alwaysBounceHorizontal = NO;
+        _collectionView.contentInset = UIEdgeInsetsMake(itemMargin, itemMargin, itemMargin, itemMargin);
+        [self.view addSubview:_collectionView];
+        [_collectionView registerClass:[TZAssetCell class] forCellWithReuseIdentifier:@"TZAssetCell"];
+        [_collectionView registerClass:[TZAssetCameraCell class] forCellWithReuseIdentifier:@"TZAssetCameraCell"];
+    } else {
+        [_collectionView reloadData];
+    }
     
     if (_showTakePhotoBtn) {
         _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber) / self.columnNumber) * self.view.tz_width);
@@ -183,11 +190,11 @@ static CGFloat itemMargin = 5;
             _noDataLabel.textColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
             _noDataLabel.font = [UIFont boldSystemFontOfSize:20];
             [_collectionView addSubview:_noDataLabel];
+        } else if (_noDataLabel) {
+            [_noDataLabel removeFromSuperview];
+            _noDataLabel = nil;
         }
     }
-    [self.view addSubview:_collectionView];
-    [_collectionView registerClass:[TZAssetCell class] forCellWithReuseIdentifier:@"TZAssetCell"];
-    [_collectionView registerClass:[TZAssetCameraCell class] forCellWithReuseIdentifier:@"TZAssetCameraCell"];
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -207,6 +214,7 @@ static CGFloat itemMargin = 5;
 
 - (void)viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
+    self.isFirstAppear = NO;
     // [self updateCachedAssets];
 }
 
@@ -393,6 +401,7 @@ static CGFloat itemMargin = 5;
     }
     
     [tzImagePickerVc showProgressHUD];
+    _doneButton.enabled = NO;
     NSMutableArray *assets = [NSMutableArray array];
     NSMutableArray *photos;
     NSMutableArray *infoArr;
@@ -431,7 +440,6 @@ static CGFloat itemMargin = 5;
             } progressHandler:^(double progress, NSError * _Nonnull error, BOOL * _Nonnull stop, NSDictionary * _Nonnull info) {
                 // 如果图片正在从iCloud同步中,提醒用户
                 if (progress < 1 && havenotShowAlert && !alertView) {
-                    [tzImagePickerVc hideProgressHUD];
                     alertView = [tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]];
                     havenotShowAlert = NO;
                     return;
@@ -451,7 +459,8 @@ static CGFloat itemMargin = 5;
 - (void)didGetAllPhotos:(NSArray *)photos assets:(NSArray *)assets infoArr:(NSArray *)infoArr {
     TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
     [tzImagePickerVc hideProgressHUD];
-    
+    _doneButton.enabled = YES;
+
     if (tzImagePickerVc.autoDismiss) {
         [self.navigationController dismissViewControllerAnimated:YES completion:^{
             [self callDelegateMethodWithPhotos:photos assets:assets infoArr:infoArr];
@@ -565,14 +574,25 @@ static CGFloat itemMargin = 5;
                 [[NSNotificationCenter defaultCenter] postNotificationName:@"TZ_PHOTO_PICKER_RELOAD_NOTIFICATION" object:strongSelf.navigationController];
             }
             [UIView showOscillatoryAnimationWithLayer:strongLayer type:TZOscillatoryAnimationToSmaller];
+            if (strongCell.model.iCloudFailed) {
+                [strongSelf->_models replaceObjectAtIndex:indexPath.item withObject:strongCell.model];
+                NSString *title = [NSBundle tz_localizedStringForKey:@"iCloud sync failed"];
+                [tzImagePickerVc showAlertWithTitle:title];
+            }
         } else {
             // 2. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制
             if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) {
-                if (tzImagePickerVc.maxImagesCount == 1 && !tzImagePickerVc.allowPreview) {
-                    model.isSelected = YES;
-                    [tzImagePickerVc addSelectedModel:model];
-                    [strongSelf doneButtonClick];
-                    return;
+                if (!tzImagePickerVc.allowPreview) {
+                    BOOL shouldDone = tzImagePickerVc.maxImagesCount == 1;
+                    if (!tzImagePickerVc.allowPickingMultipleVideo && (model.type == TZAssetModelMediaTypeVideo || model.type == TZAssetModelMediaTypePhotoGif)) {
+                        shouldDone = YES;
+                    }
+                    if (shouldDone) {
+                        model.isSelected = YES;
+                        [tzImagePickerVc addSelectedModel:model];
+                        [strongSelf doneButtonClick];
+                        return;
+                    }
                 }
                 strongCell.selectPhotoButton.selected = YES;
                 model.isSelected = YES;
@@ -648,9 +668,16 @@ static CGFloat itemMargin = 5;
         if (!appName) appName = [infoDict valueForKey:@"CFBundleName"];
         if (!appName) appName = [infoDict valueForKey:@"CFBundleExecutable"];
 
+        NSString *title = [NSBundle tz_localizedStringForKey:@"Can not use camera"];
         NSString *message = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\""],appName];
-        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Can not use camera"] message:message delegate:self cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"Cancel"] otherButtonTitles:[NSBundle tz_localizedStringForKey:@"Setting"], nil];
-        [alert show];
+        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
+        UIAlertAction *cancelAct = [UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"Cancel"] style:UIAlertActionStyleCancel handler:nil];
+        [alertController addAction:cancelAct];
+        UIAlertAction *settingAct = [UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"Setting"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
+        }];
+        [alertController addAction:settingAct];
+        [self.navigationController presentViewController:alertController animated:YES completion:nil];
     } else if (authStatus == AVAuthorizationStatusNotDetermined) {
         // fix issue 466, 防止用户首次拍照拒绝授权时相机页黑屏
         [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
@@ -795,14 +822,6 @@ static CGFloat itemMargin = 5;
     }
 }
 
-#pragma mark - UIAlertViewDelegate
-
-- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
-    if (buttonIndex == 1) { // 去设置界面,开启相机访问权限
-        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
-    }
-}
-
 #pragma mark - UIImagePickerControllerDelegate
 
 - (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
@@ -814,9 +833,14 @@ static CGFloat itemMargin = 5;
         UIImage *photo = [info objectForKey:UIImagePickerControllerOriginalImage];
         NSDictionary *meta = [info objectForKey:UIImagePickerControllerMediaMetadata];
         if (photo) {
+            self.isSavingMedia = YES;
             [[TZImageManager manager] savePhotoWithImage:photo meta:meta location:self.location completion:^(PHAsset *asset, NSError *error){
-                if (!error) {
+                self.isSavingMedia = NO;
+                if (!error && asset) {
                     [self addPHAsset:asset];
+                } else {
+                    TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
+                    [tzImagePickerVc hideProgressHUD];
                 }
             }];
             self.location = nil;
@@ -826,9 +850,14 @@ static CGFloat itemMargin = 5;
         [imagePickerVc showProgressHUD];
         NSURL *videoUrl = [info objectForKey:UIImagePickerControllerMediaURL];
         if (videoUrl) {
+            self.isSavingMedia = YES;
             [[TZImageManager manager] saveVideoWithUrl:videoUrl location:self.location completion:^(PHAsset *asset, NSError *error) {
-                if (!error) {
+                self.isSavingMedia = NO;
+                if (!error && asset) {
                     [self addPHAsset:asset];
+                } else {
+                    TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
+                    [tzImagePickerVc hideProgressHUD];
                 }
             }];
             self.location = nil;
@@ -884,10 +913,23 @@ static CGFloat itemMargin = 5;
 }
 
 - (void)dealloc {
+    [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
     [[NSNotificationCenter defaultCenter] removeObserver:self];
     // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
 }
 
+#pragma mark - PHPhotoLibraryChangeObserver
+
+- (void)photoLibraryDidChange:(PHChange *)changeInstance {
+    if (self.isSavingMedia) {
+        return;
+    }
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self.model refreshFetchResult];        
+        [self fetchAssetModels];
+    });
+}
+
 #pragma mark - Asset Caching
 
 - (void)resetCachedAssets {

+ 7 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPreviewCell.h

@@ -38,6 +38,10 @@
 @property (nonatomic, strong) UIScrollView *scrollView;
 @property (nonatomic, strong) UIView *imageContainerView;
 @property (nonatomic, strong) TZProgressView *progressView;
+@property (nonatomic, strong) UIImageView *iCloudErrorIcon;
+@property (nonatomic, strong) UILabel *iCloudErrorLabel;
+@property (nonatomic, copy) void (^iCloudSyncFailedHandle)(id asset, BOOL isSyncFailed);
+
 
 @property (nonatomic, assign) BOOL allowCrop;
 @property (nonatomic, assign) CGRect cropRect;
@@ -60,6 +64,9 @@
 @property (strong, nonatomic) UIButton *playButton;
 @property (strong, nonatomic) UIImage *cover;
 @property (nonatomic, strong) NSURL *videoURL;
+@property (nonatomic, strong) UIImageView *iCloudErrorIcon;
+@property (nonatomic, strong) UILabel *iCloudErrorLabel;
+@property (nonatomic, copy) void (^iCloudSyncFailedHandle)(id asset, BOOL isSyncFailed);
 - (void)pausePlayerAndShowNaviBar;
 @end
 

+ 64 - 9
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPreviewCell.m

@@ -61,12 +61,12 @@
             strongSelf.imageProgressUpdateBlock(progress);
         }
     }];
-    [self addSubview:self.previewView];
+    [self.contentView addSubview:self.previewView];
 }
 
 - (void)setModel:(TZAssetModel *)model {
     [super setModel:model];
-    _previewView.asset = model.asset;
+    _previewView.model = model;
 }
 
 - (void)recoverSubviews {
@@ -133,6 +133,17 @@
         _imageView.contentMode = UIViewContentModeScaleAspectFill;
         _imageView.clipsToBounds = YES;
         [_imageContainerView addSubview:_imageView];
+
+        _iCloudErrorIcon = [[UIImageView alloc] init];
+        _iCloudErrorIcon.image = [UIImage tz_imageNamedFromMyBundle:@"iCloudError"];
+        _iCloudErrorIcon.hidden = YES;
+        [self addSubview:_iCloudErrorIcon];
+        _iCloudErrorLabel = [[UILabel alloc] init];
+        _iCloudErrorLabel.font = [UIFont systemFontOfSize:10];
+        _iCloudErrorLabel.textColor = [UIColor whiteColor];
+        _iCloudErrorLabel.text = [NSBundle tz_localizedStringForKey:@"iCloud sync failed"];
+        _iCloudErrorLabel.hidden = YES;
+        [self addSubview:_iCloudErrorLabel];
         
         UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
         [self addGestureRecognizer:tap1];
@@ -159,7 +170,9 @@
     if (model.type == TZAssetModelMediaTypePhotoGif) {
         // 先显示缩略图
         [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
-            self.imageView.image = photo;
+            if (photo) {
+                self.imageView.image = photo;
+            }
             [self resizeSubviews];
             if (self.isRequestingGIF) {
                 return;
@@ -169,6 +182,13 @@
             [[TZImageManager manager] getOriginalPhotoDataWithAsset:model.asset progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
                 progress = progress > 0.02 ? progress : 0.02;
                 dispatch_async(dispatch_get_main_queue(), ^{
+                    BOOL iCloudSyncFailed = [TZCommonTools isICloudSyncError:error];
+                    self.iCloudErrorLabel.hidden = !iCloudSyncFailed;
+                    self.iCloudErrorIcon.hidden = !iCloudSyncFailed;
+                    if (self.iCloudSyncFailedHandle) {
+                        self.iCloudSyncFailedHandle(model.asset, iCloudSyncFailed);
+                    }
+                    
                     self.progressView.progress = progress;
                     if (progress >= 1) {
                         self.progressView.hidden = YES;
@@ -204,8 +224,16 @@
     
     _asset = asset;
     self.imageRequestID = [[TZImageManager manager] getPhotoWithAsset:asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
+        BOOL iCloudSyncFailed = !photo && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
+        self.iCloudErrorLabel.hidden = !iCloudSyncFailed;
+        self.iCloudErrorIcon.hidden = !iCloudSyncFailed;
+        if (self.iCloudSyncFailedHandle) {
+            self.iCloudSyncFailedHandle(asset, iCloudSyncFailed);
+        }
         if (![asset isEqual:self->_asset]) return;
-        self.imageView.image = photo;
+        if (photo) {
+            self.imageView.image = photo;
+        }
         [self resizeSubviews];
         if (self.imageView.tz_height && self.allowCrop) {
             CGFloat scale = MAX(self.cropRect.size.width / self.imageView.tz_width, self.cropRect.size.height / self.imageView.tz_height);
@@ -216,7 +244,7 @@
                 [self.scrollView setZoomScale:scale animated:YES];
             }
         }
-
+        
         self->_progressView.hidden = YES;
         if (self.imageProgressUpdateBlock) {
             self.imageProgressUpdateBlock(1);
@@ -313,8 +341,9 @@
     CGFloat progressX = (self.tz_width - progressWH) / 2;
     CGFloat progressY = (self.tz_height - progressWH) / 2;
     _progressView.frame = CGRectMake(progressX, progressY, progressWH, progressWH);
-    
     [self recoverSubviews];
+    _iCloudErrorIcon.frame = CGRectMake(20, [TZCommonTools tz_isIPhoneX] ? 88 + 10 : 64 + 10, 28, 28);
+    _iCloudErrorLabel.frame = CGRectMake(53, [TZCommonTools tz_isIPhoneX] ? 88 + 10 : 64 + 10, self.tz_width - 63, 28);
 }
 
 #pragma mark - UITapGestureRecognizer Event
@@ -371,6 +400,14 @@
 
 - (void)configSubviews {
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActiveNotification) name:UIApplicationWillResignActiveNotification object:nil];
+    _iCloudErrorIcon = [[UIImageView alloc] init];
+    _iCloudErrorIcon.image = [UIImage tz_imageNamedFromMyBundle:@"iCloudError"];
+    _iCloudErrorIcon.hidden = YES;
+    _iCloudErrorLabel = [[UILabel alloc] init];
+    _iCloudErrorLabel.font = [UIFont systemFontOfSize:10];
+    _iCloudErrorLabel.textColor = [UIColor whiteColor];
+    _iCloudErrorLabel.text = [NSBundle tz_localizedStringForKey:@"iCloud sync failed"];
+    _iCloudErrorLabel.hidden = YES;
 }
 
 - (void)configPlayButton {
@@ -381,7 +418,9 @@
     [_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
     [_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
     [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
-    [self addSubview:_playButton];
+    [self.contentView addSubview:_playButton];
+    [self.contentView addSubview:_iCloudErrorIcon];
+    [self.contentView addSubview:_iCloudErrorLabel];
 }
 
 - (void)setModel:(TZAssetModel *)model {
@@ -404,10 +443,24 @@
     
     if (self.model && self.model.asset) {
         [[TZImageManager manager] getPhotoWithAsset:self.model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
-            self.cover = photo;
+            BOOL iCloudSyncFailed = !photo && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
+            self.iCloudErrorLabel.hidden = !iCloudSyncFailed;
+            self.iCloudErrorIcon.hidden = !iCloudSyncFailed;
+            if (self.iCloudSyncFailedHandle) {
+                self.iCloudSyncFailedHandle(self.model.asset, iCloudSyncFailed);
+            }
+            if (photo) {
+                self.cover = photo;
+            }
         }];
         [[TZImageManager manager] getVideoWithAsset:self.model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
             dispatch_async(dispatch_get_main_queue(), ^{
+                BOOL iCloudSyncFailed = !playerItem && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
+                self.iCloudErrorLabel.hidden = !iCloudSyncFailed;
+                self.iCloudErrorIcon.hidden = !iCloudSyncFailed;
+                if (self.iCloudSyncFailedHandle) {
+                    self.iCloudSyncFailedHandle(self.model.asset, iCloudSyncFailed);
+                }
                 [self configPlayerWithItem:playerItem];
             });
         }];
@@ -431,6 +484,8 @@
     [super layoutSubviews];
     _playerLayer.frame = self.bounds;
     _playButton.frame = CGRectMake(0, 64, self.tz_width, self.tz_height - 64 - 44);
+    _iCloudErrorIcon.frame = CGRectMake(20, [TZCommonTools tz_isIPhoneX] ? 88 + 10 : 64 + 10, 28, 28);
+    _iCloudErrorLabel.frame = CGRectMake(53, [TZCommonTools tz_isIPhoneX] ? 88 + 10 : 64 + 10, self.tz_width - 63, 28);
 }
 
 - (void)photoPreviewCollectionViewDidScroll {
@@ -489,7 +544,7 @@
         __strong typeof(weakSelf) strongSelf = weakSelf;
         [strongSelf signleTapAction];
     }];
-    [self addSubview:_previewView];
+    [self.contentView addSubview:_previewView];
 }
 
 - (void)setModel:(TZAssetModel *)model {

+ 42 - 5
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZPhotoPreviewController.m

@@ -42,6 +42,7 @@
 
 @property (nonatomic, assign) double progress;
 @property (strong, nonatomic) UIAlertController *alertView;
+@property (nonatomic, strong) UIView *iCloudErrorView;
 @end
 
 @implementation TZPhotoPreviewController
@@ -382,9 +383,8 @@
     }
     
     // 如果没有选中过照片 点击确定时选中当前预览的照片
-    if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) {
-        TZAssetModel *model = _models[self.currentIndex];
-        [_tzImagePickerVc addSelectedModel:model];
+    if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0 && _tzImagePickerVc.autoSelectCurrentWhenDone) {
+        [self select:_selectButton];
     }
     NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.currentIndex inSection:0];
     TZPhotoPreviewCell *cell = (TZPhotoPreviewCell *)[_collectionView cellForItemAtIndexPath:indexPath];
@@ -442,7 +442,6 @@
         _currentIndex = currentIndex;
         [self refreshNaviBarAndBottomBarState];
     }
-    
     [[NSNotificationCenter defaultCenter] postNotificationName:@"photoPreviewCollectionViewDidScroll" object:nil];
 }
 
@@ -460,8 +459,20 @@
     __weak typeof(self) weakSelf = self;
     if (_tzImagePickerVc.allowPickingMultipleVideo && model.type == TZAssetModelMediaTypeVideo) {
         cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZVideoPreviewCell" forIndexPath:indexPath];
+        TZVideoPreviewCell *currentCell = (TZVideoPreviewCell *)cell;
+        currentCell.iCloudSyncFailedHandle = ^(id asset, BOOL isSyncFailed) {
+            model.iCloudFailed = isSyncFailed;
+            [weakSelf didICloudSyncStatusChanged:model];
+            [weakSelf.models replaceObjectAtIndex:indexPath.item withObject:model];
+        };
     } else if (_tzImagePickerVc.allowPickingMultipleVideo && model.type == TZAssetModelMediaTypePhotoGif && _tzImagePickerVc.allowPickingGif) {
         cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZGifPreviewCell" forIndexPath:indexPath];
+        TZGifPreviewCell *currentCell = (TZGifPreviewCell *)cell;
+        currentCell.previewView.iCloudSyncFailedHandle = ^(id asset, BOOL isSyncFailed) {
+            model.iCloudFailed = isSyncFailed;
+            [weakSelf didICloudSyncStatusChanged:model];
+            [weakSelf.models replaceObjectAtIndex:indexPath.item withObject:model];
+        };
     } else {
         cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZPhotoPreviewCell" forIndexPath:indexPath];
         TZPhotoPreviewCell *photoPreviewCell = (TZPhotoPreviewCell *)cell;
@@ -486,6 +497,11 @@
                 }
             }
         }];
+        photoPreviewCell.previewView.iCloudSyncFailedHandle = ^(id asset, BOOL isSyncFailed) {
+            model.iCloudFailed = isSyncFailed;
+            [weakSelf didICloudSyncStatusChanged:model];
+            [weakSelf.models replaceObjectAtIndex:indexPath.item withObject:model];
+        };
     }
     
     cell.model = model;
@@ -493,6 +509,7 @@
         __strong typeof(weakSelf) strongSelf = weakSelf;
         [strongSelf didTapPreviewCell];
     }];
+
     return cell;
 }
 
@@ -563,7 +580,8 @@
         _originalPhotoLabel.hidden = YES;
         _doneButton.hidden = YES;
     }
-    
+    // iCloud同步失败的UI刷新
+    [self didICloudSyncStatusChanged:model];
     if (_tzImagePickerVc.photoPreviewPageDidRefreshStateBlock) {
         _tzImagePickerVc.photoPreviewPageDidRefreshStateBlock(_collectionView, _naviBar, _backButton, _selectButton, _indexLabel, _toolBar, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel);
     }
@@ -579,6 +597,25 @@
     });
 }
 
+- (void)didICloudSyncStatusChanged:(TZAssetModel *)model{
+    dispatch_async(dispatch_get_main_queue(), ^{
+        TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
+        // onlyReturnAsset为NO时,依赖TZ返回大图,所以需要有iCloud同步失败的提示,并且不能选择,
+        if (_tzImagePickerVc.onlyReturnAsset) {
+            return;
+        }
+        TZAssetModel *currentModel = self.models[self.currentIndex];
+        if (_tzImagePickerVc.selectedModels.count <= 0) {
+            self->_doneButton.enabled = !currentModel.iCloudFailed;
+        } else {
+            self->_doneButton.enabled = YES;
+        }
+        self->_selectButton.hidden = currentModel.iCloudFailed || !_tzImagePickerVc.showSelectBtn;
+        self->_originalPhotoButton.hidden = currentModel.iCloudFailed;
+        self->_originalPhotoLabel.hidden = currentModel.iCloudFailed;
+    });
+}
+
 - (void)showPhotoBytes {
     [[TZImageManager manager] getPhotosBytesWithArray:@[_models[self.currentIndex]] completion:^(NSString *totalBytes) {
         self->_originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes];

+ 24 - 0
MusicGradeExam/MusicGradeExam/ThirdPart/TZImagePickerController/TZVideoPlayerController.m

@@ -27,6 +27,8 @@
     UIStatusBarStyle _originStatusBarStyle;
 }
 @property (assign, nonatomic) BOOL needShowStatusBar;
+// iCloud无法同步提示UI
+@property (nonatomic, strong) UIView *iCloudErrorView;
 @end
 
 #pragma clang diagnostic push
@@ -62,6 +64,8 @@
 
 - (void)configMoviePlayer {
     [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
+        BOOL iCloudSyncFailed = !photo && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
+        self.iCloudErrorView.hidden = !iCloudSyncFailed;
         if (!isDegraded && photo) {
             self->_cover = photo;
             self->_doneButton.enabled = YES;
@@ -215,6 +219,26 @@
     }
 }
 
+#pragma mark - lazy
+- (UIView *)iCloudErrorView{
+    if (!_iCloudErrorView) {
+        _iCloudErrorView = [[UIView alloc] initWithFrame:CGRectMake(0, [TZCommonTools tz_isIPhoneX] ? 88 + 10 : 64 + 10, self.view.tz_width, 28)];
+        UIImageView *icloud = [[UIImageView alloc] init];
+        icloud.image = [UIImage tz_imageNamedFromMyBundle:@"iCloudError"];
+        icloud.frame = CGRectMake(20, 0, 28, 28);
+        [_iCloudErrorView addSubview:icloud];
+        UILabel *label = [[UILabel alloc] init];
+        label.frame = CGRectMake(53, 0, self.view.tz_width - 63, 28);
+        label.font = [UIFont systemFontOfSize:10];
+        label.textColor = [UIColor whiteColor];
+        label.text = [NSBundle tz_localizedStringForKey:@"iCloud sync failed"];
+        [_iCloudErrorView addSubview:label];
+        [self.view addSubview:_iCloudErrorView];
+        _iCloudErrorView.hidden = YES;
+    }
+    return _iCloudErrorView;
+}
+
 - (void)dealloc {
     [[NSNotificationCenter defaultCenter] removeObserver:self];
 }

+ 1 - 1
MusicGradeExam/MusicGradeExam/UI/Exam/Controller/WaitExamViewController.m

@@ -98,7 +98,7 @@
     }
 }
 
-// 试听课被挤掉
+// 被挤掉
 - (void)backLoginView {
     _cancleRequest = YES;
 }

+ 25 - 1
MusicGradeExam/MusicGradeExam/UI/Home/Controller/HomeViewController.m

@@ -18,6 +18,7 @@
 #import "ExamViewController.h"
 #import "ExamDisplayViewController.h"
 #import "UserInfoManager.h"
+#import "SimulationExamConfigController.h"
 
 @interface HomeViewController ()<TYCyclePagerViewDataSource,TYCyclePagerViewDelegate>
 
@@ -114,6 +115,7 @@
             }
         }
     }
+    [self refreshBodyFrame];
 }
 
 - (void)configIMConnection {
@@ -148,7 +150,7 @@
     self.scrollView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight - kTabBarHeight);
     _bodyView = [HomeBodyView shareInstance];
     CGFloat recordHeight = (kScreenWidth - 24) / 351 * 120;
-    CGFloat viewHeight = recordHeight * 3 + 45 + (kScreenWidth - 32) / 191 * 73 + 15 + iPhoneXSafeTopMargin + 83;
+    CGFloat viewHeight = recordHeight * 4 + 60 + (kScreenWidth - 32) / 191 * 73 + 15 + iPhoneXSafeTopMargin + 83;
     viewHeight = kScreenHeight - kTabBarHeight ? viewHeight : kScreenHeight - kTabBarHeight;
     _bodyView.frame = CGRectMake(0, 0, kScreenWidth, viewHeight);
     MJWeakSelf;
@@ -169,6 +171,22 @@
     }];
 }
 
+- (void)refreshBodyFrame {
+    CGFloat recordHeight = (kScreenWidth - 24) / 351 * 120;
+    CGFloat viewHeight = CGFLOAT_MIN;
+    if (self.bodyView.hasExam) {
+        viewHeight = recordHeight * 4 + 60 + (kScreenWidth - 32) / 191 * 73 + 15 + iPhoneXSafeTopMargin + 83;
+        viewHeight = kScreenHeight - kTabBarHeight ? viewHeight : kScreenHeight - kTabBarHeight;
+        _bodyView.frame = CGRectMake(0, 0, kScreenWidth, viewHeight);
+    }
+    else {
+        viewHeight = recordHeight * 4 + 60 + 15 + iPhoneXSafeTopMargin + 83;
+        viewHeight = kScreenHeight - kTabBarHeight ? viewHeight : kScreenHeight - kTabBarHeight;
+        _bodyView.frame = CGRectMake(0, 0, kScreenWidth, viewHeight);
+    }
+    [self.scrollView setContentSize:CGSizeMake(kScreenWidth, viewHeight)];
+}
+
 - (void)addPageView {
     [_bodyView.scollBgView addSubview:self.pagerView];
 }
@@ -191,6 +209,12 @@
             
         }
             break;
+        case HOMETYPE_SIMULATIONEXAM: // 模拟考试
+        {
+            SimulationExamConfigController *ctrl = [[SimulationExamConfigController alloc] init];
+            [self.navigationController pushViewController:ctrl animated:YES];
+        }
+            break;
         case HOMETYPE_EXAMRECORD: //考试记录
         {
             KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];

+ 20 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamConfigController.h

@@ -0,0 +1,20 @@
+//
+//  SimulationExamConfigController.h
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "KSBaseViewController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// 模拟考试设置页面
+@interface SimulationExamConfigController : KSBaseViewController
+
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 234 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamConfigController.m

@@ -0,0 +1,234 @@
+//
+//  SimulationExamConfigController.m
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "SimulationExamConfigController.h"
+#import "SimulationExamConfigView.h"
+#import "KSChoosePicker.h"
+#import "SimulationWaitExamController.h"
+#import "SimulationExamRecordController.h"
+
+@interface SimulationExamConfigController ()
+
+@property (nonatomic, strong) SimulationExamConfigView *bodyView;
+
+@property (nonatomic, strong) KSChoosePicker *choosePicker;
+
+@property (nonatomic, strong) NSString *examLevel;
+
+@property (nonatomic, strong) NSString *subjectName;
+
+@end
+
+@implementation SimulationExamConfigController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self allocTitle:@"选择专业"];
+    [self configUI];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
+    if(@available(iOS 13.0, *)){
+        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
+    }
+}
+
+- (void)configUI {
+    [self.view addSubview:self.bodyView];
+    NSString *subjectName = UserDefault(@"SimulationSubject");
+    if (![NSString isEmptyString:subjectName]) {
+        self.bodyView.subjectField.text = subjectName;
+        self.subjectName = subjectName;
+    }
+    NSString *examLevel = UserDefault(@"SimulationLevel");
+    if (![NSString isEmptyString:examLevel]) {
+        self.bodyView.levelField.text = examLevel;
+        self.examLevel = examLevel;
+    }
+}
+
+- (void)operationWithType:(SEXAMACTION)actionType {
+    switch (actionType) {
+        case SEXAMACTION_SUBJECT:  // 选择专业
+        {
+            MJWeakSelf;
+            self.choosePicker = [[KSChoosePicker alloc] initWithTitle:@"选择专业" sourceData:@[@"钢琴",@"萨克斯",@"长号",@"古筝",@"低音提琴",@"小鼓",@"架子鼓",@"扬琴",@"大提琴",@"单簧管",@"双簧管",@"小提琴",@"中提琴",@"长笛",@"大管",@"小号",@"笙",@"笛子",@"圆号",@"大号",@"上低音号",@"手风琴",@"古典吉他",@"中阮",@"琵琶",@"二胡",@"其他"] chooseReturnWithBlock:^(NSString * _Nonnull returnValue, NSInteger chooseIndex) {
+                weakSelf.subjectName = returnValue;
+                weakSelf.bodyView.subjectField.text = returnValue;
+                UserDefaultSet(returnValue, @"SimulationSubject");
+            }];
+            [self.choosePicker showPicker];
+        }
+            break;
+        case SEXAMACTION_LEVEL:    // 选择级别
+        {
+            MJWeakSelf;
+            self.choosePicker = [[KSChoosePicker alloc] initWithTitle:@"选择级别" sourceData:@[@"壹级",@"贰级",@"叁级",@"肆级",@"伍级",@"陆级",@"柒级",@"捌级",@"玖级",@"拾级"] chooseReturnWithBlock:^(NSString * _Nonnull returnValue, NSInteger chooseIndex) {
+                weakSelf.examLevel = returnValue;
+                weakSelf.bodyView.levelField.text = returnValue;
+                UserDefaultSet(returnValue, @"SimulationLevel");
+            }];
+            [self.choosePicker showPicker];
+        }
+            break;
+        case SEXAMACTION_ONLINE:   // 模拟线上考试进入待考页面
+        {
+            [self configOnlineExamMessage];
+        }
+            break;
+        case SEXAMACTION_RECORD:   // 模拟录播考试
+        {
+            [self configRecordExamMessage];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)configOnlineExamMessage {
+    if ([NSString isEmptyString:self.subjectName]) {
+        [self MBPShow:@"请选择专业"];
+    }
+    if ([NSString isEmptyString:self.examLevel]) {
+        [self MBPShow:@"请选择考试级别"];
+        return;
+    }
+    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+    dateFormatter.timeZone = [NSTimeZone systemTimeZone];
+    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
+    NSDate *curDate = [NSDate date];
+    NSString *beginDay = [dateFormatter stringFromDate:curDate];
+    NSString *beginDateStr = [NSString stringWithFormat:@"%@ 08:00:00",beginDay];
+    NSString *endDateStr = [NSString stringWithFormat:@"%@ 20:00:00", beginDay];
+    TicketDetailModel *model = [[TicketDetailModel alloc] init];
+    model.subjectName = self.subjectName;
+    model.level = [self getLevelByName:self.examLevel];
+    model.finishedExam = 3;
+    model.openFlag = 1;
+    model.desc = @"1. 保证设备电量充足,提前准备好乐器,谱架,演奏资料。注意考核时段及提醒消息,及时进入考场,完成考试。\n\n2. 考生务必遵守考试纪律,独立完成,考试期间全程打开视频和语音,确保处于安静无噪音的环境,若出现非考生的演奏、提示等声音,则考试成绩作废。\n\n3. 若考试过程中,出现设备断电,网络中断,音视频中断等异常状况,请重新打开App,并于1分钟内重新登录后继续考试。";
+    model.recordFlag = 0;
+    model.waitNum = 3;
+    model.recordMinutes = 5.0f;
+    model.examStartTime = beginDateStr;
+    model.examEndTime = endDateStr;
+    model.baseExamName = @"直播模拟考试";
+    SimulationWaitExamController *waitCtrl = [[SimulationWaitExamController alloc] init];
+
+    // 生成考试id
+    NSString *examRegistrationId = [NSString stringWithFormat:@"S%@", UserDefault(UIDKey)];
+    waitCtrl.examRegistrationId = examRegistrationId;
+    waitCtrl.sourceModel = model;
+    [self.navigationController pushViewController:waitCtrl animated:YES];
+}
+
+
+- (void)configRecordExamMessage {
+    if ([NSString isEmptyString:self.subjectName]) {
+        [self MBPShow:@"请选择专业"];
+    }
+    if ([NSString isEmptyString:self.examLevel]) {
+        [self MBPShow:@"请选择考试级别"];
+        return;
+    }
+    NSString *recordEndTime = UserDefault(@"SimulationRecordEndTime");
+    // 计算时间是否超时
+    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+    dateFormatter.timeZone = [NSTimeZone systemTimeZone];
+    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+    NSDate *curDate = [NSDate date];
+    NSDate *recordEndDate = [dateFormatter dateFromString:recordEndTime];
+    NSTimeInterval timeInterval = [recordEndDate timeIntervalSinceDate:curDate];
+    NSTimeInterval subTime = 0.0f;
+    if (![NSString isEmptyString:recordEndTime] && timeInterval > 0) {
+        subTime = timeInterval;
+    }
+    else {
+        recordEndDate = [NSDate dateWithTimeInterval:1200.0f sinceDate:curDate];
+        recordEndTime = [dateFormatter stringFromDate:recordEndDate];
+        UserDefaultSet(recordEndTime, @"SimulationRecordEndTime");
+        subTime = 1200.0f;
+    }
+    NSString *examRegistrationId = [NSString stringWithFormat:@"S%@", UserDefault(UIDKey)];
+
+    RecordExamModel *model = [[RecordExamModel alloc] init];
+    model.singleSongRecordMinutes = 5.0f;
+    model.subTime = subTime;
+    model.examEndTime = recordEndTime;
+    model.songJson = @"[{\"index\":1,\"type\":\"PRACTICE\",\"songName\":\"曲目1\",\"songAuthor\":\"聂耳\",\"uploadUrl\":\"\"},{\"index\":2,\"type\":\"PRACTICE\",\"songName\":\"曲目2\",\"songAuthor\":\"小星\",\"uploadUrl\":\"\"}]";
+    
+    // 生成考试id
+    SimulationExamRecordController *ctrl = [[SimulationExamRecordController alloc] init];
+    ctrl.examRegistrationId = examRegistrationId;
+    ctrl.sourceModel = model;
+    [self.navigationController pushViewController:ctrl animated:YES];
+}
+
+
+- (SimulationExamConfigView *)bodyView {
+    if (!_bodyView) {
+        _bodyView = [SimulationExamConfigView shareInstance];
+        _bodyView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight - kNaviBarHeight - iPhoneXSafeBottomMargin);
+        MJWeakSelf;
+        [_bodyView simulationExamAction:^(SEXAMACTION action) {
+            [weakSelf operationWithType:action];
+        }];
+    }
+    return _bodyView;
+}
+
+- (NSInteger)getLevelByName:(NSString *)levelStr {
+    if ([levelStr isEqualToString:@"壹级"]) {
+        return 1;
+    }
+    else if ([levelStr isEqualToString:@"贰级"]) {
+        return 2;
+    }
+    else if ([levelStr isEqualToString:@"叁级"]) {
+        return 3;
+    }
+    else if ([levelStr isEqualToString:@"肆级"]) {
+        return 4;
+    }
+    else if ([levelStr isEqualToString:@"伍级"]) {
+        return 5;
+    }
+    else if ([levelStr isEqualToString:@"陆级"]) {
+        return 6;
+    }
+    else if ([levelStr isEqualToString:@"柒级"]) {
+        return 7;
+    }
+    else if ([levelStr isEqualToString:@"捌级"]) {
+        return 8;
+    }
+    else if ([levelStr isEqualToString:@"玖级"]) {
+        return 9;
+    }
+    else if ([levelStr isEqualToString:@"拾级"]) {
+        return 10;
+    }
+    else {
+        return 0;
+    }
+}
+
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 22 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamRecordController.h

@@ -0,0 +1,22 @@
+//
+//  SimulationExamRecordController.h
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "KSBaseViewController.h"
+#import "RecordExamModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SimulationExamRecordController : KSBaseViewController
+
+@property (nonatomic, strong) NSString *examRegistrationId;
+
+@property (nonatomic, strong) RecordExamModel *sourceModel;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 432 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationExamRecordController.m

@@ -0,0 +1,432 @@
+//
+//  SimulationExamRecordController.m
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "SimulationExamRecordController.h"
+#import "RecordBodyView.h"
+#import "RecordListCell.h"
+#import "RecordBottomView.h"
+#import "RecordTipsView.h"
+#import "KSMediaManager.h"
+#import "WMPlayer.h"
+#import "SongModel.h"
+#import "KSGuideMaskView.h"
+#import "KSNormalAlertView.h"
+
+@interface SimulationExamRecordController ()<UITableViewDelegate, UITableViewDataSource,WMPlayerDelegate>
+{
+    WMPlayer *_wmPlayer;
+    CGRect _playerFrame;
+}
+@property (nonatomic, assign) BOOL isRatation;
+
+@property (nonatomic, strong) UIView *bgView;
+
+@property (nonatomic, strong) RecordBodyView *topView;
+
+@property (nonatomic, strong) RecordTipsView *tipsView;
+
+@property (nonatomic, strong) UITableView *tableView;
+
+@property (nonatomic, strong) RecordBottomView *bottomView;
+
+@property (nonatomic, strong) NSMutableArray *songArray;
+
+@property (nonatomic, strong) KSMediaManager *mediaManager;
+
+@property (strong, nonatomic) MBProgressHUD *HUD;
+
+@property (nonatomic, strong) NSMutableArray *fileUrlArray;
+
+@property (nonatomic, assign) BOOL hasShowTips;
+
+@end
+
+@implementation SimulationExamRecordController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.ks_prefersNavigationBarHidden = YES;
+    [self configUI];
+    [self evaluateSource];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
+    
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+    [super viewDidDisappear:animated];
+    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
+    if(@available(iOS 13.0, *)){
+        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
+    }
+}
+
+- (void)evaluateSource {
+    if (self.sourceModel == nil) {
+        return;
+    }
+    [self.topView configTime:[NSString stringWithFormat:@"%.0f", self.sourceModel.subTime]];
+    [self.tipsView configWithEndTime:self.sourceModel.examEndTime];
+    NSData *songDate = [self.sourceModel.songJson dataUsingEncoding:NSUTF8StringEncoding];
+    NSArray *listArray = [NSJSONSerialization JSONObjectWithData:songDate options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:nil];
+    NSMutableArray *songList = [NSMutableArray array];
+    for (NSDictionary *parm in listArray) {
+        SongModel *model = [[SongModel alloc] initWithDictionary:parm];
+        [songList addObject:model];
+    }
+    self.songArray = [NSMutableArray arrayWithArray:songList];
+    
+    for (NSInteger i = 0; i < self.songArray.count; i++) {
+        SongModel *model = self.songArray[i];
+        NSString *fileKey = [NSString stringWithFormat:@"%@%@", self.examRegistrationId, model.songName];
+        NSDictionary *fileMessage = UserDefault(fileKey);
+        if (fileMessage) {
+            NSString *remoteUrl = [fileMessage stringValueForKey:@"remoteUrl"];
+            [self.fileUrlArray addObject:remoteUrl];
+        }
+    }
+    [self checkSubmitButtonEnable];
+    [self.tableView reloadData];
+}
+
+- (void)configUI {
+    
+    [self.view addSubview:self.topView];
+    [self.topView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.left.right.mas_equalTo(self.view);
+        make.height.mas_equalTo(self.view.mas_width).multipliedBy(79.0 / 207).offset(11);
+    }];
+    [self.view addSubview:self.bottomView];
+    [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.bottom.mas_equalTo(self.view.mas_bottomMargin);
+        make.height.mas_equalTo(90);
+    }];
+    
+    [self.view addSubview:self.tableView];
+    [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.top.mas_equalTo(self.topView.mas_bottom);
+        make.bottom.mas_equalTo(self.bottomView.mas_top);
+    }];
+}
+
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    if (_hasShowTips == NO) {
+        [self addIntroduceView];
+    }
+}
+
+- (void)addIntroduceView {
+    _hasShowTips = YES;
+    CGRect rect1 = [self.tableView convertRect:self.tableView.tableHeaderView.frame toView:[UIApplication sharedApplication].keyWindow];
+    rect1.origin.y -= 50;
+    rect1.size.height += 50;
+    UIBezierPath *pathOne = [UIBezierPath bezierPathWithRect:rect1];
+    
+    CGRect rect2 = rect1;
+    rect2.size = CGSizeMake(kScreenWidth, 130);
+    rect2.origin.y = CGRectGetMaxY(rect1);
+    UIBezierPath *pathSecond = [UIBezierPath bezierPathWithRect:rect2];
+    NSArray *tipsArray = @[@"请在录播时间内完成视频上传", @"点击上传曲目录播视频"];
+    NSArray *bezierArray = @[pathOne,pathSecond];
+    
+    KSGuideMaskView *guideView = [[KSGuideMaskView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
+    [guideView addTips:tipsArray transparentRect:bezierArray shaperLayerIndex:-1];
+    [guideView showMaskViewInView:nil];
+}
+
+#pragma mark ----- table data source
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.songArray.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    SongModel *model = self.songArray[indexPath.row];
+    RecordListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RecordListCell"];
+    MJWeakSelf;
+    [cell configCellWithSource:model examRegistrationId:self.examRegistrationId operationCallback:^(RECORDTYPE type, NSString *fileKey) {
+        [weakSelf opreationCellType:type fileKey:fileKey];
+    }];
+    return cell;
+}
+
+- (void)opreationCellType:(RECORDTYPE)type fileKey:(NSString *)fileKey {
+    if (type == RECORDTYPE_RECORD) { // 录像
+        self.mediaManager = [[KSMediaManager alloc] init];
+        self.mediaManager.mediaType = MEDIATYPE_VIDEO;
+        self.mediaManager.maxPhotoNumber = 1;
+        self.mediaManager.baseCtrl = self;
+        self.mediaManager.maxDuration = self.sourceModel.singleSongRecordMinutes * 60;
+        MJWeakSelf;
+        [self.mediaManager noAlertCallback:^(NSString * _Nullable videoUrl, NSMutableArray * _Nullable imageArray, NSMutableArray * _Nullable imageAsset) {
+            NSLog(@"%@", videoUrl);
+            // 不上传回调
+            [weakSelf refreshView:videoUrl fileKey:fileKey];
+        }];
+        [self.mediaManager takePhoto];
+    }
+    else { // 删除
+        [self deleteFileWithKey:fileKey];
+    }
+}
+
+
+- (void)refreshView:(NSString *)videoUrl fileKey:(NSString *)fileKey {
+    NSString *fileUrl = videoUrl;
+    NSString *fileName = [[videoUrl componentsSeparatedByString:@"/"] lastObject];
+    // 保存文件路径
+    NSDictionary *parm = @{@"localFileUrl":videoUrl,
+                           @"fileName": fileName};
+    UserDefaultSet(parm, fileKey);
+    [self.tableView reloadData];
+    
+    [self.fileUrlArray addObject:fileUrl];
+    [self checkSubmitButtonEnable];
+}
+
+- (void)deleteFileWithKey:(NSString *)fileKey {
+    NSDictionary *parm = UserDefault(fileKey);
+    NSString *localUrl = [parm stringValueForKey:@"localFileUrl"];
+    [self removeVideoWithPath:localUrl];
+    UserDefaultRemoveObjectForKey(fileKey);
+    [self.fileUrlArray removeObject:localUrl];
+    [self checkSubmitButtonEnable];
+    [self.tableView reloadData];
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    RecordListCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+    if (cell.fileMessage) {
+        // 播放
+        NSString *localUrl = [cell.fileMessage stringValueForKey:@"localFileUrl"];
+        if ([[NSFileManager defaultManager] fileExistsAtPath:localUrl]) {
+            [self playVideoWithUrl:[NSURL fileURLWithPath:localUrl]];
+        }
+        else {
+            NSString *remoteUrl = [cell.fileMessage stringValueForKey:@"remoteUrl"];
+            [self playVideoWithUrl:[NSURL URLWithString:remoteUrl]];
+        }
+    }
+}
+
+
+- (void)checkSubmitButtonEnable {
+    if (self.fileUrlArray.count == 0) {
+        self.bottomView.finishButton.userInteractionEnabled = NO;
+        [self.bottomView.finishButton setBackgroundImage:[UIImage imageNamed:@"button_unable"] forState:UIControlStateNormal];
+    }
+    else {
+        self.bottomView.finishButton.userInteractionEnabled = YES;
+        [self.bottomView.finishButton setBackgroundImage:[UIImage imageNamed:@"button_nomal"] forState:UIControlStateNormal];
+        [self.bottomView.finishButton setBackgroundImage:[UIImage imageNamed:@"button_highlight"] forState:UIControlStateHighlighted];
+    }
+}
+
+
+#pragma mark --- lazying
+- (RecordBodyView *)topView {
+    if (!_topView) {
+        _topView = [RecordBodyView shareInstance];
+        
+        MJWeakSelf;
+        [_topView topviewAction:^(RECORDTOPACTION action) {
+            [weakSelf backOrEndAction:action];
+        }];
+    }
+    return _topView;
+}
+
+
+- (void)backOrEndAction:(RECORDTOPACTION)action {
+    if (action == RECORDTOPACTION_BACK) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }
+    else { // 时间结束
+        MJWeakSelf;
+        if (self.fileUrlArray.count == 0) {
+            [self KSShowMsg:@"考试结束" promptCompletion:^{
+                [weakSelf.navigationController popViewControllerAnimated:YES];
+            }];
+        }
+        else {
+            [KSNormalAlertView ks_showAlertWithTitle:@"考试时间已结束,是否提交?" leftTitle:@"取消" rightTitle:@"确定" cancel:^{
+                [weakSelf removeAllFile];
+                [weakSelf.navigationController popViewControllerAnimated:YES];
+            } confirm:^{
+                [weakSelf submitService];
+            }];
+        }
+    }
+}
+
+- (RecordTipsView *)tipsView {
+    if (!_tipsView) {
+        _tipsView = [RecordTipsView shareInstance];
+    }
+    return _tipsView;
+}
+
+- (UITableView *)tableView {
+    if (!_tableView) {
+        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
+        _tableView.delegate = self;
+        _tableView.dataSource = self;
+        _tableView.rowHeight = 130;
+        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        _tableView.backgroundColor = HexRGB(0xf5f5f5);
+        _tableView.showsVerticalScrollIndicator = NO;
+        [_tableView registerNib:[UINib nibWithNibName:@"RecordListCell" bundle:nil] forCellReuseIdentifier:@"RecordListCell"];
+        _tableView.tableHeaderView = self.tipsView;
+        
+        UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 10)];
+        bottomView.backgroundColor = HexRGB(0xf3f4f8);
+        _tableView.tableFooterView = bottomView;
+    }
+    return _tableView;
+}
+
+- (RecordBottomView *)bottomView {
+    if (!_bottomView) {
+        _bottomView = [RecordBottomView shareInstance];
+        _topView.topTitleLabel.text = @"录播模拟考试";
+        MJWeakSelf;
+        [_bottomView submitMediaAction:^{
+            [weakSelf submitAction];
+        }];
+    }
+    return _bottomView;
+}
+
+- (void)submitAction {
+    
+    // 是否确认提交
+    MJWeakSelf;
+    [KSNormalAlertView ks_showAlertWithTitle:@"请确认已上传所有录播曲目" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
+        
+    } confirm:^{
+        [weakSelf submitService];
+    }];
+    
+}
+
+// 完成考试
+- (void)submitService {
+    [self removeAllFile];
+    
+    MJWeakSelf;
+    [self KSShowMsg:@"提交成功" promptCompletion:^{
+        // 移除所有缓存
+        UserDefaultRemoveObjectForKey(@"SimulationRecordEndTime");
+        [weakSelf.topView stopDurationTimer];
+        [weakSelf.navigationController popViewControllerAnimated:YES];
+    }];
+}
+
+- (void)removeAllFile {
+    for (NSInteger i = 0; i < self.songArray.count; i++) {
+        SongModel *model = self.songArray[i];
+        NSString *fileKey = [NSString stringWithFormat:@"%@%@", self.examRegistrationId, model.songName];
+        NSDictionary *fileMessage = UserDefault(fileKey);
+        if (fileMessage) {
+            NSString *localUrl = [fileMessage stringValueForKey:@"localFileUrl"];
+            UserDefaultRemoveObjectForKey(fileKey);
+            [self removeVideoWithPath:localUrl];
+            [self.fileUrlArray removeObject:localUrl];
+        }
+    }
+}
+
+- (void)removeVideoWithPath:(NSString *)videoUrl {
+    NSFileManager *fileMamager = [NSFileManager defaultManager];
+    if ([fileMamager fileExistsAtPath:videoUrl]) {
+        [fileMamager removeItemAtPath:videoUrl error:nil];
+    }
+}
+
+
+- (NSMutableArray *)fileUrlArray {
+    if (!_fileUrlArray) {
+        _fileUrlArray = [NSMutableArray arrayWithCapacity:self.songArray.count];
+    }
+    return _fileUrlArray;
+}
+
+#pragma mark ------- 播放文件
+- (void)playVideoWithUrl:(NSURL *)fileUrl {
+    _playerFrame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
+    _wmPlayer = [[WMPlayer alloc] initWithFrame:_playerFrame];
+    WMPlayerModel *playModel = [[WMPlayerModel alloc] init];
+    playModel.videoURL = fileUrl;
+    _wmPlayer.playerModel = playModel;
+    _wmPlayer.delegate = self;
+    _bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
+    _bgView.backgroundColor = [UIColor blackColor];
+    [[UIApplication sharedApplication].keyWindow addSubview:_bgView];
+    [[UIApplication sharedApplication].keyWindow addSubview:_wmPlayer];
+    [[UIApplication sharedApplication].keyWindow bringSubviewToFront:_wmPlayer];
+    
+    [_wmPlayer play];
+}
+
+- (void)wmplayer:(WMPlayer *)wmplayer clickedCloseButton:(UIButton *)backBtn {
+    [wmplayer removePlayer];
+    [_bgView removeFromSuperview];
+    [self setNeedsStatusBarAppearanceUpdate];
+}
+
+- (void)wmplayer:(WMPlayer *)wmplayer clickedFullScreenButton:(UIButton *)fullScreenBtn {
+    self.isRatation = !self.isRatation;
+    
+    if (self.isRatation) {
+        [wmplayer removeFromSuperview];
+        [UIView animateWithDuration:1.0f animations:^{
+            wmplayer.transform = CGAffineTransformMakeRotation(M_PI_2);
+            
+        } completion:^(BOOL finished) {
+            wmplayer.frame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
+            [[UIApplication sharedApplication].keyWindow addSubview:wmplayer];
+            [[UIApplication sharedApplication].keyWindow bringSubviewToFront:wmplayer];
+        }];
+    }
+    else {
+        [wmplayer removeFromSuperview];
+        
+        [UIView animateWithDuration:1.0f animations:^{
+            //        复原
+            wmplayer.transform = CGAffineTransformIdentity;
+            
+        } completion:^(BOOL finished) {
+            wmplayer.frame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
+            [[UIApplication sharedApplication].keyWindow addSubview:wmplayer];
+            [[UIApplication sharedApplication].keyWindow bringSubviewToFront:wmplayer];
+        }];
+    }
+}
+- (void)dealloc {
+    [self.topView stopDurationTimer];
+}
+
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 23 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationWaitExamController.h

@@ -0,0 +1,23 @@
+//
+//  SimulationWaitExamController.h
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "KSBaseViewController.h"
+#import "TicketDetailModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// 模拟待考区
+@interface SimulationWaitExamController : KSBaseViewController
+
+@property (nonatomic, strong) NSString *examRegistrationId;
+
+@property (nonatomic, strong) TicketDetailModel *sourceModel;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 289 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/Controller/SimulationWaitExamController.m

@@ -0,0 +1,289 @@
+//
+//  SimulationWaitExamController.m
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "SimulationWaitExamController.h"
+#import "WaitExamBodyView.h"
+#import "OnlineRoomManager.h"
+#import "ExamGuideViewController.h"
+#import "KSGuideMaskView.h"
+#import "UserInfoManager.h"
+#import "WaitExamBottomView.h"
+#import "AppDelegate.h"
+
+#define  BOTTOMVIEW_HEIGHT (150)
+
+@interface SimulationWaitExamController ()<UIScrollViewDelegate>
+
+@property (nonatomic, strong) WaitExamBodyView *bodyView;
+
+
+@property (nonatomic, strong) OnlineRoomManager *classManager;
+
+@property (nonatomic, assign) BOOL cancleRequest;
+
+@property (nonatomic, strong) WaitExamBottomView *bottomView;
+
+@property (nonatomic, assign) BOOL hasShowTopTips;
+
+@property (nonatomic, assign) BOOL hasShowBottomTips;
+
+@end
+
+@implementation SimulationWaitExamController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self allocTitle:@"直播模拟考试"];
+    self.view.backgroundColor = HexRGB(0xf3f4f8);
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backLoginView) name:@"backLoginView" object:nil];
+    [self configUI];
+    self.sourceModel.desc = [self.sourceModel.desc replaceAll:@"\\n" WithString:@"\n"];
+    [self evaluateSource];
+}
+
+// 被挤掉
+- (void)backLoginView {
+    _cancleRequest = YES;
+}
+
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
+    if(@available(iOS 13.0, *)){
+        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
+    }
+    if (_cancleRequest) {
+        _cancleRequest = NO;
+        [KSRequestManager logoutAction];
+        return;
+    }
+    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    if (_hasShowTopTips == NO) {
+        [self addIntroduceView];
+    }
+}
+
+- (void)addIntroduceView {
+    _hasShowTopTips = YES;
+    CGRect rect1 = [self.bodyView convertRect:self.bodyView.signButton.frame toView:[UIApplication sharedApplication].keyWindow];
+    rect1.origin.y += 8;
+    rect1.origin.x += 8;
+    rect1.size.width -= 16;
+    rect1.size.height -= 16;
+    
+    UIBezierPath *pathOne = [UIBezierPath bezierPathWithOvalInRect:rect1];
+    CGRect rect2 = [self.bodyView convertRect:self.bodyView.examMessageView.frame toView:[UIApplication sharedApplication].keyWindow];
+    UIBezierPath *pathSecond = [UIBezierPath bezierPathWithRect:rect2];
+    
+    CGFloat height = CGRectGetHeight(self.bodyView.frame);
+    NSArray *tipsArray = @[@"考场开启后,才可已进行签到,签到后排考", @"这是您的考试信息"];
+    NSArray *bezierArray = @[pathOne,pathSecond];
+    if (height == kScreenHeight - kTabBarHeight - iPhoneXSafeBottomMargin - BOTTOMVIEW_HEIGHT) {
+        CGRect rect3 = [self.bodyView convertRect:self.bodyView.tipsView.frame toView:[UIApplication sharedApplication].keyWindow];
+        UIBezierPath *pathThree = [UIBezierPath bezierPathWithRect:rect3];
+        tipsArray = @[@"考场开启后,才可已进行签到,签到后排考", @"这是您的考试信息",@"请认真阅读考试注意事项"];
+        bezierArray = @[pathOne,pathSecond,pathThree];
+    }
+    
+    KSGuideMaskView *guideView = [[KSGuideMaskView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
+    [guideView addTips:tipsArray transparentRect:bezierArray shaperLayerIndex:0];
+    if (tipsArray.count == 2) {
+        [guideView completeCallback:^{
+            [self scrollToBottom];
+        }];
+    }
+    [guideView showMaskViewInView:nil];
+}
+
+
+- (void)showBottomTips {
+    _hasShowBottomTips = YES;
+    NSArray *tipsArray = @[@"请认真阅读考试注意事项"];
+    CGRect rect3 = [self.bodyView convertRect:self.bodyView.tipsView.frame toView:[UIApplication sharedApplication].keyWindow];
+    UIBezierPath *pathThree = [UIBezierPath bezierPathWithRect:rect3];
+    NSArray *bezierArray = @[pathThree];
+    KSGuideMaskView *guideView = [[KSGuideMaskView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
+    [guideView addTips:tipsArray transparentRect:bezierArray shaperLayerIndex:-1];
+    [guideView showMaskViewInView:nil];
+}
+
+- (void)evaluateSource {
+    [self.bodyView configMessageSource:self.sourceModel];
+    [self.bottomView configMessageSource:self.sourceModel];
+    [self configViewHeight];
+    
+    if (USER_MANAGER.needConnect == NO) {
+        if (![NSString isEmptyString:self.sourceModel.examStartTime]) {
+            NSString *examDay = [[self.sourceModel.examStartTime componentsSeparatedByString:@" "] firstObject];
+            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+            [formatter setDateFormat:@"yyyy-MM-dd"];
+            formatter.timeZone = [NSTimeZone systemTimeZone];
+            NSDate *currentDate = [NSDate date];
+            NSString *currentDay = [formatter stringFromDate:currentDate];
+            if ([examDay isEqualToString:currentDay]) { // 如果今天有考试,IM建立连接
+                [self configIMConnection];
+            }
+        }
+    }
+}
+
+- (void)configIMConnection {
+    [USER_MANAGER connectRongCloud];
+    USER_MANAGER.needConnect = YES;
+}
+
+- (void)configViewHeight {
+    CGFloat tipsHeight = [self.bodyView configTipsHeight:self.sourceModel.desc];
+    CGFloat viewHeight = 206 + 200 + 19 + tipsHeight + 15;
+    viewHeight = viewHeight > kScreenHeight - kTabBarHeight - iPhoneXSafeBottomMargin ? viewHeight : kScreenHeight - kTabBarHeight - iPhoneXSafeBottomMargin;
+    self.bodyView.frame = CGRectMake(0, 0, kScreenWidth, viewHeight);
+    [self.scrollView setContentSize:CGSizeMake(kScreenWidth, viewHeight)];
+}
+
+- (void)configUI {
+    self.scrollView.backgroundColor = HexRGB(0xf3f4f8);
+    self.scrollView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight - kTabBarHeight - iPhoneXSafeBottomMargin - BOTTOMVIEW_HEIGHT);
+    self.scrollView.delegate = self;
+    self.scrollView.bounces = NO;
+    _bodyView = [WaitExamBodyView shareInstance];
+    CGFloat viewHeight = 206 + 200 + 19 + 204 + 15;
+    viewHeight = viewHeight > kScreenHeight - kTabBarHeight - iPhoneXSafeBottomMargin - BOTTOMVIEW_HEIGHT ? viewHeight : kScreenHeight - kTabBarHeight - iPhoneXSafeBottomMargin - BOTTOMVIEW_HEIGHT;
+    _bodyView.frame = CGRectMake(0, 0, kScreenWidth, viewHeight);
+    MJWeakSelf;
+    [_bodyView operationCallback:^(JOINROOMACTION action, TicketDetailModel * _Nullable source) {
+        [weakSelf opreationAction:action source:source];
+    }];
+    [self.scrollView addSubview:_bodyView];
+    [self.scrollView setContentSize:CGSizeMake(kScreenWidth, viewHeight)];
+    
+    _bottomView = [WaitExamBottomView shareInstance];
+    _bottomView.frame = CGRectMake(0, CGRectGetMaxY(self.scrollView.frame), kScreenWidth, BOTTOMVIEW_HEIGHT);
+    [_bottomView operationCallback:^(JOINROOMACTION action, TicketDetailModel * _Nullable source) {
+        [weakSelf opreationAction:action source:source];
+    }];
+    [self.view addSubview:_bottomView];
+}
+
+- (void)opreationAction:(JOINROOMACTION)action source:(TicketDetailModel *)source {
+    switch (action) {
+        case JOINROOMACTION_SIGN:  // 签到
+        {
+            [self signAction];
+        }
+            break;
+        case JOINROOMACTION_GUIDE: // 引导页
+        {
+            ExamGuideViewController *guideVC = [[ExamGuideViewController alloc] init];
+            [self.navigationController pushViewController:guideVC animated:YES];
+        }
+            break;
+        case JOINROOMACTION_JOIN:  // 加入房间
+        {
+            if (self.sourceModel.classroomSwitch == 1) {
+                NSString *roomId = [NSString stringWithFormat:@"%.0f", source.examRegistrationId];
+                [self joinRoomAction:roomId];
+            }
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+
+#pragma mark ----- 签到
+- (void)signAction {
+    MJWeakSelf;
+    [self KSShowMsg:@"签到成功" promptCompletion:^{
+        weakSelf.sourceModel.finishedExam = 2;
+        weakSelf.sourceModel.signInTime = @"2020-09-22 18:00:00";
+        // 滑动到底部
+        [weakSelf scrollToBottom];
+        // 开始排队
+        [weakSelf evaluateSource];
+        [weakSelf countWaitList];
+    }];
+}
+
+// 开启定时器
+- (void)countWaitList {
+    
+}
+ 
+
+- (void)scrollToBottom {
+    CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height);
+    [self.scrollView setContentOffset:bottomOffset animated:YES];
+}
+
+#pragma mark ----- 加入房间
+- (void)joinRoomAction:(NSString *)roomId {
+    [self.classManager joinRoomWithId:roomId subjectName:self.sourceModel.subjectName inViewController:self];
+}
+
+- (OnlineRoomManager *)classManager {
+    if (!_classManager) {
+        _classManager = [[OnlineRoomManager alloc] init];
+    }
+    return _classManager;
+}
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
+    CGPoint offset = scrollView.contentOffset;
+    CGRect bounds = scrollView.bounds;
+    CGSize size = scrollView.contentSize;
+    UIEdgeInsets inset = scrollView.contentInset;
+    CGFloat currentOffset = offset.y + bounds.size.height - inset.bottom;
+    CGFloat maximumOffset = size.height;
+    if((maximumOffset - currentOffset) < 40.0) {
+        if (_hasShowBottomTips == NO) {
+            [self showBottomTips];
+        }
+    }
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+    CGPoint offset = scrollView.contentOffset;
+    CGRect bounds = scrollView.bounds;
+    CGSize size = scrollView.contentSize;
+    UIEdgeInsets inset = scrollView.contentInset;
+    CGFloat currentOffset = offset.y + bounds.size.height - inset.bottom;
+    CGFloat maximumOffset = size.height;
+    if((maximumOffset - currentOffset) < 40.0) {
+        if (_hasShowBottomTips == NO) {
+            [self showBottomTips];
+        }
+    }
+}
+
+
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 34 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/View/SimulationExamConfigView.h

@@ -0,0 +1,34 @@
+//
+//  SimulationExamConfigView.h
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, SEXAMACTION) {
+    SEXAMACTION_SUBJECT,  // 选择专业
+    SEXAMACTION_LEVEL,    // 级别
+    SEXAMACTION_ONLINE,   // 线上考试模拟
+    SEXAMACTION_RECORD,   // 录播考试模拟
+};
+
+typedef void(^SExamActionCallback)(SEXAMACTION action);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SimulationExamConfigView : UIView
+
+@property (weak, nonatomic) IBOutlet UITextField *subjectField;
+@property (weak, nonatomic) IBOutlet UITextField *levelField;
+
+
++ (instancetype)shareInstance;
+
+- (void)simulationExamAction:(SExamActionCallback)action;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 62 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/View/SimulationExamConfigView.m

@@ -0,0 +1,62 @@
+//
+//  SimulationExamConfigView.m
+//  MusicGradeExam
+//
+//  Created by Kyle on 2020/9/21.
+//  Copyright © 2020 DayaMusic. All rights reserved.
+//
+
+#import "SimulationExamConfigView.h"
+
+@interface SimulationExamConfigView ()
+
+@property (nonatomic, copy) SExamActionCallback callback;
+
+@end
+
+@implementation SimulationExamConfigView
+
++ (instancetype)shareInstance {
+    SimulationExamConfigView *view = [[[NSBundle mainBundle] loadNibNamed:@"SimulationExamConfigView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)simulationExamAction:(SExamActionCallback)action {
+    if (action) {
+        self.callback = action;
+    }
+}
+- (IBAction)chooseSubject:(id)sender {
+    if (self.callback) {
+        self.callback(SEXAMACTION_SUBJECT);
+    }
+}
+
+- (IBAction)chooseLevel:(id)sender {
+    if (self.callback) {
+        self.callback(SEXAMACTION_LEVEL);
+    }
+}
+
+- (IBAction)onlineExam:(id)sender {
+    if (self.callback) {
+        self.callback(SEXAMACTION_ONLINE);
+    }
+}
+
+
+- (IBAction)recordExam:(id)sender {
+    if (self.callback) {
+        self.callback(SEXAMACTION_RECORD);
+    }
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 176 - 0
MusicGradeExam/MusicGradeExam/UI/Home/SimulationExam/View/SimulationExamConfigView.xib

@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="SimulationExamConfigView">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="630"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Mcu-Nu-uJo">
+                    <rect key="frame" x="0.0" y="1" width="414" height="50"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="选择专业" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D48-yN-5zP">
+                            <rect key="frame" x="16" y="14.5" width="70" height="21"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <textField opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请选择模拟专业" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="OTA-uH-vx9">
+                            <rect key="frame" x="245.5" y="14" width="121.5" height="22"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                            <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="mine_next" translatesAutoresizingMaskIntoConstraints="NO" id="vft-5c-lKn">
+                            <rect key="frame" x="377" y="14" width="22" height="22"/>
+                        </imageView>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <gestureRecognizers/>
+                    <constraints>
+                        <constraint firstItem="D48-yN-5zP" firstAttribute="leading" secondItem="Mcu-Nu-uJo" secondAttribute="leading" constant="16" id="1tn-Fc-lY1"/>
+                        <constraint firstAttribute="trailing" secondItem="vft-5c-lKn" secondAttribute="trailing" constant="15" id="9iB-cp-fx6"/>
+                        <constraint firstItem="OTA-uH-vx9" firstAttribute="centerY" secondItem="Mcu-Nu-uJo" secondAttribute="centerY" id="EJb-8F-qB3"/>
+                        <constraint firstItem="D48-yN-5zP" firstAttribute="centerY" secondItem="Mcu-Nu-uJo" secondAttribute="centerY" id="Hn0-NV-cia"/>
+                        <constraint firstItem="vft-5c-lKn" firstAttribute="leading" secondItem="OTA-uH-vx9" secondAttribute="trailing" constant="10" id="QCj-D2-6NO"/>
+                        <constraint firstItem="vft-5c-lKn" firstAttribute="centerY" secondItem="Mcu-Nu-uJo" secondAttribute="centerY" id="Tfq-S5-FNB"/>
+                        <constraint firstAttribute="height" constant="50" id="VgX-Rt-6AO"/>
+                    </constraints>
+                    <connections>
+                        <outletCollection property="gestureRecognizers" destination="Ycs-bP-jWx" appends="YES" id="xNo-y6-ieQ"/>
+                    </connections>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5sd-4I-dif">
+                    <rect key="frame" x="0.0" y="52" width="414" height="50"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="选择级别" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ySo-Iu-xA9">
+                            <rect key="frame" x="16" y="14.5" width="70" height="21"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <textField opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请选择模拟级别" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7GM-9z-GKK">
+                            <rect key="frame" x="245.5" y="14" width="121.5" height="22"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                            <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="mine_next" translatesAutoresizingMaskIntoConstraints="NO" id="jNy-EB-tVw">
+                            <rect key="frame" x="377" y="14" width="22" height="22"/>
+                        </imageView>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <gestureRecognizers/>
+                    <constraints>
+                        <constraint firstItem="jNy-EB-tVw" firstAttribute="leading" secondItem="7GM-9z-GKK" secondAttribute="trailing" constant="10" id="aqK-Bb-mE9"/>
+                        <constraint firstAttribute="trailing" secondItem="jNy-EB-tVw" secondAttribute="trailing" constant="15" id="bxs-JH-E68"/>
+                        <constraint firstItem="ySo-Iu-xA9" firstAttribute="leading" secondItem="5sd-4I-dif" secondAttribute="leading" constant="16" id="cKT-Kk-TOp"/>
+                        <constraint firstAttribute="height" constant="50" id="ebe-Ja-yDv"/>
+                        <constraint firstItem="jNy-EB-tVw" firstAttribute="centerY" secondItem="5sd-4I-dif" secondAttribute="centerY" id="efs-QH-37s"/>
+                        <constraint firstItem="ySo-Iu-xA9" firstAttribute="centerY" secondItem="5sd-4I-dif" secondAttribute="centerY" id="qz9-SD-7go"/>
+                        <constraint firstItem="7GM-9z-GKK" firstAttribute="centerY" secondItem="5sd-4I-dif" secondAttribute="centerY" id="smq-2e-7g0"/>
+                    </constraints>
+                    <connections>
+                        <outletCollection property="gestureRecognizers" destination="d66-hx-v3i" appends="YES" id="G6e-6e-7dg"/>
+                    </connections>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OG9-ur-aHd">
+                    <rect key="frame" x="0.0" y="556" width="414" height="74"/>
+                    <subviews>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SWJ-np-Nbb">
+                            <rect key="frame" x="15" y="12" width="187" height="50"/>
+                            <color key="backgroundColor" red="0.1764705882352941" green="0.7803921568627451" blue="0.66666666666666663" alpha="1" colorSpace="calibratedRGB"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="50" id="tnP-tK-gr3"/>
+                            </constraints>
+                            <state key="normal" title="直播考试模拟"/>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="25"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="onlineExam:" destination="iN0-l3-epB" eventType="touchUpInside" id="wf5-lA-pMj"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bTe-If-8kL">
+                            <rect key="frame" x="212" y="12" width="187" height="50"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="50" id="cxd-LN-Bhw"/>
+                            </constraints>
+                            <state key="normal" title="录播考试模拟">
+                                <color key="titleColor" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="1" colorSpace="calibratedRGB"/>
+                            </state>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                    <real key="value" value="1"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                    <color key="value" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="1" colorSpace="calibratedRGB"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="25"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="recordExam:" destination="iN0-l3-epB" eventType="touchUpInside" id="wSm-R0-lNc"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <constraints>
+                        <constraint firstItem="SWJ-np-Nbb" firstAttribute="centerY" secondItem="OG9-ur-aHd" secondAttribute="centerY" id="4et-GN-LwK"/>
+                        <constraint firstItem="bTe-If-8kL" firstAttribute="leading" secondItem="SWJ-np-Nbb" secondAttribute="trailing" constant="10" id="56W-Qu-W0V"/>
+                        <constraint firstAttribute="trailing" secondItem="bTe-If-8kL" secondAttribute="trailing" constant="15" id="aFc-8U-bQO"/>
+                        <constraint firstAttribute="height" constant="74" id="bXn-0S-Heb"/>
+                        <constraint firstItem="SWJ-np-Nbb" firstAttribute="leading" secondItem="OG9-ur-aHd" secondAttribute="leading" constant="15" id="f3S-rq-32f"/>
+                        <constraint firstItem="bTe-If-8kL" firstAttribute="width" secondItem="SWJ-np-Nbb" secondAttribute="width" id="pgm-nw-xaO"/>
+                        <constraint firstItem="bTe-If-8kL" firstAttribute="centerY" secondItem="OG9-ur-aHd" secondAttribute="centerY" id="sjs-k0-QnR"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" red="0.95294117647058818" green="0.95686274509803915" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="OG9-ur-aHd" secondAttribute="trailing" id="3gV-Hq-sxj"/>
+                <constraint firstItem="Mcu-Nu-uJo" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="1" id="9Nh-Nw-uI5"/>
+                <constraint firstAttribute="trailing" secondItem="Mcu-Nu-uJo" secondAttribute="trailing" id="IWC-OJ-Z9Q"/>
+                <constraint firstItem="5sd-4I-dif" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="jf0-0E-eYC"/>
+                <constraint firstItem="5sd-4I-dif" firstAttribute="top" secondItem="Mcu-Nu-uJo" secondAttribute="bottom" constant="1" id="t4F-X9-Asf"/>
+                <constraint firstItem="OG9-ur-aHd" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="vz5-6p-U8i"/>
+                <constraint firstAttribute="trailing" secondItem="5sd-4I-dif" secondAttribute="trailing" id="w9V-5x-lTA"/>
+                <constraint firstAttribute="bottom" secondItem="OG9-ur-aHd" secondAttribute="bottom" id="zMj-wV-1qX"/>
+                <constraint firstItem="Mcu-Nu-uJo" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="zNb-Nt-tf5"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="levelField" destination="7GM-9z-GKK" id="ryG-uG-nXb"/>
+                <outlet property="subjectField" destination="OTA-uH-vx9" id="JxW-2H-JCL"/>
+            </connections>
+            <point key="canvasLocation" x="-94.20289855072464" y="-54.910714285714285"/>
+        </view>
+        <tapGestureRecognizer id="Ycs-bP-jWx">
+            <connections>
+                <action selector="chooseSubject:" destination="iN0-l3-epB" id="CZD-s8-WcH"/>
+            </connections>
+        </tapGestureRecognizer>
+        <tapGestureRecognizer id="d66-hx-v3i">
+            <connections>
+                <action selector="chooseLevel:" destination="iN0-l3-epB" id="JUx-a8-UK1"/>
+            </connections>
+        </tapGestureRecognizer>
+    </objects>
+    <resources>
+        <image name="mine_next" width="22" height="22"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 1 - 0
MusicGradeExam/MusicGradeExam/UI/Home/View/HomeBodyView.h

@@ -11,6 +11,7 @@
 typedef NS_ENUM(NSInteger, HOMETYPE) {
     HOMETYPE_NOTICE = 1,   // 通知
     HOMETYPE_BOOKRECORD,   // 报考记录
+    HOMETYPE_SIMULATIONEXAM, // 模拟考试
     HOMETYPE_EXAMRECORD,   // 考试记录
     HOMETYPE_MUSICLIBRARY, // 考级曲库
 };

+ 64 - 16
MusicGradeExam/MusicGradeExam/UI/Home/View/HomeBodyView.xib

@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -21,7 +22,7 @@
                 </imageView>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="deZ-CC-Tlw">
                     <rect key="frame" x="16" y="90.5" width="382" height="146"/>
-                    <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="146" id="2Ow-0T-1Ld"/>
                         <constraint firstAttribute="width" secondItem="deZ-CC-Tlw" secondAttribute="height" multiplier="191:73" id="oCK-Gi-Vza"/>
@@ -83,15 +84,15 @@
                     <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                     <nil key="highlightedColor"/>
                 </label>
-                <imageView clipsSubviews="YES" tag="1003" contentMode="redraw" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="exam_record" translatesAutoresizingMaskIntoConstraints="NO" id="X8m-zH-diL">
-                    <rect key="frame" x="12" y="385.5" width="392" height="134"/>
+                <imageView clipsSubviews="YES" tag="1004" contentMode="redraw" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="exam_record" translatesAutoresizingMaskIntoConstraints="NO" id="X8m-zH-diL">
+                    <rect key="frame" x="12" y="524.5" width="392" height="134"/>
                     <gestureRecognizers/>
                     <connections>
                         <outletCollection property="gestureRecognizers" destination="g0m-kn-yMe" appends="YES" id="J0N-dX-A4b"/>
                     </connections>
                 </imageView>
-                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="您即将进行的考试" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y0E-93-7ac">
-                    <rect key="frame" x="32" y="459.5" width="114.5" height="20"/>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="考试结果一键查询" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y0E-93-7ac">
+                    <rect key="frame" x="32" y="598.5" width="114.5" height="20"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="20" id="eD7-7U-5gB"/>
                     </constraints>
@@ -100,7 +101,7 @@
                     <nil key="highlightedColor"/>
                 </label>
                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="考试记录" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g1C-Ty-W4n">
-                    <rect key="frame" x="32" y="427.5" width="74" height="25"/>
+                    <rect key="frame" x="32" y="566.5" width="74" height="25"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="25" id="tTe-yW-e14"/>
                     </constraints>
@@ -109,10 +110,10 @@
                     <nil key="highlightedColor"/>
                 </label>
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="record_detail" translatesAutoresizingMaskIntoConstraints="NO" id="lSQ-oa-URI">
-                    <rect key="frame" x="151.5" y="460.5" width="14" height="18"/>
+                    <rect key="frame" x="151.5" y="599.5" width="14" height="18"/>
                 </imageView>
-                <imageView clipsSubviews="YES" tag="1004" contentMode="redraw" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="home_library" translatesAutoresizingMaskIntoConstraints="NO" id="6jn-Ca-srp">
-                    <rect key="frame" x="12" y="524.5" width="392" height="134"/>
+                <imageView clipsSubviews="YES" tag="1005" contentMode="redraw" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="home_library" translatesAutoresizingMaskIntoConstraints="NO" id="6jn-Ca-srp">
+                    <rect key="frame" x="12" y="663.5" width="392" height="134"/>
                     <gestureRecognizers/>
                     <constraints>
                         <constraint firstAttribute="width" secondItem="6jn-Ca-srp" secondAttribute="height" multiplier="351:120" id="We3-pT-D82"/>
@@ -121,8 +122,8 @@
                         <outletCollection property="gestureRecognizers" destination="hzg-Cm-ZWb" appends="YES" id="re3-Lm-wRD"/>
                     </connections>
                 </imageView>
-                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="进入考级曲库" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gd1-H6-mZc">
-                    <rect key="frame" x="32" y="598.5" width="86" height="20"/>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="考级曲库提前练习" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gd1-H6-mZc">
+                    <rect key="frame" x="32" y="737.5" width="114.5" height="20"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="20" id="oVm-Ho-adW"/>
                     </constraints>
@@ -131,7 +132,7 @@
                     <nil key="highlightedColor"/>
                 </label>
                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="考级曲库" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ylI-OI-Itq">
-                    <rect key="frame" x="32" y="566.5" width="74" height="25"/>
+                    <rect key="frame" x="32" y="705.5" width="74" height="25"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="25" id="ClN-i1-S5V"/>
                     </constraints>
@@ -140,7 +141,7 @@
                     <nil key="highlightedColor"/>
                 </label>
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="record_detail" translatesAutoresizingMaskIntoConstraints="NO" id="3du-vq-z5T">
-                    <rect key="frame" x="123" y="599.5" width="14" height="18"/>
+                    <rect key="frame" x="151.5" y="738.5" width="14" height="18"/>
                 </imageView>
                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="您的报考记录" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aDg-7e-SV3">
                     <rect key="frame" x="32" y="320.5" width="86" height="20"/>
@@ -154,6 +155,34 @@
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="record_detail" translatesAutoresizingMaskIntoConstraints="NO" id="J1M-Gy-55Y">
                     <rect key="frame" x="123" y="321.5" width="14" height="18"/>
                 </imageView>
+                <imageView clipsSubviews="YES" tag="1003" contentMode="redraw" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="home_SExam" translatesAutoresizingMaskIntoConstraints="NO" id="SJM-7X-iBH">
+                    <rect key="frame" x="12" y="385.5" width="392" height="134"/>
+                    <gestureRecognizers/>
+                    <connections>
+                        <outletCollection property="gestureRecognizers" destination="VWT-A8-Pzz" appends="YES" id="s9b-bD-ULC"/>
+                    </connections>
+                </imageView>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="提前了解考试操作" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ja4-F7-8Lc">
+                    <rect key="frame" x="32" y="459.5" width="114.5" height="20"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="20" id="nhJ-wc-Ray"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="模拟考试" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ayp-KS-rh6">
+                    <rect key="frame" x="32" y="427.5" width="74" height="25"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="25" id="lu9-MF-Xyd"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
+                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="record_detail" translatesAutoresizingMaskIntoConstraints="NO" id="eW7-WS-rBu">
+                    <rect key="frame" x="151.5" y="460.5" width="14" height="18"/>
+                </imageView>
             </subviews>
             <color key="backgroundColor" red="0.95294117647058818" green="0.95686274509803915" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
             <constraints>
@@ -167,34 +196,44 @@
                 <constraint firstItem="X8m-zH-diL" firstAttribute="leading" secondItem="FTX-tf-JYt" secondAttribute="leading" id="8IJ-cL-MHB"/>
                 <constraint firstItem="lSQ-oa-URI" firstAttribute="centerY" secondItem="y0E-93-7ac" secondAttribute="centerY" id="9z9-g0-6Xn"/>
                 <constraint firstItem="pm2-TK-yzh" firstAttribute="centerY" secondItem="qJ1-Pm-qsl" secondAttribute="centerY" id="AjB-gW-5Oi"/>
+                <constraint firstItem="SJM-7X-iBH" firstAttribute="trailing" secondItem="FTX-tf-JYt" secondAttribute="trailing" id="Ckd-Qy-4te"/>
                 <constraint firstItem="6jn-Ca-srp" firstAttribute="trailing" secondItem="FTX-tf-JYt" secondAttribute="trailing" id="EMt-8Q-idq"/>
                 <constraint firstItem="UE7-CX-F3s" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="ES7-0O-HYY"/>
                 <constraint firstItem="g1C-Ty-W4n" firstAttribute="bottom" secondItem="X8m-zH-diL" secondAttribute="centerY" id="FYP-mc-9EX"/>
+                <constraint firstItem="Ayp-KS-rh6" firstAttribute="bottom" secondItem="SJM-7X-iBH" secondAttribute="centerY" id="G2l-Qq-enn"/>
+                <constraint firstItem="Ayp-KS-rh6" firstAttribute="leading" secondItem="SJM-7X-iBH" secondAttribute="leading" constant="20" id="GsH-aQ-sIa"/>
                 <constraint firstItem="6jn-Ca-srp" firstAttribute="leading" secondItem="FTX-tf-JYt" secondAttribute="leading" id="IZb-ZI-5x6"/>
                 <constraint firstItem="J1M-Gy-55Y" firstAttribute="leading" secondItem="aDg-7e-SV3" secondAttribute="trailing" constant="5" id="KkW-2E-C2m"/>
                 <constraint firstAttribute="trailing" secondItem="deZ-CC-Tlw" secondAttribute="trailing" constant="16" id="Nek-Xb-k8j"/>
+                <constraint firstItem="SJM-7X-iBH" firstAttribute="width" secondItem="SJM-7X-iBH" secondAttribute="height" multiplier="351:120" id="PVf-Tt-0K6"/>
                 <constraint firstItem="g1C-Ty-W4n" firstAttribute="leading" secondItem="X8m-zH-diL" secondAttribute="leading" constant="20" id="Se2-In-qdn"/>
                 <constraint firstItem="Gd1-H6-mZc" firstAttribute="top" secondItem="ylI-OI-Itq" secondAttribute="bottom" constant="7" id="TEV-is-ZS3"/>
                 <constraint firstItem="71n-fC-CqF" firstAttribute="leading" secondItem="FTX-tf-JYt" secondAttribute="leading" constant="20" id="VpC-SF-2LZ"/>
                 <constraint firstItem="3du-vq-z5T" firstAttribute="centerY" secondItem="Gd1-H6-mZc" secondAttribute="centerY" id="WOA-Fd-oVt"/>
                 <constraint firstItem="qJ1-Pm-qsl" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="XWG-Hi-LXu"/>
                 <constraint firstItem="6jn-Ca-srp" firstAttribute="top" secondItem="X8m-zH-diL" secondAttribute="bottom" constant="5" id="Xdu-ZS-WnO"/>
+                <constraint firstItem="SJM-7X-iBH" firstAttribute="leading" secondItem="FTX-tf-JYt" secondAttribute="leading" id="b5Y-U5-4YK"/>
+                <constraint firstItem="ja4-F7-8Lc" firstAttribute="leading" secondItem="Ayp-KS-rh6" secondAttribute="leading" id="ctn-x8-Ipz"/>
                 <constraint firstItem="lSQ-oa-URI" firstAttribute="leading" secondItem="y0E-93-7ac" secondAttribute="trailing" constant="5" id="duC-ZB-gBe"/>
                 <constraint firstItem="X8m-zH-diL" firstAttribute="trailing" secondItem="FTX-tf-JYt" secondAttribute="trailing" id="eLs-5L-Yai"/>
+                <constraint firstItem="ja4-F7-8Lc" firstAttribute="top" secondItem="Ayp-KS-rh6" secondAttribute="bottom" constant="7" id="enl-Et-epa"/>
+                <constraint firstItem="X8m-zH-diL" firstAttribute="top" secondItem="SJM-7X-iBH" secondAttribute="bottom" constant="5" id="feO-GJ-4eb"/>
+                <constraint firstItem="eW7-WS-rBu" firstAttribute="leading" secondItem="ja4-F7-8Lc" secondAttribute="trailing" constant="5" id="fgG-HK-Khm"/>
                 <constraint firstItem="ylI-OI-Itq" firstAttribute="leading" secondItem="6jn-Ca-srp" secondAttribute="leading" constant="20" id="gmk-5l-Qbf"/>
                 <constraint firstItem="UE7-CX-F3s" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hKP-bb-VyG"/>
                 <constraint firstItem="deZ-CC-Tlw" firstAttribute="top" secondItem="pm2-TK-yzh" secondAttribute="bottom" constant="20" id="iLw-WW-Lf8"/>
                 <constraint firstItem="J1M-Gy-55Y" firstAttribute="centerY" secondItem="aDg-7e-SV3" secondAttribute="centerY" id="oiT-pM-V6J"/>
                 <constraint firstItem="FTX-tf-JYt" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="12" id="ond-pM-vCq"/>
+                <constraint firstItem="SJM-7X-iBH" firstAttribute="top" secondItem="FTX-tf-JYt" secondAttribute="bottom" constant="5" id="sPh-xu-bag"/>
                 <constraint firstItem="aDg-7e-SV3" firstAttribute="top" secondItem="71n-fC-CqF" secondAttribute="bottom" constant="7" id="sZM-2r-jhV"/>
                 <constraint firstItem="y0E-93-7ac" firstAttribute="top" secondItem="g1C-Ty-W4n" secondAttribute="bottom" constant="7" id="tGA-jG-Bm1"/>
+                <constraint firstItem="eW7-WS-rBu" firstAttribute="centerY" secondItem="ja4-F7-8Lc" secondAttribute="centerY" id="tlR-1b-TeL"/>
                 <constraint firstItem="71n-fC-CqF" firstAttribute="bottom" secondItem="FTX-tf-JYt" secondAttribute="centerY" id="upB-i4-JqE"/>
                 <constraint firstItem="Gd1-H6-mZc" firstAttribute="leading" secondItem="ylI-OI-Itq" secondAttribute="leading" id="wQf-uF-w9i"/>
                 <constraint firstAttribute="trailing" secondItem="pm2-TK-yzh" secondAttribute="trailing" constant="10" id="wWc-Ul-kmu"/>
                 <constraint firstItem="ylI-OI-Itq" firstAttribute="bottom" secondItem="6jn-Ca-srp" secondAttribute="centerY" id="xHE-4u-yL6"/>
                 <constraint firstItem="aDg-7e-SV3" firstAttribute="leading" secondItem="71n-fC-CqF" secondAttribute="leading" id="xNP-fv-2MS"/>
                 <constraint firstItem="qJ1-Pm-qsl" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="34" id="z7t-8v-nwm"/>
-                <constraint firstItem="X8m-zH-diL" firstAttribute="top" secondItem="FTX-tf-JYt" secondAttribute="bottom" constant="5" id="zqL-CI-vbV"/>
             </constraints>
             <connections>
                 <outlet property="bgHeight" destination="2Ow-0T-1Ld" id="wrY-ii-pAl"/>
@@ -209,6 +248,11 @@
                 <action selector="tapAction:" destination="iN0-l3-epB" id="2oP-m7-QR3"/>
             </connections>
         </tapGestureRecognizer>
+        <tapGestureRecognizer id="VWT-A8-Pzz">
+            <connections>
+                <action selector="tapAction:" destination="iN0-l3-epB" id="kX0-pZ-Tee"/>
+            </connections>
+        </tapGestureRecognizer>
         <tapGestureRecognizer id="g0m-kn-yMe">
             <connections>
                 <action selector="tapAction:" destination="iN0-l3-epB" id="xmA-Kb-uvf"/>
@@ -223,9 +267,13 @@
     <resources>
         <image name="book_record" width="351" height="120"/>
         <image name="exam_record" width="351" height="120"/>
+        <image name="home_SExam" width="351" height="120"/>
         <image name="home_library" width="351" height="120"/>
         <image name="home_top" width="375" height="158"/>
         <image name="notice_read" width="19" height="22"/>
         <image name="record_detail" width="14" height="18"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
     </resources>
 </document>

+ 1 - 1
MusicGradeExam/MusicGradeExam/UI/RecordExam/Controller/RecordExamViewController.m

@@ -248,7 +248,7 @@
 - (RecordBodyView *)topView {
     if (!_topView) {
         _topView = [RecordBodyView shareInstance];
-        
+        _topView.topTitleLabel.text = @"录播考试";
         MJWeakSelf;
         [_topView topviewAction:^(RECORDTOPACTION action) {
             [weakSelf backOrEndAction:action];

+ 2 - 0
MusicGradeExam/MusicGradeExam/UI/RecordExam/View/RecordBodyView.h

@@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 @interface RecordBodyView : UIView
 
+@property (weak, nonatomic) IBOutlet UILabel *topTitleLabel;
+
 + (instancetype)shareInstance;
 
 - (void)configTime:(NSString *)subTime;

+ 9 - 4
MusicGradeExam/MusicGradeExam/UI/RecordExam/View/RecordBodyView.xib

@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -64,7 +65,7 @@
                             <nil key="highlightedColor"/>
                         </label>
                     </subviews>
-                    <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="46" id="DC6-cS-Jye"/>
                         <constraint firstItem="Q8k-CG-YKq" firstAttribute="leading" secondItem="76t-dO-T3V" secondAttribute="trailing" id="DVU-KZ-PJP"/>
@@ -92,6 +93,7 @@
                     <nil key="highlightedColor"/>
                 </label>
             </subviews>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
             <color key="backgroundColor" red="0.96078431372549022" green="0.96078431372549022" blue="0.96078431372549022" alpha="1" colorSpace="calibratedRGB"/>
             <constraints>
                 <constraint firstItem="u8d-f2-rBu" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="3Ip-x5-kYQ"/>
@@ -107,9 +109,9 @@
                 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="68b-I8-Bmr" secondAttribute="trailing" constant="16" id="rWe-qe-faA"/>
                 <constraint firstItem="68b-I8-Bmr" firstAttribute="bottom" secondItem="u8d-f2-rBu" secondAttribute="bottom" constant="11" id="sHM-ZD-pDL"/>
             </constraints>
-            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
             <connections>
                 <outlet property="countLabel" destination="Q8k-CG-YKq" id="962-eh-ilI"/>
+                <outlet property="topTitleLabel" destination="hAD-kA-qss" id="INa-Gf-icp"/>
             </connections>
             <point key="canvasLocation" x="163.768115942029" y="71.651785714285708"/>
         </view>
@@ -118,5 +120,8 @@
         <image name="count_image" width="22" height="25"/>
         <image name="home_top" width="375" height="158"/>
         <image name="login_back" width="12" height="21"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
     </resources>
 </document>