Просмотр исходного кода

Merge branch 'feature/dev_Chris' into develop

# Conflicts:
#	RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj
Chris лет назад: 5
Родитель
Сommit
3380830814
100 измененных файлов с 5618 добавлено и 0 удалено
  1. 222 0
      RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj
  2. 2 0
      RainbowPlanet/RainbowPlanet/Macro/ColorMacro.swift
  3. 9 0
      RainbowPlanet/RainbowPlanet/Macro/RainbowPlanet-Bridging-Header.h
  4. 128 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/Controller/PublishEditController.swift
  5. 108 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditAddAddressCell.swift
  6. 103 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditAddPicCell.swift
  7. 85 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditAddTopicCell.swift
  8. 86 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditDescribeCell.swift
  9. 89 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditTitleCell.swift
  10. 551 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Controller/KSMediaPickerController.swift
  11. 65 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSButton/KSBorderButton.swift
  12. 52 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSButton/KSButton.swift
  13. 184 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSExtension.swift
  14. 26 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSLayout.h
  15. 22 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSMediaPicker.strings
  16. 33 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSSegmentedControl/KSSegmentedControl.h
  17. 258 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSSegmentedControl/KSSegmentedControl.m
  18. 50 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoLayer.h
  19. 221 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoLayer.m
  20. 35 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerBaseView.h
  21. 188 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerBaseView.m
  22. 18 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerLiteView.h
  23. 82 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerLiteView.m
  24. 50 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Model/KSMediaPickerAlbumModel.swift
  25. 67 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Model/KSMediaPickerItemModel.swift
  26. 37 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Model/KSMediaPickerOutputModel.swift
  27. 227 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCameraToolBar.swift
  28. 447 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCameraView.swift
  29. 20 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCollectionView.h
  30. 49 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCollectionView.m
  31. 56 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerNavigationView.swift
  32. 455 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerPreviewView.swift
  33. 196 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerRECButton.swift
  34. 26 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerScrollView.h
  35. 67 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerScrollView.m
  36. 112 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerSelectIndicator.swift
  37. 486 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerView.swift
  38. 141 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerViewImageCell.swift
  39. 119 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerViewVideoCell.swift
  40. 6 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/Contents.json
  41. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_Selected.imageset/Contents.json
  42. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_Selected.imageset/icon_ImagePicker_Selected@2x.png
  43. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_Selected.imageset/icon_ImagePicker_Selected@3x.png
  44. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_play.imageset/Contents.json
  45. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_play.imageset/icon_ImagePicker_play@2x.png
  46. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_play.imageset/icon_ImagePicker_play@3x.png
  47. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close.imageset/Contents.json
  48. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close.imageset/icon_mediaPicker_camera_close@2x.png
  49. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close.imageset/icon_mediaPicker_camera_close@3x.png
  50. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close_b.imageset/Contents.json
  51. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close_b.imageset/icon_mediaPicker_camera_close_b@2x.png
  52. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close_b.imageset/icon_mediaPicker_camera_close_b@3x.png
  53. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto.imageset/Contents.json
  54. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto.imageset/icon_mediaPicker_camera_flashlight_auto@2x.png
  55. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto.imageset/icon_mediaPicker_camera_flashlight_auto@3x.png
  56. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto_b.imageset/Contents.json
  57. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto_b.imageset/icon_mediaPicker_camera_flashlight_auto_b@2x.png
  58. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto_b.imageset/icon_mediaPicker_camera_flashlight_auto_b@3x.png
  59. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off.imageset/Contents.json
  60. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off.imageset/icon_mediaPicker_camera_flashlight_off@2x.png
  61. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off.imageset/icon_mediaPicker_camera_flashlight_off@3x.png
  62. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off_b.imageset/Contents.json
  63. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off_b.imageset/icon_mediaPicker_camera_flashlight_off_b@2x.png
  64. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off_b.imageset/icon_mediaPicker_camera_flashlight_off_b@3x.png
  65. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on.imageset/Contents.json
  66. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on.imageset/icon_mediaPicker_camera_flashlight_on@2x.png
  67. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on.imageset/icon_mediaPicker_camera_flashlight_on@3x.png
  68. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on_b.imageset/Contents.json
  69. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on_b.imageset/icon_mediaPicker_camera_flashlight_on_b@2x.png
  70. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on_b.imageset/icon_mediaPicker_camera_flashlight_on_b@3x.png
  71. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle.imageset/Contents.json
  72. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle.imageset/icon_mediaPicker_camera_rectangle@2x.png
  73. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle.imageset/icon_mediaPicker_camera_rectangle@3x.png
  74. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle_16_9.imageset/Contents.json
  75. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle_16_9.imageset/icon_mediaPicker_camera_rectangle_16_9@2x.png
  76. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle_16_9.imageset/icon_mediaPicker_camera_rectangle_16_9@3x.png
  77. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square.imageset/Contents.json
  78. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square.imageset/icon_mediaPicker_camera_square@2x.png
  79. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square.imageset/icon_mediaPicker_camera_square@3x.png
  80. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square_b.imageset/Contents.json
  81. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square_b.imageset/icon_mediaPicker_camera_square_b@2x.png
  82. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square_b.imageset/icon_mediaPicker_camera_square_b@3x.png
  83. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch.imageset/Contents.json
  84. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch.imageset/icon_mediaPicker_camera_switch@2x.png
  85. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch.imageset/icon_mediaPicker_camera_switch@3x.png
  86. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch_b.imageset/Contents.json
  87. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch_b.imageset/icon_mediaPicker_camera_switch_b@2x.png
  88. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch_b.imageset/icon_mediaPicker_camera_switch_b@3x.png
  89. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fill.imageset/Contents.json
  90. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fill.imageset/icon_mediaPicker_preview_aspect_fill@2x.png
  91. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fill.imageset/icon_mediaPicker_preview_aspect_fill@3x.png
  92. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fit.imageset/Contents.json
  93. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fit.imageset/icon_mediaPicker_preview_aspect_fit@2x.png
  94. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fit.imageset/icon_mediaPicker_preview_aspect_fit@3x.png
  95. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_cut.imageset/Contents.json
  96. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_cut.imageset/icon_mediaPicker_preview_cut@2x.png
  97. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_cut.imageset/icon_mediaPicker_preview_cut@3x.png
  98. 22 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_nocut.imageset/Contents.json
  99. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_nocut.imageset/icon_mediaPicker_preview_nocut@2x.png
  100. 0 0
      RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_nocut.imageset/icon_mediaPicker_preview_nocut@3x.png

+ 222 - 0
RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj

@@ -388,6 +388,28 @@
 		BD12205022AFB08B0051C7C2 /* MessageThumbTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12204F22AFB08B0051C7C2 /* MessageThumbTableCell.swift */; };
 		BD12B66922B47D4800AEB10B /* RecommendSubCommentCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B66822B47D4700AEB10B /* RecommendSubCommentCollectionCell.swift */; };
 		BD12B66B22B4A01300AEB10B /* RecommendSubCommentCollectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B66A22B4A01300AEB10B /* RecommendSubCommentCollectionFooter.swift */; };
+		BD12B67422B4EC9700AEB10B /* KSMediaPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B67322B4EC9700AEB10B /* KSMediaPickerController.swift */; };
+		BD12B67822B4ED9200AEB10B /* KSMediaPickerOutputModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B67722B4ED9200AEB10B /* KSMediaPickerOutputModel.swift */; };
+		BD12B67C22B4EE6D00AEB10B /* KSMediaPickerAlbumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B67A22B4EE6C00AEB10B /* KSMediaPickerAlbumModel.swift */; };
+		BD12B67D22B4EE6D00AEB10B /* KSMediaPickerItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B67B22B4EE6D00AEB10B /* KSMediaPickerItemModel.swift */; };
+		BD12B68022B4EF2600AEB10B /* KSMediaPickerViewImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B67E22B4EF2600AEB10B /* KSMediaPickerViewImageCell.swift */; };
+		BD12B68122B4EF2600AEB10B /* KSMediaPickerViewVideoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B67F22B4EF2600AEB10B /* KSMediaPickerViewVideoCell.swift */; };
+		BD12B68322B4EFF000AEB10B /* KSMediaPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B68222B4EFF000AEB10B /* KSMediaPickerView.swift */; };
+		BD12B68522B4F15300AEB10B /* KSMediaPickerCameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B68422B4F15300AEB10B /* KSMediaPickerCameraView.swift */; };
+		BD12B68822B4F28F00AEB10B /* KSExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B68722B4F28F00AEB10B /* KSExtension.swift */; };
+		BD12B68C22B4F4FF00AEB10B /* KSSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = BD12B68B22B4F4FF00AEB10B /* KSSegmentedControl.m */; };
+		BD12B68E22B4F5DD00AEB10B /* KSMediaPickerCameraToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B68D22B4F5DD00AEB10B /* KSMediaPickerCameraToolBar.swift */; };
+		BD12B69122B4F60300AEB10B /* KSMediaPickerScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD12B69022B4F60200AEB10B /* KSMediaPickerScrollView.m */; };
+		BD12B69422B4F68400AEB10B /* KSMediaPickerCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD12B69322B4F68400AEB10B /* KSMediaPickerCollectionView.m */; };
+		BD12B69622B4F72900AEB10B /* KSMediaPickerPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B69522B4F72900AEB10B /* KSMediaPickerPreviewView.swift */; };
+		BD12B69A22B4FA8400AEB10B /* KSMediaPickerSelectIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B69922B4FA8400AEB10B /* KSMediaPickerSelectIndicator.swift */; };
+		BD12B69C22B4FAC800AEB10B /* KSMediaPickerRECButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B69B22B4FAC800AEB10B /* KSMediaPickerRECButton.swift */; };
+		BD12B69E22B4FAF000AEB10B /* KSMediaPickerNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B69D22B4FAF000AEB10B /* KSMediaPickerNavigationView.swift */; };
+		BD12B6A222B4FC9B00AEB10B /* KSBorderButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B6A022B4FC9B00AEB10B /* KSBorderButton.swift */; };
+		BD12B6A322B4FC9B00AEB10B /* KSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD12B6A122B4FC9B00AEB10B /* KSButton.swift */; };
+		BD12B6AB22B502C200AEB10B /* KSVideoPlayerLiteView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD12B6A522B502C200AEB10B /* KSVideoPlayerLiteView.m */; };
+		BD12B6AC22B502C200AEB10B /* KSVideoPlayerBaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD12B6A722B502C200AEB10B /* KSVideoPlayerBaseView.m */; };
+		BD12B6AD22B502C200AEB10B /* KSVideoLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = BD12B6AA22B502C200AEB10B /* KSVideoLayer.m */; };
 		BD1DC6C5228CFD0B00B89C57 /* SwiftMoyaNetWorkServiceOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD1DC6C3228CFD0B00B89C57 /* SwiftMoyaNetWorkServiceOrder.swift */; };
 		BD1DC6C6228CFD0B00B89C57 /* SwiftMoyaServiceOrderApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD1DC6C4228CFD0B00B89C57 /* SwiftMoyaServiceOrderApi.swift */; };
 		BD1DC6C9228D005000B89C57 /* OrderCreateParameterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD1DC6C8228D005000B89C57 /* OrderCreateParameterModel.swift */; };
@@ -408,6 +430,14 @@
 		BD20F1CF2283CE2300677D8E /* OrderFinishPayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD20F1CE2283CE2300677D8E /* OrderFinishPayView.swift */; };
 		BD20F1D32283D0ED00677D8E /* OrderFinishPaySuccessCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD20F1D22283D0ED00677D8E /* OrderFinishPaySuccessCell.swift */; };
 		BD20F1D52283D15500677D8E /* OrderFinishPayFailureCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD20F1D42283D15500677D8E /* OrderFinishPayFailureCell.swift */; };
+		BD24FABB22B509CF00C7AA3B /* PublishModule.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BD24FABA22B509CF00C7AA3B /* PublishModule.xcassets */; };
+		BD24FABF22B50C4B00C7AA3B /* KSMediaPicker.strings in Resources */ = {isa = PBXBuildFile; fileRef = BD24FABE22B50C4B00C7AA3B /* KSMediaPicker.strings */; };
+		BD28077822B721BF002AB976 /* PublishEditController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD28077722B721BF002AB976 /* PublishEditController.swift */; };
+		BD28077A22B72734002AB976 /* PublishEditTitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD28077922B72734002AB976 /* PublishEditTitleCell.swift */; };
+		BD28077C22B72761002AB976 /* PublishEditDescribeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD28077B22B72761002AB976 /* PublishEditDescribeCell.swift */; };
+		BD28077E22B72797002AB976 /* PublishEditAddTopicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD28077D22B72797002AB976 /* PublishEditAddTopicCell.swift */; };
+		BD28078022B727A6002AB976 /* PublishEditAddAddressCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD28077F22B727A6002AB976 /* PublishEditAddAddressCell.swift */; };
+		BD28078222B727BD002AB976 /* PublishEditAddPicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD28078122B727BD002AB976 /* PublishEditAddPicCell.swift */; };
 		BD29A92E228F99780018CFC3 /* OrderCommentParameterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD29A92D228F99780018CFC3 /* OrderCommentParameterModel.swift */; };
 		BD2FCBE222B21CF70006D974 /* CommunityRecommendController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD2FCBE122B21CF70006D974 /* CommunityRecommendController.swift */; };
 		BD2FCBE422B244250006D974 /* RecommendDetailContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD2FCBE322B244250006D974 /* RecommendDetailContentCell.swift */; };
@@ -879,6 +909,35 @@
 		BD12204F22AFB08B0051C7C2 /* MessageThumbTableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageThumbTableCell.swift; sourceTree = "<group>"; };
 		BD12B66822B47D4700AEB10B /* RecommendSubCommentCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendSubCommentCollectionCell.swift; sourceTree = "<group>"; };
 		BD12B66A22B4A01300AEB10B /* RecommendSubCommentCollectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendSubCommentCollectionFooter.swift; sourceTree = "<group>"; };
+		BD12B67322B4EC9700AEB10B /* KSMediaPickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerController.swift; sourceTree = "<group>"; };
+		BD12B67722B4ED9200AEB10B /* KSMediaPickerOutputModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerOutputModel.swift; sourceTree = "<group>"; };
+		BD12B67A22B4EE6C00AEB10B /* KSMediaPickerAlbumModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerAlbumModel.swift; sourceTree = "<group>"; };
+		BD12B67B22B4EE6D00AEB10B /* KSMediaPickerItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerItemModel.swift; sourceTree = "<group>"; };
+		BD12B67E22B4EF2600AEB10B /* KSMediaPickerViewImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerViewImageCell.swift; sourceTree = "<group>"; };
+		BD12B67F22B4EF2600AEB10B /* KSMediaPickerViewVideoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerViewVideoCell.swift; sourceTree = "<group>"; };
+		BD12B68222B4EFF000AEB10B /* KSMediaPickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerView.swift; sourceTree = "<group>"; };
+		BD12B68422B4F15300AEB10B /* KSMediaPickerCameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerCameraView.swift; sourceTree = "<group>"; };
+		BD12B68722B4F28F00AEB10B /* KSExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSExtension.swift; sourceTree = "<group>"; };
+		BD12B68A22B4F4FF00AEB10B /* KSSegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSegmentedControl.h; sourceTree = "<group>"; };
+		BD12B68B22B4F4FF00AEB10B /* KSSegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSegmentedControl.m; sourceTree = "<group>"; };
+		BD12B68D22B4F5DD00AEB10B /* KSMediaPickerCameraToolBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerCameraToolBar.swift; sourceTree = "<group>"; };
+		BD12B68F22B4F60200AEB10B /* KSMediaPickerScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSMediaPickerScrollView.h; sourceTree = "<group>"; };
+		BD12B69022B4F60200AEB10B /* KSMediaPickerScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSMediaPickerScrollView.m; sourceTree = "<group>"; };
+		BD12B69222B4F68400AEB10B /* KSMediaPickerCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSMediaPickerCollectionView.h; sourceTree = "<group>"; };
+		BD12B69322B4F68400AEB10B /* KSMediaPickerCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSMediaPickerCollectionView.m; sourceTree = "<group>"; };
+		BD12B69522B4F72900AEB10B /* KSMediaPickerPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerPreviewView.swift; sourceTree = "<group>"; };
+		BD12B69922B4FA8400AEB10B /* KSMediaPickerSelectIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerSelectIndicator.swift; sourceTree = "<group>"; };
+		BD12B69B22B4FAC800AEB10B /* KSMediaPickerRECButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerRECButton.swift; sourceTree = "<group>"; };
+		BD12B69D22B4FAF000AEB10B /* KSMediaPickerNavigationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSMediaPickerNavigationView.swift; sourceTree = "<group>"; };
+		BD12B6A022B4FC9B00AEB10B /* KSBorderButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSBorderButton.swift; sourceTree = "<group>"; };
+		BD12B6A122B4FC9B00AEB10B /* KSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSButton.swift; sourceTree = "<group>"; };
+		BD12B6A522B502C200AEB10B /* KSVideoPlayerLiteView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSVideoPlayerLiteView.m; sourceTree = "<group>"; };
+		BD12B6A622B502C200AEB10B /* KSVideoLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSVideoLayer.h; sourceTree = "<group>"; };
+		BD12B6A722B502C200AEB10B /* KSVideoPlayerBaseView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSVideoPlayerBaseView.m; sourceTree = "<group>"; };
+		BD12B6A822B502C200AEB10B /* KSVideoPlayerLiteView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSVideoPlayerLiteView.h; sourceTree = "<group>"; };
+		BD12B6A922B502C200AEB10B /* KSVideoPlayerBaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSVideoPlayerBaseView.h; sourceTree = "<group>"; };
+		BD12B6AA22B502C200AEB10B /* KSVideoLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSVideoLayer.m; sourceTree = "<group>"; };
+		BD12B6AE22B5076800AEB10B /* KSLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSLayout.h; sourceTree = "<group>"; };
 		BD1DC6C3228CFD0B00B89C57 /* SwiftMoyaNetWorkServiceOrder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftMoyaNetWorkServiceOrder.swift; sourceTree = "<group>"; };
 		BD1DC6C4228CFD0B00B89C57 /* SwiftMoyaServiceOrderApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftMoyaServiceOrderApi.swift; sourceTree = "<group>"; };
 		BD1DC6C8228D005000B89C57 /* OrderCreateParameterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderCreateParameterModel.swift; sourceTree = "<group>"; };
@@ -904,6 +963,14 @@
 		BD20F1CE2283CE2300677D8E /* OrderFinishPayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderFinishPayView.swift; sourceTree = "<group>"; };
 		BD20F1D22283D0ED00677D8E /* OrderFinishPaySuccessCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderFinishPaySuccessCell.swift; sourceTree = "<group>"; };
 		BD20F1D42283D15500677D8E /* OrderFinishPayFailureCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderFinishPayFailureCell.swift; sourceTree = "<group>"; };
+		BD24FABA22B509CF00C7AA3B /* PublishModule.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = PublishModule.xcassets; sourceTree = "<group>"; };
+		BD24FABE22B50C4B00C7AA3B /* KSMediaPicker.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = KSMediaPicker.strings; sourceTree = "<group>"; };
+		BD28077722B721BF002AB976 /* PublishEditController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishEditController.swift; sourceTree = "<group>"; };
+		BD28077922B72734002AB976 /* PublishEditTitleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishEditTitleCell.swift; sourceTree = "<group>"; };
+		BD28077B22B72761002AB976 /* PublishEditDescribeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishEditDescribeCell.swift; sourceTree = "<group>"; };
+		BD28077D22B72797002AB976 /* PublishEditAddTopicCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishEditAddTopicCell.swift; sourceTree = "<group>"; };
+		BD28077F22B727A6002AB976 /* PublishEditAddAddressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishEditAddAddressCell.swift; sourceTree = "<group>"; };
+		BD28078122B727BD002AB976 /* PublishEditAddPicCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishEditAddPicCell.swift; sourceTree = "<group>"; };
 		BD29A92D228F99780018CFC3 /* OrderCommentParameterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderCommentParameterModel.swift; sourceTree = "<group>"; };
 		BD2FCBE122B21CF70006D974 /* CommunityRecommendController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityRecommendController.swift; sourceTree = "<group>"; };
 		BD2FCBE322B244250006D974 /* RecommendDetailContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendDetailContentCell.swift; sourceTree = "<group>"; };
@@ -2275,6 +2342,7 @@
 				A77F2CAE2232010F001BD3F6 /* RegisterLoginModule */,
 				A719EE6622AF4374001AAC98 /* CommunityModule */,
 				A77F2CA32232010F001BD3F6 /* ShoppingMallModule */,
+				BD12B67122B4E96100AEB10B /* PublishModule */,
 				BD3AA45422AE635700EF4F20 /* MessageModule */,
 				A77F2CA92232010F001BD3F6 /* MineModule */,
 				A7FF155A228C689C00A85748 /* OrderModule */,
@@ -2392,6 +2460,7 @@
 				A7931E0722AF855E00297D0A /* RegisterLoginModule.xcassets */,
 				A7BF202322B392D600396DB3 /* CommunityModule.xcassets */,
 				A7BF202622B3930100396DB3 /* MessageModule.xcassets */,
+				BD24FABA22B509CF00C7AA3B /* PublishModule.xcassets */,
 				A729B5A92266F6FD004AE098 /* Launch Screen.storyboard */,
 				A77F2C6C2231FB4A001BD3F6 /* Info.plist */,
 			);
@@ -3394,6 +3463,100 @@
 			path = MessagePlanetThumb;
 			sourceTree = "<group>";
 		};
+		BD12B67122B4E96100AEB10B /* PublishModule */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B67222B4E99800AEB10B /* PublishMediaPicker */,
+				BD28077422B72175002AB976 /* PublishEditController */,
+			);
+			path = PublishModule;
+			sourceTree = "<group>";
+		};
+		BD12B67222B4E99800AEB10B /* PublishMediaPicker */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B6A422B502C200AEB10B /* KSVideoPlayerView */,
+				BD12B6AE22B5076800AEB10B /* KSLayout.h */,
+				BD12B68722B4F28F00AEB10B /* KSExtension.swift */,
+				BD24FABE22B50C4B00C7AA3B /* KSMediaPicker.strings */,
+				BD12B69F22B4FC9B00AEB10B /* KSButton */,
+				BD12B68922B4F4FF00AEB10B /* KSSegmentedControl */,
+				BD12B67522B4ECE200AEB10B /* Controller */,
+				BD12B67622B4ED8800AEB10B /* Model */,
+				BD12B67922B4EE1A00AEB10B /* View */,
+			);
+			path = PublishMediaPicker;
+			sourceTree = "<group>";
+		};
+		BD12B67522B4ECE200AEB10B /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B67322B4EC9700AEB10B /* KSMediaPickerController.swift */,
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		BD12B67622B4ED8800AEB10B /* Model */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B67A22B4EE6C00AEB10B /* KSMediaPickerAlbumModel.swift */,
+				BD12B67B22B4EE6D00AEB10B /* KSMediaPickerItemModel.swift */,
+				BD12B67722B4ED9200AEB10B /* KSMediaPickerOutputModel.swift */,
+			);
+			path = Model;
+			sourceTree = "<group>";
+		};
+		BD12B67922B4EE1A00AEB10B /* View */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B68D22B4F5DD00AEB10B /* KSMediaPickerCameraToolBar.swift */,
+				BD12B68422B4F15300AEB10B /* KSMediaPickerCameraView.swift */,
+				BD12B69222B4F68400AEB10B /* KSMediaPickerCollectionView.h */,
+				BD12B69322B4F68400AEB10B /* KSMediaPickerCollectionView.m */,
+				BD12B69D22B4FAF000AEB10B /* KSMediaPickerNavigationView.swift */,
+				BD12B69522B4F72900AEB10B /* KSMediaPickerPreviewView.swift */,
+				BD12B69B22B4FAC800AEB10B /* KSMediaPickerRECButton.swift */,
+				BD12B68F22B4F60200AEB10B /* KSMediaPickerScrollView.h */,
+				BD12B69022B4F60200AEB10B /* KSMediaPickerScrollView.m */,
+				BD12B69922B4FA8400AEB10B /* KSMediaPickerSelectIndicator.swift */,
+				BD12B68222B4EFF000AEB10B /* KSMediaPickerView.swift */,
+				BD12B67E22B4EF2600AEB10B /* KSMediaPickerViewImageCell.swift */,
+				BD12B67F22B4EF2600AEB10B /* KSMediaPickerViewVideoCell.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
+		BD12B68922B4F4FF00AEB10B /* KSSegmentedControl */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B68A22B4F4FF00AEB10B /* KSSegmentedControl.h */,
+				BD12B68B22B4F4FF00AEB10B /* KSSegmentedControl.m */,
+			);
+			path = KSSegmentedControl;
+			sourceTree = "<group>";
+		};
+		BD12B69F22B4FC9B00AEB10B /* KSButton */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B6A022B4FC9B00AEB10B /* KSBorderButton.swift */,
+				BD12B6A122B4FC9B00AEB10B /* KSButton.swift */,
+			);
+			path = KSButton;
+			sourceTree = "<group>";
+		};
+		BD12B6A422B502C200AEB10B /* KSVideoPlayerView */ = {
+			isa = PBXGroup;
+			children = (
+				BD12B6A522B502C200AEB10B /* KSVideoPlayerLiteView.m */,
+				BD12B6A622B502C200AEB10B /* KSVideoLayer.h */,
+				BD12B6A722B502C200AEB10B /* KSVideoPlayerBaseView.m */,
+				BD12B6A822B502C200AEB10B /* KSVideoPlayerLiteView.h */,
+				BD12B6A922B502C200AEB10B /* KSVideoPlayerBaseView.h */,
+				BD12B6AA22B502C200AEB10B /* KSVideoLayer.m */,
+			);
+			path = KSVideoPlayerView;
+			sourceTree = "<group>";
+		};
 		BD1DC6C2228CFD0B00B89C57 /* SwiftMoyaServiceOrder */ = {
 			isa = PBXGroup;
 			children = (
@@ -3460,6 +3623,35 @@
 			path = Category;
 			sourceTree = "<group>";
 		};
+		BD28077422B72175002AB976 /* PublishEditController */ = {
+			isa = PBXGroup;
+			children = (
+				BD28077622B721AC002AB976 /* View */,
+				BD28077522B721A2002AB976 /* Controller */,
+			);
+			path = PublishEditController;
+			sourceTree = "<group>";
+		};
+		BD28077522B721A2002AB976 /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+				BD28077722B721BF002AB976 /* PublishEditController.swift */,
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		BD28077622B721AC002AB976 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				BD28078122B727BD002AB976 /* PublishEditAddPicCell.swift */,
+				BD28077922B72734002AB976 /* PublishEditTitleCell.swift */,
+				BD28077B22B72761002AB976 /* PublishEditDescribeCell.swift */,
+				BD28077D22B72797002AB976 /* PublishEditAddTopicCell.swift */,
+				BD28077F22B727A6002AB976 /* PublishEditAddAddressCell.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		BD2FCBDE22B21BE00006D974 /* CommunityRecommendDetail */ = {
 			isa = PBXGroup;
 			children = (
@@ -3875,6 +4067,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				BD24FABF22B50C4B00C7AA3B /* KSMediaPicker.strings in Resources */,
 				A7CC74DE22703B4A003C4F38 /* MineModule.xcassets in Resources */,
 				A7BF202422B392D600396DB3 /* CommunityModule.xcassets in Resources */,
 				A71AF0BE226F1792001730FE /* ShoppingMallModule.xcassets in Resources */,
@@ -3890,6 +4083,7 @@
 				A7BF202722B3930100396DB3 /* MessageModule.xcassets in Resources */,
 				BD108C9A22A60C3300837DAB /* HGImage.xcassets in Resources */,
 				A729B5AA2266F6FD004AE098 /* Launch Screen.storyboard in Resources */,
+				BD24FABB22B509CF00C7AA3B /* PublishModule.xcassets in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3991,11 +4185,13 @@
 				BDAF83A822B343C50004BCC3 /* RecommendBottomCommentView.swift in Sources */,
 				BD12B66B22B4A01300AEB10B /* RecommendSubCommentCollectionFooter.swift in Sources */,
 				A77F2C9E2231FDDC001BD3F6 /* BaseViewController.swift in Sources */,
+				BD12B68122B4EF2600AEB10B /* KSMediaPickerViewVideoCell.swift in Sources */,
 				A7284A75225465DD000BAEC4 /* SwiftMoyaNetWorkServicePay.swift in Sources */,
 				A77F2CC722320627001BD3F6 /* WRNavigationBar.swift in Sources */,
 				A7274C5E228EE636000E3A07 /* LBXPermissions.swift in Sources */,
 				A7D46092227619CD00A5A54E /* BaiduToCityFactory.swift in Sources */,
 				A71AA51C227219EF008FF1A5 /* EditExpressAddressView.swift in Sources */,
+				BD12B68522B4F15300AEB10B /* KSMediaPickerCameraView.swift in Sources */,
 				BD1FC1A822B1075F00D55081 /* LXTextView.m in Sources */,
 				BDAA40FB228E9CC300CF841D /* OrderApplyRefundNoteInfoCell.swift in Sources */,
 				A7DF50D622A4E8B400998908 /* OrderDetailProductTableViewCell.swift in Sources */,
@@ -4026,12 +4222,14 @@
 				A72A72B722321DE000B21995 /* Extension+NSMutableAttributedString.swift in Sources */,
 				A7931E0D22AF874600297D0A /* GenderSelectionViewController.swift in Sources */,
 				A7C0FDF522B65FE000BC1E86 /* FeaturedTopicsCollectionViewCell.swift in Sources */,
+				BD28077E22B72797002AB976 /* PublishEditAddTopicCell.swift in Sources */,
 				A7F2D6D022B1119A0093000B /* CommunityEnum.swift in Sources */,
 				A7BB6857226965C100AB07A2 /* SelfRecommendationHeaderCollectionReusableView.swift in Sources */,
 				BDE3045F228554CA001D050F /* ProductCartAmountModel.swift in Sources */,
 				A7BB68672269B1DD00AB07A2 /* AddressPOIViewController.swift in Sources */,
 				A7284A7322546460000BAEC4 /* SwiftMoyaServicePayApi.swift in Sources */,
 				BDE3045D22851E4F001D050F /* ProductCartListModel.swift in Sources */,
+				BD12B68822B4F28F00AEB10B /* KSExtension.swift in Sources */,
 				A7A98DFF227E8501005306E9 /* SwiftMoyaNetWorkServiceProduct.swift in Sources */,
 				BDDF3B28228EBB72003A7D16 /* ProductRefundReasonModel.swift in Sources */,
 				A7CC74DC2270352F003C4F38 /* MineOrderCollectionViewCell.swift in Sources */,
@@ -4042,7 +4240,9 @@
 				A7CC74D822700359003C4F38 /* MineTableViewHeaderView.swift in Sources */,
 				A7931E1122AF989B00297D0A /* TopicSelectionViewController.swift in Sources */,
 				A71D2A602265673A00A55D16 /* RegisterLoginView.swift in Sources */,
+				BD12B6AC22B502C200AEB10B /* KSVideoPlayerBaseView.m in Sources */,
 				BD2FCBE422B244250006D974 /* RecommendDetailContentCell.swift in Sources */,
+				BD28078022B727A6002AB976 /* PublishEditAddAddressCell.swift in Sources */,
 				A73D7C682268A032002A4CE3 /* SwiftyStarRatingView.swift in Sources */,
 				A7931E0122AF827600297D0A /* ESTabBarItemContentView.swift in Sources */,
 				A71AA5102272156A008FF1A5 /* ExpressAddressListViewController.swift in Sources */,
@@ -4073,6 +4273,7 @@
 				A7CC75332271ABB0003C4F38 /* AddressManagerViewController.swift in Sources */,
 				A7FF158C228C911C00A85748 /* OrderRefunddetailsViewController.swift in Sources */,
 				A7CC750D227157DA003C4F38 /* MessageDetailesView.swift in Sources */,
+				BD12B67D22B4EE6D00AEB10B /* KSMediaPickerItemModel.swift in Sources */,
 				A7F2D6DD22B2536F0093000B /* CardContentPicVideoCollectionViewCell.swift in Sources */,
 				BD7AB83622841A8B0030646A /* ShoppingCartPayOrderItemCell.swift in Sources */,
 				A71AA519227219D7008FF1A5 /* EditExpressAddressViewController.swift in Sources */,
@@ -4095,12 +4296,15 @@
 				A729B5AD2266FF45004AE098 /* BindPhoneNumberView.swift in Sources */,
 				A75C474E22938B3900139C0C /* OrderFreightTableViewCell.swift in Sources */,
 				A7FF1592228C918100A85748 /* OrderRefunddetailsStatusTableViewCell.swift in Sources */,
+				BD12B67822B4ED9200AEB10B /* KSMediaPickerOutputModel.swift in Sources */,
 				A7CC74E62270628B003C4F38 /* DeliveryMethodTypeModel.swift in Sources */,
+				BD12B68322B4EFF000AEB10B /* KSMediaPickerView.swift in Sources */,
 				BDAF83A222B330540004BCC3 /* RecommendSimilarCell.swift in Sources */,
 				BDAA40FD228E9CD600CF841D /* OrderApplyRefundPhoneCell.swift in Sources */,
 				BD2FCBE222B21CF70006D974 /* CommunityRecommendController.swift in Sources */,
 				A71AA51F22729F35008FF1A5 /* AuthorizationSwift.swift in Sources */,
 				A7A98E3622802AD7005306E9 /* ShoppingMallBannerFSPagerViewCell.swift in Sources */,
+				BD12B6A222B4FC9B00AEB10B /* KSBorderButton.swift in Sources */,
 				BD12204E22AFB07E0051C7C2 /* MessageThumbController.swift in Sources */,
 				A7824AFD2271EAC900ABA381 /* SelfMentionContactsListTableViewCell.swift in Sources */,
 				BD7AB83F228438290030646A /* OrderPayExpressAddInfoCell.swift in Sources */,
@@ -4109,6 +4313,7 @@
 				A77F2CB92232010F001BD3F6 /* ShoppingCartViewController.swift in Sources */,
 				A72A72B822321DE000B21995 /* Extension+UserDefaults.swift in Sources */,
 				A719016B22757A5A00104A50 /* ProvinceCityAreaTableViewCell.swift in Sources */,
+				BD12B6AD22B502C200AEB10B /* KSVideoLayer.m in Sources */,
 				A729B5B72267270B004AE098 /* PasswordLoginView.swift in Sources */,
 				A7778CB82244E97A00C7C47A /* BindPhoneNumberViewController.swift in Sources */,
 				A754150F224CACF9002480B5 /* SwiftSign.swift in Sources */,
@@ -4123,6 +4328,7 @@
 				A7824B082271F53A00ABA381 /* EditSetDefaultTableViewCell.swift in Sources */,
 				A77F2CC3223203BA001BD3F6 /* AppDelegate+Window.swift in Sources */,
 				A7824B062271F25400ABA381 /* EditAddressTableViewCell.swift in Sources */,
+				BD12B69E22B4FAF000AEB10B /* KSMediaPickerNavigationView.swift in Sources */,
 				A70B2C4C228845E800B2449F /* ProductDetailParameterTableViewCell.swift in Sources */,
 				A7FF156A228C6E3600A85748 /* OrderProductTableViewCell.swift in Sources */,
 				A7931DF022AF4C9100297D0A /* BaseBouncesContentView.swift in Sources */,
@@ -4160,6 +4366,7 @@
 				A70B2C75228920BA00B2449F /* ProductDetailSkuSectionHeaerCollectionReusableView.swift in Sources */,
 				A7DF50D822A4FAFC00998908 /* ProductDetailEvaluationImageCollectionViewCell.swift in Sources */,
 				A7C0FDE922B4BC5600BC1E86 /* CardContentCommentListContentTableViewCell.swift in Sources */,
+				BD12B67C22B4EE6D00AEB10B /* KSMediaPickerAlbumModel.swift in Sources */,
 				A72843FC224DB6B800F82F30 /* SwiftMoyaServiceUserApi.swift in Sources */,
 				A7931DF122AF4C9100297D0A /* BaseIrregularityBasicContentView.swift in Sources */,
 				A7931DEF22AF4C9100297D0A /* BaseBasicContentView.swift in Sources */,
@@ -4168,6 +4375,7 @@
 				A7284A7722547333000BAEC4 /* AlipayResultModel.swift in Sources */,
 				A72A72B422321DE000B21995 /* Extension+UIImage.swift in Sources */,
 				A7BB68552268DE8600AB07A2 /* SelfRecommendationView.swift in Sources */,
+				BD12B69622B4F72900AEB10B /* KSMediaPickerPreviewView.swift in Sources */,
 				A7BF203122B47CC000396DB3 /* CardContentCommnetTableViewCell.swift in Sources */,
 				A72A72AF22321DE000B21995 /* AppInfo.swift in Sources */,
 				A70B843422911AF600882BC5 /* ProductDetailView.swift in Sources */,
@@ -4186,6 +4394,7 @@
 				A7CC75432271E038003C4F38 /* SelfMentionContactsListViewController.swift in Sources */,
 				BDF47D872282C92200941AB9 /* ShoppingCartListTableViewHeader.swift in Sources */,
 				A70B2C46228840B100B2449F /* ProductDetailHotSellTableViewCell.swift in Sources */,
+				BD12B69C22B4FAC800AEB10B /* KSMediaPickerRECButton.swift in Sources */,
 				A7778CDF22461BAD00C7C47A /* PhoneCountryAreaSectionHeaderView.swift in Sources */,
 				A7A98E2D22801642005306E9 /* SwiftMoyaServiceCMSApi.swift in Sources */,
 				A70B2C402288312900B2449F /* ProductDetailSectionHeader.swift in Sources */,
@@ -4199,6 +4408,7 @@
 				A71AA52822732173008FF1A5 /* SwiftMoyaNetWorkServiceConfig.swift in Sources */,
 				A70B2C732289019200B2449F /* ProductDetailSkuView.swift in Sources */,
 				A70B2C4322883B4E00B2449F /* ProductDetailShopTableViewCell.swift in Sources */,
+				BD28078222B727BD002AB976 /* PublishEditAddPicCell.swift in Sources */,
 				A70B2C102286A3BC00B2449F /* ProductDetailModel.swift in Sources */,
 				A7A17E5F22A0CEF200B7A77E /* SwiftMoyaNetWorkManagerTools.swift in Sources */,
 				A72A72A922321DE000B21995 /* NumberKeyboard.swift in Sources */,
@@ -4227,6 +4437,7 @@
 				A7C0FE0222B682DB00BC1E86 /* CommunityFeaturedTopicsHeaderView.swift in Sources */,
 				A7274C5F228EE636000E3A07 /* LBXScanWrapper.swift in Sources */,
 				A7CC752F2271A1F2003C4F38 /* SetPasswordView.swift in Sources */,
+				BD12B68E22B4F5DD00AEB10B /* KSMediaPickerCameraToolBar.swift in Sources */,
 				A7A98E09227EB8DD005306E9 /* CategoryView.swift in Sources */,
 				A7CC75362271AC14003C4F38 /* AddressManagerView.swift in Sources */,
 				A7146349228EFCE20066099B /* ORSKUDataFilter.m in Sources */,
@@ -4235,6 +4446,7 @@
 				A71901752275F71F00104A50 /* BaiduToCityModel.swift in Sources */,
 				BD12203F22AF8E190051C7C2 /* MessagePlanetNotiController.swift in Sources */,
 				A7BB685922696B9200AB07A2 /* SelfRecommendationCollectionViewCell.swift in Sources */,
+				BD12B69A22B4FA8400AEB10B /* KSMediaPickerSelectIndicator.swift in Sources */,
 				A7636AC822682BAF00374F9E /* LocationView.swift in Sources */,
 				A738D205225AF90D00EEE860 /* WeChatpayOrderModel.swift in Sources */,
 				A7F2D6BD22B09F930093000B /* CommunityNavigationBarView.swift in Sources */,
@@ -4248,6 +4460,7 @@
 				A7A98E05227EB891005306E9 /* CategoryViewController.swift in Sources */,
 				A7DF50E322A55AB600998908 /* BrowsePicturesPagerViewCell.swift in Sources */,
 				A77F2CC822320627001BD3F6 /* WRCustomNavigationBar.swift in Sources */,
+				BD12B6A322B4FC9B00AEB10B /* KSButton.swift in Sources */,
 				A7FF1564228C696B00A85748 /* OrderListView.swift in Sources */,
 				A7CC74EF22706CCA003C4F38 /* MessageView.swift in Sources */,
 				A70B2C072284305400B2449F /* ProductModel.swift in Sources */,
@@ -4270,6 +4483,7 @@
 				A7B4E73A228192D20012914A /* CMSTemplateModel.swift in Sources */,
 				A72A72C622321DE000B21995 /* WebView.swift in Sources */,
 				A72A72D122321E2700B21995 /* HTMLURLMacro.swift in Sources */,
+				BD12B6AB22B502C200AEB10B /* KSVideoPlayerLiteView.m in Sources */,
 				BD1FC1A622B1075F00D55081 /* LxButton.m in Sources */,
 				BD12B66922B47D4800AEB10B /* RecommendSubCommentCollectionCell.swift in Sources */,
 				BDF862A1228E41CC000DEF84 /* OrderLogisticsController.swift in Sources */,
@@ -4289,7 +4503,9 @@
 				A7CC74D6226FF421003C4F38 /* MineNavigationBarView.swift in Sources */,
 				BDAF83AA22B388F20004BCC3 /* RecommendDefaultBackCell.swift in Sources */,
 				A71AF0BC226F099B001730FE /* ProductHBigTableViewCell.swift in Sources */,
+				BD12B69122B4F60300AEB10B /* KSMediaPickerScrollView.m in Sources */,
 				BD108C9622A60C2100837DAB /* HGImagePickerCell.swift in Sources */,
+				BD28077822B721BF002AB976 /* PublishEditController.swift in Sources */,
 				A7A98E3C228036D7005306E9 /* ShoppingMallCategoryCollectionViewCell.swift in Sources */,
 				A7C0FDEB22B4C6C300BC1E86 /* CardContentCommentListFooterView.swift in Sources */,
 				BD3AA45822AE63EC00EF4F20 /* MessageMainViewController.swift in Sources */,
@@ -4304,9 +4520,11 @@
 				BD2FCBE622B2586C0006D974 /* CommunityTagCollectionCell.swift in Sources */,
 				BD1DC6C9228D005000B89C57 /* OrderCreateParameterModel.swift in Sources */,
 				A7BF203422B47E8600396DB3 /* CardContentActionTableViewCell.swift in Sources */,
+				BD12B68C22B4F4FF00AEB10B /* KSSegmentedControl.m in Sources */,
 				A71AA52622732068008FF1A5 /* SwiftMoyaServiceConfigApi.swift in Sources */,
 				A77F2C982231FD25001BD3F6 /* BaseNavigationViewController.swift in Sources */,
 				A7274C5D228EE636000E3A07 /* LBXScanViewStyle.swift in Sources */,
+				BD28077C22B72761002AB976 /* PublishEditDescribeCell.swift in Sources */,
 				A73911B3229ECE340033177E /* UICollectionViewLeftAlignedLayout.m in Sources */,
 				A7A98E1B227EEE49005306E9 /* SpecialView.swift in Sources */,
 				BDF47D7A228271F600941AB9 /* ShoppingCartView.swift in Sources */,
@@ -4326,6 +4544,7 @@
 				BDF862AE228E57E1000DEF84 /* OrderCommentDefaultCollectionCell.swift in Sources */,
 				A70B2C3E228825B100B2449F /* ProductDetailEvaluationTableViewCell.swift in Sources */,
 				A79057022276C9770037F823 /* SetPasswordModel.swift in Sources */,
+				BD12B68022B4EF2600AEB10B /* KSMediaPickerViewImageCell.swift in Sources */,
 				A7274C5A228EE636000E3A07 /* LBXScanView.swift in Sources */,
 				A7FF1560228C693D00A85748 /* OrderViewController.swift in Sources */,
 				A729B5B42267254B004AE098 /* PasswordLoginViewController.swift in Sources */,
@@ -4354,6 +4573,7 @@
 				A71AF0A6226EDDC8001730FE /* SearchViewController.swift in Sources */,
 				BD20F1CF2283CE2300677D8E /* OrderFinishPayView.swift in Sources */,
 				A7A98E4322804851005306E9 /* ShoppingMallSepcialFlowLayout.swift in Sources */,
+				BD12B69422B4F68400AEB10B /* KSMediaPickerCollectionView.m in Sources */,
 				BD12204122AF8E320051C7C2 /* MessagePlanetNotiTableCell.swift in Sources */,
 				A79057062276EA3D0037F823 /* OpenCityListModel.swift in Sources */,
 				BD7AB838228420310030646A /* ShoppingCartPayOrderHeader.swift in Sources */,
@@ -4387,8 +4607,10 @@
 				BD12204422AF996E0051C7C2 /* MessageCommentController.swift in Sources */,
 				A7778CDD2246121500C7C47A /* PhoneCountryAreaListMdoel.swift in Sources */,
 				A72A733522325A4B00B21995 /* AppDelegate+HandleOpen.swift in Sources */,
+				BD28077A22B72734002AB976 /* PublishEditTitleCell.swift in Sources */,
 				A7FF156E228C6EAE00A85748 /* OrderDeliveryModeTableViewCell.swift in Sources */,
 				A72A72AC22321DE000B21995 /* Regex.swift in Sources */,
+				BD12B67422B4EC9700AEB10B /* KSMediaPickerController.swift in Sources */,
 				A7778CC52246035700C7C47A /* PhoneCountryAreaViewController.swift in Sources */,
 				A72A72CF22321E2700B21995 /* NotificationCenterMacro.swift in Sources */,
 				A72A72BF22321DE000B21995 /* Extension+UIButton.swift in Sources */,

+ 2 - 0
RainbowPlanet/RainbowPlanet/Macro/ColorMacro.swift

@@ -135,3 +135,5 @@ let kfff8ecColor = UIColor(hexString: "fff8ec")
 let k62cc74Color = UIColor(hexString: "62cc74")
 
 let kFFF8ECColor = UIColor(hexString: "FFF8EC")
+
+let kDDDDDDColor = UIColor(hexString: "DDDDDD")

+ 9 - 0
RainbowPlanet/RainbowPlanet/Macro/RainbowPlanet-Bridging-Header.h

@@ -55,4 +55,13 @@
 #import "LXKeyBoard.h"
 
 
+//  KSMediaPicker所依靠的OC文件
+//#import "KSMediaViewerCell.h"
+#import "KSSegmentedControl.h"
+#import "KSMediaPickerScrollView.h"
+#import "KSMediaPickerCollectionView.h"
+#import "KSVideoPlayerLiteView.h"
+//#import "KSPageControl.h"
+
+
 #endif /* RainbowPlanet_Bridging_Header_h */

+ 128 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/Controller/PublishEditController.swift

@@ -0,0 +1,128 @@
+//
+//  PublishEditController.swift
+//  RainbowPlanet
+//
+//  Created by Christopher on 2019/6/17.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//  编辑发布Vc
+
+import UIKit
+import RxSwift
+import SwiftyJSON
+import Photos
+
+class PublishEditController: BaseViewController {
+    
+    // 上传图片数组
+    var goodsImageArr = Array<UIImage>()
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupViews()
+        setupData()
+    }
+    
+    override func setupViews() {
+        self.view.backgroundColor = kffffffColor
+        
+        navigationBar.title = ""
+        navigationBar.wr_setRightButton(title: "发布", titleColor: k333333Color)
+        navigationBar.onClickRightButton = {
+            [weak self] in
+            print("----点击了发布")
+        }
+        
+        self.view.addSubview(tableView)
+    }
+    
+    override func setupLayouts() {
+        tableView.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(kNavBarTotalHeight)
+            make.left.right.bottom.equalToSuperview()
+        }
+    }
+    
+    override func setupData() {
+        
+    }
+    
+    lazy var tableView: UITableView = {
+        let tableView = UITableView(frame: CGRect.zero, style: UITableView.Style.grouped)
+        tableView.separatorStyle = .none
+        tableView.backgroundColor = kffffffColor
+        tableView.dataSource = self
+        tableView.delegate = self
+        tableView.estimatedRowHeight = 0.000001
+        tableView.estimatedSectionFooterHeight = 0.000001
+        tableView.estimatedSectionHeaderHeight = 0.000001
+        return tableView
+    }()
+    
+}
+
+// MARK: - tableView dataSource && delegate
+extension PublishEditController : UITableViewDelegate, UITableViewDataSource {
+    
+    func numberOfSections(in tableView: UITableView) -> Int {
+        return 1
+    }
+    
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        return 5
+    }
+    
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        switch indexPath.row {
+        case 0:
+            let picCell = PublishEditAddPicCell.cellWith(tableView: tableView, indexPath: indexPath)
+            return picCell
+        case 1:
+            let titleCell = PublishEditTitleCell.cellWith(tableView: tableView, indexPath: indexPath)
+            return titleCell
+        case 2:
+            let desCell = PublishEditDescribeCell.cellWith(tableView: tableView, indexPath: indexPath)
+//            actCell.allSelectBlock = {
+//                [weak self] (isAllSel) in
+//                self?.isAllSelected = isAllSel
+//                self?.allSelectedAction(isAllSel)
+//            }
+            return desCell
+        case 3:
+            let topicCell = PublishEditAddTopicCell.cellWith(tableView: tableView, indexPath: indexPath)
+            return topicCell
+        case 4:
+            let addrCell = PublishEditAddAddressCell.cellWith(tableView: tableView, indexPath: indexPath)
+            return addrCell
+        default:
+            return UITableViewCell()
+        }
+    }
+    
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        switch indexPath.row {
+        case 1,3,4:
+            return 50
+        case 2:
+            return 190
+        default:
+            return UITableView.automaticDimension
+        }
+    }
+    
+    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+        return 0
+    }
+    
+    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+        return nil
+    }
+    
+    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
+        return 0.000001
+    }
+    
+    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+        return nil
+    }
+    
+}

+ 108 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditAddAddressCell.swift

@@ -0,0 +1,108 @@
+//
+//  PublishEditAddAddressCell.swift
+//  RainbowPlanet
+//
+//  Created by Christopher on 2019/6/17.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+
+class PublishEditAddAddressCell: UITableViewCell {
+    
+    class func cellWith(tableView:UITableView,indexPath:IndexPath) -> PublishEditAddAddressCell {
+        let ID = "PublishEditAddAddressCell"
+        tableView.register(PublishEditAddAddressCell.self, forCellReuseIdentifier: ID)
+        let cell : PublishEditAddAddressCell = tableView.dequeueReusableCell(withIdentifier: ID, for: indexPath) as! PublishEditAddAddressCell
+        cell.indexPath = indexPath
+        return cell
+    }
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        setupViews()
+        setupLayouts()
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var indexPath: IndexPath? {
+        didSet {
+            
+        }
+    }
+    
+    //MRAK: - 设置View
+    private func setupViews() {
+        self.selectionStyle = .none
+        backgroundColor = kffffffColor
+        
+        addSubview(iconImageView)
+        addSubview(titleLabel)
+        addSubview(contentLabel)
+        addSubview(timeLabel)
+    }
+    
+    private func setupLayouts() {
+        iconImageView.snp.makeConstraints { (make) in
+            make.top.equalTo(20)
+            make.left.equalTo(14)
+            make.size.equalTo(24)
+        }
+        titleLabel.snp.makeConstraints { (make) in
+            make.left.equalTo(iconImageView.snp_right).offset(10)
+            make.right.equalToSuperview().offset(-26)
+            make.centerY.equalTo(iconImageView)
+            make.height.equalTo(17)
+        }
+        contentLabel.snp.makeConstraints { (make) in
+            make.top.equalTo(titleLabel.snp_bottom).offset(12)
+            make.left.equalTo(titleLabel.snp_left)
+            make.right.equalToSuperview().offset(-26)
+        }
+        timeLabel.snp.makeConstraints { (make) in
+            make.top.equalTo(contentLabel.snp_bottom).offset(8)
+            make.left.equalTo(titleLabel.snp_left)
+            make.right.equalTo(contentLabel.snp_right)
+            make.height.equalTo(15)
+            make.bottom.equalToSuperview().offset(-20)
+        }
+    }
+    
+    lazy var iconImageView : UIImageView = {
+        let iconImageView = UIImageView()
+        iconImageView.image = kImage(name: "page05")
+        return iconImageView
+    }()
+    
+    private lazy var titleLabel: UILabel = {
+        let titleLabel = UILabel()
+        titleLabel.text = "张吃饭"
+        titleLabel.textColor = k999999Color
+        titleLabel.font = kRegularFont14
+        titleLabel.textAlignment = .left
+        return titleLabel
+    }()
+    
+    private lazy var contentLabel: UILabel = {
+        let contentLabel = UILabel()
+        contentLabel.text = "点击单条评时弹出选择操作框(目前仅支持回复),点击操作框后进行相应的操作"
+        contentLabel.textColor = k333333Color
+        contentLabel.font = kRegularFont14
+        contentLabel.textAlignment = .left
+        contentLabel.numberOfLines = 0
+        return contentLabel
+    }()
+    
+    private lazy var timeLabel: UILabel = {
+        let timeLabel = UILabel()
+        timeLabel.text = "6个小时前"
+        timeLabel.textColor = kbbbbbbColor
+        timeLabel.font = kRegularFont12
+        timeLabel.textAlignment = .left
+        return timeLabel
+    }()
+    
+}

+ 103 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditAddPicCell.swift

@@ -0,0 +1,103 @@
+//
+//  PublishEditAddPicCell.swift
+//  RainbowPlanet
+//
+//  Created by Christopher on 2019/6/17.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+import IQKeyboardManagerSwift
+
+class PublishEditAddPicCell: UITableViewCell {
+    
+    let disposeBag = DisposeBag()
+    
+    typealias NoteTextViewClosure = (_ text: String) -> Void
+    var noteTextViewClosure : NoteTextViewClosure?
+    
+    class func cellWith(tableView:UITableView,indexPath:IndexPath) -> PublishEditAddPicCell {
+        let ID = "PublishEditAddPicCell"
+        tableView.register(PublishEditAddPicCell.self, forCellReuseIdentifier: ID)
+        let cell : PublishEditAddPicCell = tableView.dequeueReusableCell(withIdentifier: ID, for: indexPath) as! PublishEditAddPicCell
+        cell.indexPath = indexPath
+        return cell
+    }
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        setupViews()
+        setupLayouts()
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var indexPath: IndexPath? {
+        didSet {
+            
+        }
+    }
+    //MRAK: - 设置View
+    private func setupViews() {
+        self.selectionStyle = .none
+        addSubview(titleLabel)
+        addSubview(noteTextView)
+    }
+    
+    private func setupLayouts() {
+        titleLabel.snp.makeConstraints { (make) in
+            make.top.left.equalTo(14)
+            make.width.equalTo(56)
+            make.height.equalTo(20)
+        }
+        noteTextView.snp.remakeConstraints { (make) in
+            make.top.equalTo(6).priority(999)
+            make.height.greaterThanOrEqualTo(46).priority(888)
+            make.bottom.equalTo(-6).priority(777)
+            make.left.equalTo(titleLabel.snp_right).offset(20)
+            make.right.equalToSuperview().offset(-14)
+        }
+    }
+    
+    lazy var titleLabel: UILabel = {
+        let titleLabel = UILabel()
+        titleLabel.textColor = k333333Color
+        titleLabel.font = kRegularFont14
+        titleLabel.text = "备注信息"
+        return titleLabel
+    }()
+    
+    lazy var noteTextView: IQTextView = {
+        let noteTextView = IQTextView()
+        noteTextView.backgroundColor = kffffffColor
+        noteTextView.textColor = k999999Color
+        noteTextView.font = kRegularFont14
+        noteTextView.placeholder = "如需部分商品退款请备注退款商品的名称和数量,如订单疑问可通过“我的”联系社长哦"
+        noteTextView.placeholderTextColor = k999999Color
+        noteTextView.isScrollEnabled = false
+        noteTextView.delegate = self
+        return noteTextView
+    }()
+    
+}
+
+extension PublishEditAddPicCell: UITextViewDelegate {
+    
+    func textViewDidChange(_ textView: UITextView) {
+        if textView == noteTextView {
+            var fullStr = textView.text ?? ""
+            if textView.text?.count ?? 0 > 180 {
+                fullStr = String(fullStr.prefix(150)) as String
+                textView.text = fullStr
+            }
+            
+            if let noteTextViewClosure = self.noteTextViewClosure {
+                noteTextViewClosure(self.noteTextView.text ?? "")
+            }
+        }
+    }
+    
+}

+ 85 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditAddTopicCell.swift

@@ -0,0 +1,85 @@
+//
+//  PublishEditAddTopicCell.swift
+//  RainbowPlanet
+//
+//  Created by Christopher on 2019/6/17.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+
+class PublishEditAddTopicCell: UITableViewCell {
+    
+    class func cellWith(tableView:UITableView,indexPath:IndexPath) -> PublishEditAddTopicCell {
+        let ID = "PublishEditAddTopicCell"
+        tableView.register(PublishEditAddTopicCell.self, forCellReuseIdentifier: ID)
+        let cell : PublishEditAddTopicCell = tableView.dequeueReusableCell(withIdentifier: ID, for: indexPath) as! PublishEditAddTopicCell
+        cell.indexPath = indexPath
+        return cell
+    }
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        setupViews()
+        setupLayouts()
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var indexPath: IndexPath? {
+        didSet {
+            
+        }
+    }
+    
+    //MRAK: - 设置View
+    private func setupViews() {
+        self.selectionStyle = .none
+        backgroundColor = kffffffColor
+        
+        addSubview(iconImageView)
+        
+    }
+    
+    private func setupLayouts() {
+        iconImageView.snp.makeConstraints { (make) in
+            make.top.equalTo(20)
+            make.left.equalTo(14)
+            make.size.equalTo(24)
+        }
+        
+    }
+    
+    lazy var iconImageView : UIImageView = {
+        let iconImageView = UIImageView()
+        iconImageView.image = kImage(name: "page05")
+        return iconImageView
+    }()
+    
+    private lazy var titleLabel: UILabel = {
+        let titleLabel = UILabel()
+        titleLabel.text = "添加话题"
+        titleLabel.textColor = k333333Color
+        titleLabel.font = kMediumFont14
+        titleLabel.textAlignment = .left
+        return titleLabel
+    }()
+    
+    private lazy var subLabel: UILabel = {
+        let subLabel = UILabel()
+        subLabel.text = "添加话题"
+        subLabel.textColor = k333333Color
+        subLabel.font = kMediumFont14
+        subLabel.textAlignment = .left
+        return subLabel
+    }()
+    
+    lazy var arrowImageView : UIImageView = {
+        let iconImageView = UIImageView()
+        iconImageView.image = kImage(name: "my_arrows_unfold")
+        return iconImageView
+    }()
+    
+}

+ 86 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditDescribeCell.swift

@@ -0,0 +1,86 @@
+//
+//  PublishEditDescribeCell.swift
+//  RainbowPlanet
+//
+//  Created by Christopher on 2019/6/17.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+import IQKeyboardManagerSwift
+
+class PublishEditDescribeCell: UITableViewCell {
+    
+    let disposeBag = DisposeBag()
+    
+    typealias CommentTextViewClosure = (_ text: String) -> Void
+    var commentTextViewClosure : CommentTextViewClosure?
+    
+    class func cellWith(tableView:UITableView,indexPath:IndexPath) -> PublishEditDescribeCell {
+        let ID = "PublishEditDescribeCell"
+        tableView.register(PublishEditDescribeCell.self, forCellReuseIdentifier: ID)
+        let cell : PublishEditDescribeCell = tableView.dequeueReusableCell(withIdentifier: ID, for: indexPath) as! PublishEditDescribeCell
+        cell.indexPath = indexPath
+        return cell
+    }
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        setupViews()
+        setupLayouts()
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var indexPath: IndexPath? {
+        didSet {
+            
+        }
+    }
+    
+    //MRAK: - 设置View
+    private func setupViews() {
+        self.selectionStyle = .none
+        
+        addSubview(cmtTextView)
+    }
+    
+    private func setupLayouts() {
+        cmtTextView.snp.makeConstraints { (make) in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    private lazy var cmtTextView: IQTextView = {
+        let cmtTextView = IQTextView()
+        cmtTextView.backgroundColor = kffffffColor
+        cmtTextView.textColor = k333333Color
+        cmtTextView.font = kRegularFont14
+        cmtTextView.placeholder = "说一说你的美好心得..."
+        cmtTextView.placeholderTextColor = k999999Color
+        cmtTextView.delegate = self
+        return cmtTextView
+    }()
+    
+}
+
+extension PublishEditDescribeCell: UITextViewDelegate {
+    
+    func textViewDidChange(_ textView: UITextView) {
+        if textView == cmtTextView {
+            var fullStr = textView.text ?? ""
+            if textView.text?.count ?? 0 > 180 {
+                fullStr = String(fullStr.prefix(150)) as String
+                textView.text = fullStr
+            }
+            
+            if let commentTextViewClosure = self.commentTextViewClosure {
+                commentTextViewClosure(self.cmtTextView.text ?? "")
+            }
+        }
+    }
+    
+}

+ 89 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishEditController/View/PublishEditTitleCell.swift

@@ -0,0 +1,89 @@
+//
+//  PublishEditTitleCell.swift
+//  RainbowPlanet
+//
+//  Created by Christopher on 2019/6/17.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+
+class PublishEditTitleCell: UITableViewCell {
+    
+    let disposeBag = DisposeBag()
+    
+    typealias EditTextFieldClosure = (_ text: String,_ indexPath:IndexPath) -> Void
+    var editTextFieldClosure : EditTextFieldClosure?
+    
+    class func cellWith(tableView:UITableView,indexPath:IndexPath) -> PublishEditTitleCell {
+        let ID = "PublishEditTitleCell"
+        tableView.register(PublishEditTitleCell.self, forCellReuseIdentifier: ID)
+        let cell : PublishEditTitleCell = tableView.dequeueReusableCell(withIdentifier: ID, for: indexPath) as! PublishEditTitleCell
+        cell.indexPath = indexPath
+        return cell
+    }
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        setupViews()
+        setupLayouts()
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var indexPath: IndexPath? {
+        didSet {
+            
+        }
+    }
+    
+    //MRAK: - 设置View
+    private func setupViews() {
+        self.selectionStyle = .none
+        addSubview(editTextField)
+        addSubview(h_lineLabel)
+    }
+    
+    private func setupLayouts() {
+        editTextField.snp.makeConstraints { (make) in
+            make.top.equalToSuperview()
+            make.bottom.equalToSuperview().offset(-1)
+            make.left.equalTo(14)
+            make.right.equalTo(-14)
+        }
+        h_lineLabel.snp.makeConstraints { (make) in
+            make.left.equalTo(editTextField.snp_left)
+            make.right.equalTo(editTextField.snp_right)
+            make.top.equalTo(editTextField.snp_top)
+            make.height.equalTo(0.5)
+        }
+    }
+    
+    private lazy var editTextField: UITextField = {
+        let editTextField = UITextField()
+        editTextField.textColor = k333333Color
+        editTextField.font = kRegularFont16
+        editTextField.tintColor = kEnabledButtonColor
+        editTextField.clearButtonMode = .whileEditing
+        editTextField.placeholder = "标题吸引人,收豆不求人(标题20字,内容详情页不限)"
+        editTextField.rx.text.orEmpty.changed.subscribe(onNext: {
+            [weak self] (text) in
+            self?.editTextField.text = String(describing: text.prefix(11))
+            if let editTextFieldClosure = self?.editTextFieldClosure {
+                editTextFieldClosure(self?.editTextField.text ?? "",(self?.indexPath!)!)
+            }
+            
+        }).disposed(by: disposeBag)
+        return editTextField
+    }()
+    
+    private lazy var h_lineLabel: UILabel = {
+        let h_lineLabel = UILabel()
+        h_lineLabel.backgroundColor = kf5f5f5Color
+        return h_lineLabel
+    }()
+    
+}

+ 551 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Controller/KSMediaPickerController.swift

@@ -0,0 +1,551 @@
+//
+//  KSMediaPickerController.swift
+// 
+//
+//  Created by kinsun on 2019/3/1.
+//
+
+import UIKit
+
+open class KSNavigationController: UINavigationController {
+    
+    override open func viewDidLoad() {
+        super.viewDidLoad()
+        view.sendSubviewToBack(navigationBar)
+    }
+}
+
+import Photos
+
+@objc public protocol KSMediaPickerControllerDelegate: NSObjectProtocol {
+    
+    @objc optional func mediaPicker(_ mediaPicker: KSMediaPickerController, didFinishSelected outputArray: [KSMediaPickerOutputModel])
+}
+
+open class KSMediaPickerController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
+    
+    @objc public enum mediaType : Int {
+        case all        = 0
+        case picture    = 1
+        case video      = 2
+    }
+    
+    @objc public let maxItemCount: UInt
+    @objc public let maxVideoItemCount: UInt
+    @objc public let maxPictureItemCount: UInt
+    @objc public let mediaType: KSMediaPickerController.mediaType
+    @objc open weak var delegate: KSMediaPickerControllerDelegate?
+    
+    /// 限制单一媒体类型混合显示构造函数,此函数为指定初始化器
+    ///
+    /// - Parameters:
+    ///   - maxVideoItemCount: 选择视频的最大数量
+    ///   - maxPictureItemCount: 选择图片的最大数量
+    @objc public init(maxVideoItemCount: UInt, maxPictureItemCount: UInt) {
+        if maxVideoItemCount == 0 {
+            self.mediaType = .picture
+        } else if maxPictureItemCount == 0 {
+            self.mediaType = .video
+        } else {
+            self.mediaType = .all
+        }
+        maxItemCount = maxVideoItemCount+maxPictureItemCount
+        self.maxPictureItemCount = maxPictureItemCount
+        self.maxVideoItemCount = maxVideoItemCount
+        super.init(nibName: nil, bundle: nil)
+    }
+    
+    /// 自由视频与图片构造函数,就是图片加视频的总数为maxItemCount,不对每种做限制只对总数做限制,此函数为指定初始化器
+    ///
+    /// - Parameter maxItemCount: 选择媒体的最大总数
+    @objc public init(maxItemCount: UInt = 9) {
+        self.mediaType = .all
+        self.maxItemCount = maxItemCount
+        maxPictureItemCount = 0
+        maxVideoItemCount = 0
+        super.init(nibName: nil, bundle: nil)
+    }
+    
+    @nonobjc required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    private static let k_image_item_class = KSMediaPickerViewImageCell.self
+    private static let k_video_item_class = KSMediaPickerViewVideoCell.self
+    private static let k_image_item_iden = NSStringFromClass(k_image_item_class)
+    private static let k_video_item_iden = NSStringFromClass(k_video_item_class)
+    
+    override open func loadView() {
+        let view = KSMediaPickerView()
+        
+        let nav = view.albumNavigationView
+        nav.closeButton.addTarget(self, action: #selector(_didClick(closeButton:)), for: .touchUpInside)
+        nav.nextButton.addTarget(self, action: #selector(_didClick(nextButton:)), for: .touchUpInside)
+        
+        let classObj = KSMediaPickerController.self
+        let collectionView = view.collectionView
+        collectionView.register(classObj.k_image_item_class, forCellWithReuseIdentifier: classObj.k_image_item_iden)
+        collectionView.register(classObj.k_video_item_class, forCellWithReuseIdentifier: classObj.k_video_item_iden)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        
+        let cameraView = view.cameraView
+        cameraView.didTakePhotoCallback = {[weak self] (cameraView, image) in
+            self?._didTakePhotoFinish(cameraView: cameraView, image: image)
+        }
+        cameraView.didTakeVideoCallback = {[weak self] (cameraView, fileURL) in
+            self?._didTakeVideoFinish(cameraView: cameraView, fileURL: fileURL)
+        }
+        let toolBar = cameraView.toolBar
+        toolBar.closeButton.addTarget(self, action: #selector(_didClick(closeButton:)), for: .touchUpInside)
+        toolBar.didChangedStyleCallback = { (style) in
+            UIApplication.shared.setStatusBarStyle(style == .lightContent ? .lightContent : .default, animated: true)
+        }
+        self.view = view
+    }
+    
+    override open func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        (view as! KSMediaPickerView).previewView.videoPause()
+    }
+    
+    override open func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        (view as! KSMediaPickerView).previewView.videoPlay()
+    }
+    
+    override open func viewDidLoad() {
+        super.viewDidLoad()
+        let cancelHandler: ((UIAlertAction) -> Void) = {[weak self] (action) in
+            self?._didClick(closeButton: nil)
+        }
+        KSMediaPickerController.authorityCheckUp(controller: self, type: .picture, completionHandler: {[weak self] (type) in
+            if let obj = self {
+                KSMediaPickerController.authorityCheckUp(controller: obj, type: .video, completionHandler: { (type) in
+                    KSMediaPickerController.authorityAudioCheckUp(controller: obj, completionHandler: {
+                        DispatchQueue.global().async {
+                            let assetCollections = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .any, options: nil)
+                            let regularAssetCollections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: nil)
+                            let array = [assetCollections, regularAssetCollections]
+                            self?._set(assetData: array)
+                        }
+                    }, cancelHandler: cancelHandler)
+                }, cancelHandler: cancelHandler)
+            }
+        }, cancelHandler: cancelHandler)
+    }
+    
+    private var _albumList: [KSMediaPickerAlbumModel]?
+    
+    private func _set(assetData: [PHFetchResult<PHAssetCollection>]) {
+        _albumList = KSMediaPickerAlbumModel.albumModel(from: assetData, mediaType: self.mediaType)
+        DispatchQueue.main.async(execute: _loadAssetDataFinish)
+    }
+    
+    private var _selectedAlbum: KSMediaPickerAlbumModel? {
+        didSet {
+            let view = self.view as! KSMediaPickerView
+            _updateHighlightedItemStatus()
+            if let itemModel = _selectedAlbum?.assetList.first {
+                let isStandard = _selectedAssetArray.count == 0 || itemModel == (_selectedAssetArray.firstObject as! KSMediaPickerItemModel)
+                view.previewView.set(itemModel: itemModel, isStandard: isStandard)
+                itemModel.isHighlight = true
+            }
+            _highlightedItemIndexPath = IndexPath(item: 0, section: 0)
+            view.collectionView.reloadData()
+        }
+    }
+    
+    private func _loadAssetDataFinish() {
+        _selectedAlbum = _albumList?.first
+    }
+    
+    @objc private func _didClick(closeButton: UIButton?) {
+//        navigationController?.dismiss(animated: true, completion: nil)
+        
+        print("----点击了返回")
+        navigationController?.popViewController(animated: true)
+    }
+    
+    @objc private func _didClick(nextButton: UIButton) {
+        (view as! KSMediaPickerView).previewView.saveCurrentState()
+        print("----选择完成,传递_selectedAssetArray")
+    }
+    
+    private func _didClickCell(collectionViewCell: KSMediaPickerViewImageCell) -> UInt {
+        guard let itemModel = collectionViewCell.itemModel, !itemModel.isLoseFocus else {
+            return 0
+        }
+        let indexPath = (view as! KSMediaPickerView).collectionView.indexPath(for: collectionViewCell)
+        if indexPath != nil {
+            _updateHighlightItem(at: indexPath!)
+        }
+        
+        if itemModel.index > 0 {
+            return _remove(itemModel: itemModel)
+        } else {
+            return _add(itemModel: itemModel)
+        }
+    }
+    
+    private func _didTakePhotoFinish(cameraView: KSMediaPickerCameraView, image: UIImage) {
+        var createdAssetID: String? = nil
+        try? PHPhotoLibrary.shared().performChangesAndWait {
+            let request = PHAssetChangeRequest.creationRequestForAsset(from: image)
+            createdAssetID = request.placeholderForCreatedAsset?.localIdentifier
+        }
+        guard let k_id = createdAssetID,
+            let asset = PHAsset.fetchAssets(withLocalIdentifiers: [k_id], options: nil).firstObject else {
+                return
+        }
+        _update(asset: asset)
+    }
+    
+    private func _didTakeVideoFinish(cameraView: KSMediaPickerCameraView, fileURL: URL) {
+        var createdAssetID: String? = nil
+        try? PHPhotoLibrary.shared().performChangesAndWait {
+            let request = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: fileURL)
+            createdAssetID = request?.placeholderForCreatedAsset?.localIdentifier
+        }
+        guard let k_id = createdAssetID,
+            let asset = PHAsset.fetchAssets(withLocalIdentifiers: [k_id], options: nil).firstObject else {
+                return
+        }
+        _update(asset: asset)
+    }
+    
+    private func _update(asset: PHAsset) {
+        _updateHighlightedItemStatus()
+        let itemModel = KSMediaPickerItemModel(asset)
+        itemModel.isHighlight = true
+        _selectedAlbum?.assetList.insert(itemModel, at: 0)
+        let indexPath = IndexPath(item: 0, section: 0)
+        _highlightedItemIndexPath = indexPath
+        let isStandard = _selectedAssetArray.count == 0 || itemModel == (_selectedAssetArray.firstObject as! KSMediaPickerItemModel)
+        let view = self.view as! KSMediaPickerView
+        view.previewView.set(itemModel: itemModel, isStandard: isStandard)
+        let collectionView = view.collectionView
+        collectionView.performBatchUpdates({
+            collectionView.insertItems(at: [indexPath])
+        }) {[weak self] (finished) in
+            let index = self?._add(itemModel: itemModel) ?? 0
+            if index > 0 {
+                itemModel.index = index
+            } else {
+                itemModel.isLoseFocus = true
+            }
+            collectionView.reloadItems(at: [indexPath])
+            view.collectionViewScrollToTop()
+            view.didClick(segmentedControl: view.segmentedControl, index: 0)
+        }
+    }
+    
+    private lazy var _selectedAssetArray = NSMutableArray(capacity: Int(maxItemCount))
+    
+    private func _add(itemModel: KSMediaPickerItemModel) -> UInt {
+        let selectedAssetArray = _selectedAssetArray
+        let count = UInt(selectedAssetArray.count)
+        var k_maxItemCount = maxItemCount
+        let assetMediaType = (selectedAssetArray.firstObject as? KSMediaPickerItemModel)?.asset.mediaType ?? itemModel.asset.mediaType
+        var isSingleType = false
+        if self.mediaType == .all {
+            if assetMediaType == .video && maxVideoItemCount != 0 {
+                k_maxItemCount = maxVideoItemCount
+                _currentSingleType = .video
+            } else if assetMediaType == .image && maxPictureItemCount != 0 {
+                k_maxItemCount = maxPictureItemCount
+                _currentSingleType = .picture
+            }
+            if _currentSingleType != nil && count == 0 {
+                isSingleType = true
+            }
+        }
+        guard count < k_maxItemCount else {
+            return 0
+        }
+        selectedAssetArray.add(itemModel)
+        let lastCount = count+1
+        let isLastItem = lastCount == k_maxItemCount
+        let view = self.view as! KSMediaPickerView
+        if isSingleType || isLastItem {
+            let assetList = _selectedAlbum!.assetList
+            var indexPaths = Array<IndexPath>()
+            for (i, k_itemModel) in assetList.enumerated() {
+                let isOk = (isSingleType && k_itemModel.asset.mediaType != assetMediaType) || (isLastItem && !selectedAssetArray.contains(k_itemModel))
+                if isOk && !k_itemModel.isLoseFocus {
+                    k_itemModel.isLoseFocus = true
+                    let indexPath = IndexPath(item: i, section: 0)
+                    indexPaths.append(indexPath)
+                }
+            }
+            
+            let collectionView = view.collectionView
+            collectionView.performBatchUpdates({
+                collectionView.reloadItems(at: indexPaths)
+            }, completion: nil)
+            //FIXME: disable
+//            view.albumNavigationView.centerButton.isEnabled = !isLastItem
+        }
+        view.albumNavigationView.nextButton.isEnabled = lastCount > 0
+        return lastCount
+    }
+    
+    private var _currentSingleType: KSMediaPickerController.mediaType?
+    
+    private func _remove(itemModel: KSMediaPickerItemModel) -> UInt {
+        let selectedAssetArray = _selectedAssetArray
+        let index = selectedAssetArray.index(of: itemModel)
+        let count = selectedAssetArray.count
+        guard index >= 0, index < count else {
+            return 0
+        }
+        itemModel.index = 0
+        selectedAssetArray.removeObject(at: index)
+        
+        let view = self.view as! KSMediaPickerView
+        let assetMediaType = itemModel.asset.mediaType
+        var k_maxItemCount = maxItemCount
+        var needUpdateSingleType = false
+        let isSingleType = _currentSingleType != nil
+        if isSingleType {
+            if _currentSingleType! == .video {
+                k_maxItemCount = maxVideoItemCount
+            } else if _currentSingleType! == .picture {
+                k_maxItemCount = maxPictureItemCount
+            }
+            needUpdateSingleType = count == 1
+        }
+        let needUpdateIndexNumber = index != count-1
+        let needUpdateFocus = count == k_maxItemCount
+        if needUpdateIndexNumber && needUpdateFocus {
+            let assetList = _selectedAlbum!.assetList
+            var j = Int(1)
+            for k_itemModel in assetList {
+                if selectedAssetArray.contains(k_itemModel) {
+                    k_itemModel.index = UInt(j)
+                    j += 1
+                } else {
+                    let ok = isSingleType ? (assetMediaType == k_itemModel.asset.mediaType) : true
+                    if (needUpdateSingleType || (ok && k_itemModel.isLoseFocus)) {
+                        k_itemModel.isLoseFocus = false
+                    }
+                }
+            }
+            let collectionView = view.collectionView
+            collectionView.reloadData()
+        } else if needUpdateIndexNumber {
+            let assetList = _selectedAlbum!.assetList as NSArray
+            let assetListCount = assetList.count
+            var indexPaths = Array<IndexPath>()
+            for (i, k_itemModel) in selectedAssetArray.enumerated() {
+                let l_itemModel = k_itemModel as! KSMediaPickerItemModel
+                l_itemModel.index = UInt(i+1)
+                let k_index = assetList.index(of: l_itemModel)
+                if k_index >= 0 && k_index < assetListCount {
+                    let indexPath = IndexPath(item: k_index, section: 0)
+                    indexPaths.append(indexPath)
+                }
+            }
+            let collectionView = view.collectionView
+            collectionView.performBatchUpdates({
+                collectionView.reloadItems(at: indexPaths)
+            }, completion: nil)
+        } else {
+            let collectionView = view.collectionView
+            let assetList = _selectedAlbum!.assetList
+            if needUpdateSingleType {
+                for k_itemModel in assetList {
+                    k_itemModel.isLoseFocus = false
+                }
+                collectionView.reloadData()
+            } else if needUpdateFocus {
+                var indexPaths = Array<IndexPath>()
+                for (i, k_itemModel) in assetList.enumerated() {
+                    let ok = isSingleType ? (assetMediaType == k_itemModel.asset.mediaType) : true
+                    if (ok && k_itemModel.isLoseFocus) {
+                        k_itemModel.isLoseFocus = false
+                        let indexPath = IndexPath(item: i, section: 0)
+                        indexPaths.append(indexPath)
+                    }
+                }
+                collectionView.performBatchUpdates({
+                    collectionView.reloadItems(at: indexPaths)
+                }, completion: nil)
+            }
+        }
+        let albumNavigationView = view.albumNavigationView
+        //FIXME: disable
+//        albumNavigationView.centerButton.isEnabled = true
+        albumNavigationView.nextButton.isEnabled = selectedAssetArray.count > 0
+        return 0
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return _selectedAlbum?.assetList.count ?? 0
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        let itemModel = _selectedAlbum?.assetList[indexPath.item]
+        let mediaType = itemModel?.asset.mediaType
+        let isPictureCell = mediaType == .image
+        let iden = isPictureCell ? KSMediaPickerController.k_image_item_iden : KSMediaPickerController.k_video_item_iden
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: iden, for: indexPath) as! KSMediaPickerViewImageCell
+        if cell.didSelectedItem == nil {
+            cell.didSelectedItem = {[weak self] (collectionViewCell) -> UInt in
+                return self?._didClickCell(collectionViewCell: collectionViewCell) ?? 0
+            }
+            cell.isMultipleSelected = maxItemCount > 1
+        }
+        cell.itemModel = itemModel
+        return cell
+    }
+    
+    private var _highlightedItemIndexPath: IndexPath?
+    
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        collectionView.deselectItem(at: indexPath, animated: true)
+        _updateHighlightItem(at: indexPath)
+    }
+    
+    private func _updateHighlightItem(at indexPath: IndexPath) {
+        let view = self.view as! KSMediaPickerView
+        guard indexPath != _highlightedItemIndexPath,
+            let cell = view.collectionView.cellForItem(at: indexPath) as? KSMediaPickerViewImageCell,
+            let itemModel = cell.itemModel,
+            !itemModel.isLoseFocus else {
+                return
+        }
+        let isStandard = _selectedAssetArray.count == 0 || itemModel == (_selectedAssetArray.firstObject as! KSMediaPickerItemModel)
+        let previewView = view.previewView
+        previewView.set(itemModel: itemModel, isStandard: isStandard)
+        ///滚动至选择item区域
+        let collectionView = view.collectionView
+        let top = collectionView.contentInset.top
+        var frame = collectionView.frame
+        frame.origin.y = top
+        frame.size.height -= top
+        let cellFrame = cell.frame
+        let frameInSuper = collectionView.convert(cellFrame, to: view)
+        if !frame.contains(frameInSuper) {
+            var point = CGPoint(x: 0.0, y: cellFrame.origin.y-top)
+            let contentSizeHeight = collectionView.contentSize.height
+            if cellFrame.maxY >= contentSizeHeight {
+                point.y = contentSizeHeight-collectionView.bounds.size.height
+            }
+            collectionView.setContentOffset(point, animated: true)
+        }
+        ///滚动至选择item区域end
+        view.showPreview(true)
+        
+        _updateHighlightedItemStatus()
+        
+        itemModel.isHighlight = true
+        cell.itemIsHighlight = true
+        _highlightedItemIndexPath = indexPath
+    }
+    
+    private func _updateHighlightedItemStatus() {
+        guard let indexPath = _highlightedItemIndexPath else {
+            return
+        }
+        let highlightedItemModel: KSMediaPickerItemModel
+        let highlightedCell = (view as! KSMediaPickerView).collectionView.cellForItem(at: indexPath) as? KSMediaPickerViewImageCell
+        if highlightedCell == nil {
+            highlightedItemModel = _selectedAlbum!.assetList[indexPath.item]
+        } else {
+            highlightedItemModel = highlightedCell!.itemModel
+            highlightedCell?.itemIsHighlight = false
+        }
+        highlightedItemModel.isHighlight = false
+    }
+    
+}
+
+extension KSMediaPickerController {
+    
+    open class func authorityCheckUp(controller: UIViewController, type: KSMediaPickerController.mediaType, completionHandler: @escaping ((KSMediaPickerController.mediaType) -> Void), cancelHandler: ((UIAlertAction) -> Void)?) {
+        switch type {
+        case .picture:
+            let authorization = {(status: PHAuthorizationStatus) in
+                switch status {
+                case .authorized:
+                    completionHandler(type)
+                    break
+                case .denied:
+                    authorityAlert(controller: controller, name: "IMAGE_PICKER_PHOTOS".ks_mediaPickerKeyToLocalized, cancelHandler: cancelHandler)
+                    break
+                default:
+                    break
+                }
+            }
+            let status = PHPhotoLibrary.authorizationStatus()
+            if status == .notDetermined {
+                PHPhotoLibrary.requestAuthorization(authorization)
+            } else {
+                authorization(status)
+            }
+            break
+        case .video:
+            let authorization = {(granted: Bool) in
+                if granted {
+                    completionHandler(type)
+                } else {
+                    authorityAlert(controller: controller, name: "IMAGE_PICKER_CAMERA".ks_mediaPickerKeyToLocalized, cancelHandler: cancelHandler)
+                }
+            }
+            let mediaType = AVMediaType.video
+            let status = AVCaptureDevice.authorizationStatus(for: mediaType)
+            if status == .notDetermined {
+                AVCaptureDevice.requestAccess(for: mediaType, completionHandler: authorization)
+            } else {
+                authorization(status == .authorized)
+            }
+            break
+        default :
+            break
+        }
+    }
+    
+    open class func authorityAlert(controller: UIViewController, name: String, cancelHandler: ((UIAlertAction) -> Void)?) {
+        let bundle = Bundle.main
+        let appName = NSLocalizedString("CFBundleDisplayName", tableName: "InfoPlist", bundle: bundle, comment: "")
+        let title = String(format: "IMAGE_PICKER_NONAUTHORITY_TITLE_FORMAT".ks_mediaPickerKeyToLocalized(in: bundle), name)
+        let message = String(format: "IMAGE_PICKER_NONAUTHORITY_TIP_FORMAT".ks_mediaPickerKeyToLocalized(in: bundle), appName, name)
+        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
+        let go = UIAlertAction(title: "IMAGE_PICKER_NONAUTHORITY_GO_SETTING".ks_mediaPickerKeyToLocalized(in: bundle), style: .default) { (action) in
+            let application = UIApplication.shared
+            let url = URL(string: UIApplication.openSettingsURLString)!
+            if application.canOpenURL(url) {
+                if #available(iOS 10.0, *) {
+                    application.open(url, options: [.universalLinksOnly: false], completionHandler: nil)
+                } else {
+                    application.openURL(url)
+                }
+                if cancelHandler != nil {
+                    cancelHandler!(action)
+                }
+            }
+        }
+        alert.addAction(go)
+        let cancel = UIAlertAction(title: "CANCEL".ks_mediaPickerKeyToLocalized(in: bundle), style: .cancel, handler: cancelHandler)
+        alert.addAction(cancel)
+        controller.present(alert, animated: true, completion: nil)
+    }
+    
+    open class func authorityAudioCheckUp(controller: UIViewController, completionHandler: @escaping (() -> Void), cancelHandler: ((UIAlertAction) -> Void)?) {
+        let authorization = {(granted: Bool) in
+            if granted {
+                completionHandler()
+            } else {
+                authorityAlert(controller: controller, name: "IMAGE_PICKER_MICROPHONE".ks_mediaPickerKeyToLocalized, cancelHandler: cancelHandler)
+            }
+        }
+        let mediaType = AVMediaType.audio
+        let status = AVCaptureDevice.authorizationStatus(for: mediaType)
+        if status == .notDetermined {
+            AVCaptureDevice.requestAccess(for: mediaType, completionHandler: authorization)
+        } else {
+            authorization(status == .authorized)
+        }
+    }
+}

+ 65 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSButton/KSBorderButton.swift

@@ -0,0 +1,65 @@
+//
+//  KSBorderButton.swift
+//  KSMediaPickerDemo
+//
+//  Created by kinsun on 2019/5/8.
+//  Copyright © 2019年 kinsun. All rights reserved.
+//
+
+import UIKit
+
+open class KSBorderButton: KSButton {
+    
+    private var _colors = {() -> [UIControl.State.RawValue: CGColor] in
+        let state = UIControl.State.self
+        return [state.normal.rawValue: UIColor.ks_white.cgColor,
+                state.highlighted.rawValue: UIColor.ks_lightGray.cgColor,
+                state.disabled.rawValue: UIColor.ks_lightGray.cgColor]
+    }()
+    
+    @objc open func setBorderColor(_ borderColor: UIColor?, for state: UIControl.State) {
+        if borderColor == nil {
+            _colors.removeValue(forKey: state.rawValue)
+            if self.state == state {
+                layer.borderColor = UIColor.clear.cgColor
+            }
+        } else {
+            let cgColor = borderColor!.cgColor
+            _colors[state.rawValue] = cgColor
+            if self.state == state {
+                layer.borderColor = cgColor
+            }
+        }
+    }
+    
+    @objc open func borderColor(for state: UIControl.State) -> UIColor? {
+        if let color = _borderColor(for: state) {
+            return UIColor(cgColor: color)
+        } else {
+            return nil
+        }
+    }
+    
+    private func _borderColor(for state: UIControl.State) -> CGColor? {
+        return _colors[state.rawValue]
+    }
+    
+    open override var isEnabled: Bool {
+        didSet {
+            layer.borderColor = _borderColor(for: state) ?? _borderColor(for: .normal)
+        }
+    }
+    
+    open override var isHighlighted: Bool {
+        didSet {
+            layer.borderColor = _borderColor(for: state) ?? _borderColor(for: .normal)
+        }
+    }
+    
+    open override var isSelected: Bool {
+        didSet {
+            layer.borderColor = _borderColor(for: state) ?? _borderColor(for: .normal)
+        }
+    }
+
+}

+ 52 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSButton/KSButton.swift

@@ -0,0 +1,52 @@
+//
+//  KSButton.swift
+//  KSMediaPickerDemo
+//
+//  Created by kinsun on 2019/5/8.
+//  Copyright © 2019年 kinsun. All rights reserved.
+//
+
+import UIKit
+
+open class KSButton: UIButton {
+    
+    private var _colors = {() -> [UIControl.State.RawValue: UIColor] in
+        let state = UIControl.State.self
+        return [state.normal.rawValue: UIColor.ks_white,
+                state.highlighted.rawValue: UIColor.ks_lightGray,
+                state.disabled.rawValue: UIColor.ks_lightGray]
+    }()
+    
+    @objc open func setBackgroundColor(_ backgroundColor: UIColor?, for state: UIControl.State) {
+        if backgroundColor == nil {
+            _colors.removeValue(forKey: state.rawValue)
+        } else {
+            _colors[state.rawValue] = backgroundColor!
+        }
+        if self.state == state {
+            self.backgroundColor = backgroundColor
+        }
+    }
+    
+    @objc open func backgroundColor(for state: UIControl.State) -> UIColor? {
+        return _colors[state.rawValue]
+    }
+
+    open override var isEnabled: Bool {
+        didSet {
+            backgroundColor = backgroundColor(for: state) ?? backgroundColor(for: .normal)
+        }
+    }
+    
+    open override var isHighlighted: Bool {
+        didSet {
+            backgroundColor = backgroundColor(for: state) ?? backgroundColor(for: .normal)
+        }
+    }
+    
+    open override var isSelected: Bool {
+        didSet {
+            backgroundColor = backgroundColor(for: state) ?? backgroundColor(for: .normal)
+        }
+    }
+}

+ 184 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSExtension.swift

@@ -0,0 +1,184 @@
+//
+//  KSExtension.swift
+//  KSMediaPickerDemo
+//
+//  Created by kinsun on 2019/4/29.
+//  Copyright © 2019年 kinsun. All rights reserved.
+//
+
+import UIKit
+
+extension String {
+
+    public var ks_KeyToLocalized: String {
+        return ks_KeyToLocalized(in: Bundle.main)
+    }
+    
+    public var ks_mediaPickerKeyToLocalized: String {
+        return ks_mediaPickerKeyToLocalized(in: Bundle.main)
+    }
+    
+    public func ks_mediaPickerKeyToLocalized(in bundle: Bundle, table: String? = "KSMediaPicker") -> String {
+        return ks_KeyToLocalized(in: bundle, table: table)
+    }
+    
+    public func ks_KeyToLocalized(in bundle: Bundle, table: String? = nil) -> String {
+        return bundle.localizedString(forKey: self, value: nil, table: table)
+    }
+    
+}
+
+extension UIEdgeInsets {
+    
+    static public let safeAreaInsets = {() -> UIEdgeInsets in
+        let safeAreaInsets: UIEdgeInsets
+        if #available(iOS 11.0, *) {
+            safeAreaInsets = UIApplication.shared.keyWindow?.safeAreaInsets ?? .zero
+        } else {
+            safeAreaInsets = .zero
+        }
+        return safeAreaInsets
+    }()
+    
+}
+
+extension UIView {
+    
+    public static let statusBarSize = UIApplication.shared.statusBarFrame.size
+    public static let navigationBarSize = CGSize(width: statusBarSize.width, height: 44.0)
+    public static let statusBarNavigationBarSize = {() -> CGSize in
+        var size = statusBarSize
+        size.height += navigationBarSize.height
+        return size
+    }()
+    
+    open var renderingImage: UIImage? {
+        UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0)
+        let image: UIImage?
+        if let ctx = UIGraphicsGetCurrentContext() {
+            layer.render(in: ctx)
+            image = UIGraphicsGetImageFromCurrentImageContext()
+        } else {
+            image = nil
+        }
+        UIGraphicsEndImageContext()
+        return image
+    }
+    
+}
+
+extension UIImage {
+    
+    static public let ks_defaultPlaceholder = UIImage(named: "img_default_placeholder")!
+    
+    public convenience init(JPEGData: Data, of cutSizeProportion: CGSize) {
+        let dataRef = CFBridgingRetain(JPEGData) as! CFData
+        let source = CGImageSourceCreateWithData(dataRef, nil)!
+        let imageInfoRef = CGImageSourceCopyPropertiesAtIndex(source, 0, nil)!
+        let pixelHeightKey = Unmanaged.passRetained(NSString(string: "PixelHeight")).autorelease().toOpaque()
+        let pixelWidthKey = Unmanaged.passRetained(NSString(string: "PixelWidth")).autorelease().toOpaque()
+        let pixelHeightPoint = CFDictionaryGetValue(imageInfoRef, pixelHeightKey)!
+        let pixelWidthPoint = CFDictionaryGetValue(imageInfoRef, pixelWidthKey)!
+        let windowHeight = CGFloat(Unmanaged<NSNumber>.fromOpaque(pixelHeightPoint).takeUnretainedValue().doubleValue)
+        let windowWidth = CGFloat(Unmanaged<NSNumber>.fromOpaque(pixelWidthPoint).takeUnretainedValue().doubleValue)
+        let viewH = windowHeight
+        let viewW = cutSizeProportion.height/cutSizeProportion.width*viewH
+        let rect = CGRect(x: (windowWidth-viewW)*0.5, y: 0.0, width: viewW, height: viewH)
+        let cgData = CGDataProvider(data: dataRef)!
+        let cgImage = CGImage(jpegDataProviderSource: cgData, decode: nil, shouldInterpolate: true, intent: .defaultIntent)!
+        let newCgImage = cgImage.cropping(to: rect)!
+//        let newImageData = CFDataCreateMutable(kCFAllocatorDefault, 0)!
+//        let destination = CGImageDestinationCreateWithData(newImageData, "public.jpeg" as CFString, 1, nil)!
+        let newImageData = NSMutableData()
+        let destination = CGImageDestinationCreateWithData(CFBridgingRetain(newImageData) as! CFMutableData, "public.jpeg" as CFString, 1, nil)!
+        let newImageInfoRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(imageInfoRef), imageInfoRef)!
+        CFDictionaryReplaceValue(newImageInfoRef, pixelHeightKey, Unmanaged.passRetained(NSNumber(value: Double(viewH))).autorelease().toOpaque())
+        CFDictionaryReplaceValue(newImageInfoRef, pixelWidthKey, Unmanaged.passRetained(NSNumber(value: Double(viewW))).autorelease().toOpaque())
+        CGImageDestinationAddImage(destination, newCgImage, newImageInfoRef)
+        CGImageDestinationFinalize(destination)
+        self.init(data: newImageData as Data)!
+    }
+    
+    public func cut(from rect: CGRect) -> UIImage? {
+        if let cgImage = self.cgImage {
+            var newRect = rect
+            let scale = self.scale
+            newRect.origin.x *= scale
+            newRect.origin.y *= scale
+            newRect.size.width *= scale
+            newRect.size.height *= scale
+            
+            if let newCgImage = cgImage.cropping(to: newRect) {
+                return UIImage(cgImage: newCgImage)
+            }
+        }
+        return nil
+    }
+    
+    public func aspectFit(from size: CGSize, backgroundColor: UIColor = .clear) -> UIImage? {
+        let imageSize = self.size
+        let imageWidth = floor(imageSize.width)
+        let imageHeight = floor(imageSize.height)
+        let windowWidth = floor(size.width)
+        let windowHeight = floor(size.height)
+        if imageWidth == windowWidth, imageHeight == windowHeight {
+            return self
+        } else {
+            let rect: CGRect
+            let imageScale = imageWidth/imageHeight
+            let windowScale = windowWidth/windowHeight
+            if imageScale > windowScale {
+                let height = floor(imageHeight*windowWidth/imageWidth)
+                rect = CGRect(x: 0.0, y: (windowHeight-height)*0.5, width: windowWidth, height: height)
+            } else {
+                let width = floor(imageWidth*windowHeight/imageHeight)
+                rect = CGRect(x: (windowWidth-width)*0.5, y: 0.0, width: width, height: windowHeight)
+            }
+            UIGraphicsBeginImageContextWithOptions(size, false, 0)
+            let context = UIGraphicsGetCurrentContext()
+            //        CGContextScaleCTM(context, scale, scale)
+            context?.setFillColor(backgroundColor.cgColor)
+            context?.addRect(CGRect(origin: .zero, size: size))
+            context?.drawPath(using: .fill)
+            draw(in: rect)
+            let newImage = UIGraphicsGetImageFromCurrentImageContext()
+            UIGraphicsEndImageContext()
+            return newImage
+        }
+    }
+    
+    public func resize(_ newSize: CGSize) -> UIImage? {
+        UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
+        draw(in: CGRect(origin: .zero, size: newSize))
+        let newImage = UIGraphicsGetImageFromCurrentImageContext()
+        UIGraphicsEndImageContext()
+        return newImage
+    }
+    
+    public func equalResize(sideLength: CGFloat) -> UIImage? {
+        let size = self.size
+        let width = size.width
+        let height = size.height
+        let newSize: CGSize
+        if width == height {
+            newSize = CGSize(width: sideLength, height: sideLength)
+        } else if width > height {
+            newSize = CGSize(width: width/height*sideLength, height: sideLength)
+        } else {
+            newSize = CGSize(width: sideLength, height: height/width*sideLength)
+        }
+        return resize(newSize)
+    }
+}
+
+extension UIColor {
+    
+    public static let ks_wordMain = UIColor(red: 44/255.0, green: 41/255.0, blue: 84/255.0, alpha: 1)
+    public static let ks_wordMain_2 = UIColor(red: 44/255.0, green: 41/255.0, blue: 84/255.0, alpha: 0.5)
+    public static let ks_background = UIColor(red: 248/255.0, green: 248/255.0, blue: 248/255.0, alpha: 1)
+    public static let ks_main = UIColor(red: 255/255.0, green: 84/255.0, blue: 65/255.0, alpha: 1)
+    public static let ks_lightMain = UIColor(red: 240/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1)
+    public static let ks_lightGray = UIColor(red: 234/255.0, green: 234/255.0, blue: 234/255.0, alpha: 1)
+    public static let ks_white = UIColor.white
+    public static let ks_black = UIColor.black
+}

+ 26 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSLayout.h

@@ -0,0 +1,26 @@
+//
+//  KSLayout.h
+//
+//  Created by kinsun on 2018/10/29.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#ifndef KSLayout_h
+#define KSLayout_h
+
+#define k_creatFrameElement     CGFloat viewX=0.f, viewY=0.f, viewW=0.f, viewH=0.f
+#define k_setFrame              (CGRect){viewX, viewY, viewW, viewH}
+#define k_settingFrame(view)    (view).frame = k_setFrame
+#define k_creatWindowSizeElement(width, height) CGFloat windowWidth = (width), windowHeight = (height)
+#define k_creatSizeElementOfSize(size)  k_creatWindowSizeElement((size).width, (size).height)
+#define k_creatSelfSizeElement CGSize kkkk_size = self.bounds.size;\
+k_creatSizeElementOfSize(kkkk_size)
+
+//全局屏幕相关
+#define k_MAIN_SCREEN   UIScreen.mainScreen
+#define k_SCREEN_BOUNDS k_MAIN_SCREEN.bounds
+#define k_SCREEN_WIDTH  k_SCREEN_BOUNDS.size.width
+#define k_SCREEN_HEIGHT k_SCREEN_BOUNDS.size.height
+#define k_SCREEN_SCALE  k_MAIN_SCREEN.scale
+
+#endif /* KSLayout_h */

+ 22 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSMediaPicker.strings

@@ -0,0 +1,22 @@
+/* 
+  KSMediaPicker.strings
+  KSMediaPickerDemo
+
+  Created by kinsun on 2019/4/29.
+  Copyright © 2019年 kinsun. All rights reserved.
+*/
+
+NEXT = "下一步";
+
+IMAGE_PICKER_PHOTOS = "照片";
+IMAGE_PICKER_CAMERA = "照相机";
+IMAGE_PICKER_MICROPHONE = "麦克风";
+IMAGE_PICKER_NONAUTHORITY_TITLE_FORMAT = "没有打开“%@”访问权限";
+IMAGE_PICKER_NONAUTHORITY_TIP_FORMAT = "请进入“设置”-“%@”打开%@开关";
+IMAGE_PICKER_NONAUTHORITY_GO_SETTING = "去设置";
+
+MEDIA_PICKER_SCALE_ASPECT_FIT = "留白";
+MEDIA_PICKER_SCALE_ASPECT_FILL = "充满";
+MEDIA_PICKER_ALBUM_TAB_TITLE = "相册";
+MEDIA_PICKER_CAMERA_TAB_TITLE = "拍照";
+MEDIA_PICKER_VIDEOCORDER_TAB_TITLE = "拍视频";

+ 33 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSSegmentedControl/KSSegmentedControl.h

@@ -0,0 +1,33 @@
+//
+//  KSSegmentedControl.h
+// 
+//
+//  Created by kinsun on 2018/11/25.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSSegmentedControl : UIView
+
+@property (nonatomic, strong, readonly) NSArray <NSString *> *items;
+@property (nonatomic, assign) CGFloat egdeMargin;
+@property (nonatomic, strong) UIFont *font;
+@property (nonatomic, strong) UIColor *normalTextColor;
+@property (nonatomic, strong) UIColor *selectedTextColor;
+@property (nonatomic, assign) NSUInteger selectedSegmentIndex;
+@property (nonatomic, copy, nullable) void (^didClickItem)(KSSegmentedControl *segmentedControl, NSInteger index);
+
+@property (nonatomic, assign, getter=isShowIndicator) BOOL showIndicator;
+@property (nonatomic, assign) CGFloat indicatorHeight;
+@property (nonatomic, assign) CGFloat indicatorBottomEgdeInset;
+@property (nonatomic) UIColor *indndicatorColor;
+
+- (instancetype)initWithFrame:(CGRect)frame items:(NSArray <NSString *> *)items;
+- (void)updateIndicatorProportion:(CGFloat)proportion;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 258 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSSegmentedControl/KSSegmentedControl.m

@@ -0,0 +1,258 @@
+//
+//  KSSegmentedControl.m
+// 
+//
+//  Created by kinsun on 2018/11/25.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#import "KSSegmentedControl.h"
+
+@interface _KSSCItemLayer : CATextLayer
+
+@property (nonatomic, assign) CGColorRef normalColor;
+@property (nonatomic, assign) CGColorRef selectedColor;
+@property (nonatomic, assign, getter=isSelected) BOOL selected;
+
+@end
+
+@implementation _KSSCItemLayer
+
+- (instancetype)init {
+    if (self = [super init]) {
+        self.wrapped = NO;
+        self.alignmentMode = kCAAlignmentCenter;
+    }
+    return self;
+}
+
+- (void)setNormalColor:(CGColorRef)normalColor {
+    _normalColor = normalColor;
+    if (!_selected) self.foregroundColor = normalColor;
+}
+
+- (void)setSelectedColor:(CGColorRef)selectedColor {
+    _selectedColor = selectedColor;
+    if (_selected) self.foregroundColor = selectedColor;
+}
+
+- (void)setSelected:(BOOL)selected {
+    _selected = selected;
+    self.foregroundColor = selected ? _selectedColor : _normalColor;
+}
+
+@end
+
+#import "KSLayout.h"
+
+@implementation KSSegmentedControl {
+    NSArray <NSNumber *> *_itemsWidthArray;
+    NSPointerArray *_textLayerArray;
+    __weak _KSSCItemLayer *_selectedTextlayer;
+    __weak CALayer *_indLayer;
+    
+    CGFloat _itemMargin;
+    CGFloat _tempProportion;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame items:(NSArray <NSString *> *)items {
+    if (self = [super initWithFrame:frame]) {
+        _items = items;
+        [self _initView];
+    }
+    return self;
+}
+
+- (void)_initView {
+    _indicatorHeight = 3.f;
+    CALayer *layer = self.layer;
+    
+    CALayer *indLayer = [CALayer layer];
+    [layer addSublayer:indLayer];
+    _indLayer = indLayer;
+    self.indndicatorColor = self.tintColor;
+    
+    CGFloat scale = UIScreen.mainScreen.scale;
+    NSPointerArray *textLayerArray = [NSPointerArray weakObjectsPointerArray];
+    for (NSString *title in _items) {
+        _KSSCItemLayer *textLayer = [_KSSCItemLayer layer];
+        textLayer.contentsScale = scale;
+        textLayer.string = title;
+        [layer addSublayer:textLayer];
+        [textLayerArray addPointer:(__bridge void *)textLayer];
+    }
+    _textLayerArray = textLayerArray;
+    
+    [self _forceUpdateSelectedSegmentIndex:0];
+    self.font = [UIFont systemFontOfSize:18.f];
+    self.normalTextColor = UIColor.lightTextColor;
+    self.selectedTextColor = UIColor.blackColor;
+}
+
+- (void)layoutSublayersOfLayer:(CALayer *)layer {
+    [super layoutSublayersOfLayer:layer];
+    CGSize size = layer.frame.size;
+    k_creatSizeElementOfSize(size);
+    k_creatFrameElement;
+    
+    CGFloat remainderWidth = windowWidth;
+    NSUInteger count = _itemsWidthArray.count;
+    for (NSUInteger i = 0; i < count; i++) {
+        NSNumber *value = [_itemsWidthArray objectAtIndex:i];
+        CGFloat width = value.doubleValue;
+        remainderWidth -= width;
+    }
+    CGFloat margin = floor((remainderWidth-_egdeMargin*2.f)/count);
+    _itemMargin = margin;
+    viewX = _egdeMargin+margin*0.5f; viewH = self.font.lineHeight; viewY = (windowHeight-viewH)*0.5f;
+    for (NSUInteger i = 0; i < count; i++) {
+        NSNumber *value = [_itemsWidthArray objectAtIndex:i];
+        viewW = value.doubleValue;
+        _KSSCItemLayer *textLayer = [_textLayerArray pointerAtIndex:i];
+        CGRect frame = k_setFrame;
+        textLayer.frame = frame;
+        viewX = CGRectGetMaxX(frame)+margin;
+    }
+    
+    if (windowHeight > 1.f && !_indLayer.hidden && _indLayer.frame.size.width < 1.f) {
+        _KSSCItemLayer *textLayer = [_textLayerArray pointerAtIndex:_selectedSegmentIndex];
+        CGRect frame = textLayer.frame;
+        frame.size.height = _indicatorHeight;
+        frame.origin.y = windowHeight-_indicatorBottomEgdeInset-_indicatorHeight;
+        _indLayer.frame = frame;
+    }
+}
+
+- (void)setShowIndicator:(BOOL)showIndicator {
+    _indLayer.hidden = !showIndicator;
+}
+
+- (BOOL)isShowIndicator {
+    return !_indLayer.hidden;
+}
+
+- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
+    [super touchesEnded:touches withEvent:event];
+    if (_didClickItem != nil) {
+        UITouch *touch = touches.anyObject;
+        CGPoint location = [touch locationInView:self];
+        CGRect bounds = self.bounds;
+        if (CGRectContainsPoint(bounds, location)) {
+            for (NSUInteger i = 0; i < _textLayerArray.count; i++) {
+                _KSSCItemLayer *textLayer = [_textLayerArray pointerAtIndex:i];
+                if (CGRectContainsPoint(textLayer.frame, location)) {
+                    _didClickItem(self, i);
+                }
+            }
+        }
+    }
+}
+
+- (void)setSelectedSegmentIndex:(NSUInteger)selectedSegmentIndex {
+    if (_selectedSegmentIndex != selectedSegmentIndex) {
+        [self _forceUpdateSelectedSegmentIndex:selectedSegmentIndex];
+    }
+}
+
+- (void)_forceUpdateSelectedSegmentIndex:(NSUInteger)selectedSegmentIndex {
+    if (selectedSegmentIndex >= 0 && selectedSegmentIndex < _textLayerArray.count) {
+        _selectedSegmentIndex = selectedSegmentIndex;
+        if (_selectedTextlayer != nil)
+            _selectedTextlayer.selected = NO;
+        
+        _KSSCItemLayer *textLayer = [_textLayerArray pointerAtIndex:selectedSegmentIndex];
+        textLayer.selected = YES;
+        _selectedTextlayer = textLayer;
+    }
+}
+
+- (void)setFont:(UIFont *)font {
+    if (font == nil) return;
+    _font = font;
+    
+    NSUInteger count = _textLayerArray.count;
+    CGFloat pointSize = font.pointSize;
+    CFStringRef fontCFString = (__bridge CFStringRef)font.fontName;
+    CGFontRef fontRef = CGFontCreateWithFontName(fontCFString);
+    
+    CGSize maxSize = (CGSize){MAXFLOAT, MAXFLOAT};
+    NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
+    NSDictionary <NSAttributedStringKey, UIFont *> *attributes = @{NSFontAttributeName: font};
+    NSMutableArray <NSNumber *> *itemsWidthArray = [NSMutableArray arrayWithCapacity:count];
+    
+    for (NSUInteger i = 0; i < count; i++) {
+        NSString *string = [_items objectAtIndex:i];
+        CGSize size = [string boundingRectWithSize:maxSize options:options attributes:attributes context:nil].size;
+        NSNumber *width = [NSNumber numberWithDouble:size.width+3];
+        [itemsWidthArray addObject:width];
+        
+        _KSSCItemLayer *textLayer = [_textLayerArray pointerAtIndex:i];
+        textLayer.font = fontRef;
+        textLayer.fontSize = pointSize;
+    }
+    CGFontRelease(fontRef);
+    _itemsWidthArray = itemsWidthArray;
+}
+
+- (void)setNormalTextColor:(UIColor *)normalTextColor {
+    _normalTextColor = normalTextColor;
+    CGColorRef cgColor = normalTextColor.CGColor;
+    for (_KSSCItemLayer *textLayer in _textLayerArray) {
+        textLayer.normalColor = cgColor;
+    }
+}
+
+- (void)setSelectedTextColor:(UIColor *)selectedTextColor {
+    _selectedTextColor = selectedTextColor;
+    CGColorRef cgColor = selectedTextColor.CGColor;
+    for (_KSSCItemLayer *textLayer in _textLayerArray) {
+        textLayer.selectedColor = cgColor;
+    }
+}
+
+- (void)setIndndicatorColor:(UIColor *)indndicatorColor {
+    _indLayer.backgroundColor = indndicatorColor.CGColor;
+}
+
+- (UIColor *)indndicatorColor {
+    return [UIColor colorWithCGColor:_indLayer.backgroundColor];
+}
+
+- (void)updateIndicatorProportion:(CGFloat)proportion {
+    NSInteger index = floor(proportion);
+    NSInteger toIndex = index+1;
+    if ([self checkIndexAvailable:index] && [self checkIndexAvailable:toIndex]) {
+        _KSSCItemLayer *textLayer = [_textLayerArray pointerAtIndex:index];
+        _KSSCItemLayer *toTextLayer = [_textLayerArray pointerAtIndex:toIndex];
+        CGRect textLayerFrame = textLayer.frame;
+        CGRect toTextLayerFrame = toTextLayer.frame;
+        
+        CGFloat scale = proportion-index;
+        
+        CGFloat width = textLayerFrame.size.width;
+        CGFloat toWidth = toTextLayerFrame.size.width;
+        CGFloat defWidth = toWidth-width;
+        CGFloat resultWidth = defWidth*scale+width;
+        
+        CGFloat x = textLayerFrame.origin.x;
+        CGFloat toX = toTextLayerFrame.origin.x;
+        CGFloat defX = toX-x;
+        CGFloat resultX = defX*scale+x;
+
+        CGRect frame = _indLayer.frame;
+        frame.size.width = resultWidth;
+        frame.origin.x = resultX;
+        [CATransaction begin];
+        [CATransaction setDisableActions:YES];
+        _indLayer.frame = frame;
+        [CATransaction commit];
+    }
+    _tempProportion = proportion;
+}
+
+- (BOOL)checkIndexAvailable:(NSInteger)index {
+    return index >= 0 && index < _textLayerArray.count;
+}
+
+@end
+

+ 50 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoLayer.h

@@ -0,0 +1,50 @@
+//
+//  KSVideoLayer.h
+// 
+//
+//  Created by kinsun on 2018/11/21.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <CoreMedia/CMTime.h>
+#import <AVFoundation/AVFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+FOUNDATION_EXPORT NSNotificationName const KSVideoLayerDidChangedNotification;
+FOUNDATION_EXPORT NSNotificationName const KSVideoLayerDidResetNotification;
+
+typedef NS_ENUM(NSInteger, KSVideoLayerGravity) {
+    KSVideoLayerGravityResizeAspect = 0,
+    KSVideoLayerGravityResizeAspectFill,
+    KSVideoLayerGravityResize
+};
+
+@interface KSVideoLayer : CALayer
+
+@property (nonatomic, copy) void (^videoTimeDidChangdWithLeftTime)(float time);
+@property (nonatomic, copy) void (^videoTimeDidChangdCallback)(CMTime time);
+@property (nonatomic, copy) void (^videoCanBePlayed)(float duration);
+@property (nonatomic, copy) void (^videoPlaybackFinished)(void);
+
+@property (nonatomic, assign, getter=isPlaying) BOOL playing;
+@property (nonatomic, strong) AVPlayerItem *playerItem;
+@property (nonatomic, assign) KSVideoLayerGravity videoGravity;
+@property (nonatomic) float volume;
+
++ (instancetype)shareInstance;
+
+- (void)play;
+- (void)pause;
+- (void)stop;
+
+- (void)changeVideoTime:(float)time;
+
+- (void)resetPlayer;
+- (void)forcePlay;
+- (void)forcePause;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 221 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoLayer.m

@@ -0,0 +1,221 @@
+//
+//  KSVideoLayer.m
+// 
+//
+//  Created by kinsun on 2018/11/21.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#import "KSVideoLayer.h"
+
+static NSString * const k_AVPlayerStatusKey = @"status";
+NSNotificationName const KSVideoLayerDidChangedNotification = @"KSVideoLayerDidChangedNotification";
+NSNotificationName const KSVideoLayerDidResetNotification = @"KSVideoLayerDidResetNotification";
+
+@implementation KSVideoLayer {
+    AVPlayer *_player;
+    __weak AVPlayerLayer *_playerLayer;
+    
+    id _playTimeObserver;
+    
+    BOOL _isInBackground;
+}
+
+static KSVideoLayer *k_instance = nil;
++ (instancetype)shareInstance {
+    if (k_instance == nil) {
+        @synchronized (self) {
+            if (k_instance == nil) {
+                k_instance = [self layer];
+            }
+        }
+    }
+    return k_instance;
+}
+
+- (instancetype)init {
+    if (self = [super init]) {
+        _isInBackground = NO;
+        AVPlayer *player = [[AVPlayer alloc] init];
+        _player = player;
+        
+        AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
+        [self addSublayer:playerLayer];
+        _playerLayer = playerLayer;
+        
+        NSNotificationCenter *notificationCenter = NSNotificationCenter.defaultCenter;
+        [notificationCenter addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
+        [notificationCenter addObserver:self selector:@selector(didEnterBackgroundNotification:) name:UIApplicationDidEnterBackgroundNotification object:nil];
+        [notificationCenter addObserver:self selector:@selector(willEnterForegroundNotification:) name:UIApplicationWillEnterForegroundNotification object:nil];
+        
+        __weak typeof(self) weakSelf = self;
+        _playTimeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 10.f) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
+            [weakSelf videoTimeDidChanged];
+        }];
+    }
+    return self;
+}
+
+- (void)layoutSublayers {
+    [super layoutSublayers];
+    _playerLayer.frame = self.bounds;
+}
+
+- (void)videoTimeDidChanged {
+    if (_videoTimeDidChangdCallback != nil) {
+        // 获取 item 当前播放秒
+        _videoTimeDidChangdCallback(_playerItem.currentTime);
+    }
+    
+    if (_videoTimeDidChangdWithLeftTime) {
+        float duration = CMTimeGetSeconds(_playerItem.duration);// 获取视频长度
+        float playLength = CMTimeGetSeconds(_playerItem.currentTime);// 获取视频长度
+         _videoTimeDidChangdWithLeftTime(duration-playLength);
+    }
+}
+
+- (void)playbackFinished:(NSNotification *)notification {
+    if (notification.object == _playerItem) {
+        _playing = NO;
+        NSLog(@"视频播放完成通知");
+        [_playerItem seekToTime:kCMTimeZero]; // 跳转到初始
+        if (_videoPlaybackFinished != nil) {
+            _videoPlaybackFinished();
+        }
+    }
+}
+
+- (void)didEnterBackgroundNotification:(NSNotification *)noti {
+    [self resetPlayer];
+    _isInBackground = YES;
+}
+
+- (void)willEnterForegroundNotification:(NSNotification *)noti {
+    _isInBackground = NO;
+}
+
+- (void)removeItemObserver:(AVPlayerItem *)item {
+    if (item != nil) {
+        [item.asset cancelLoading];
+        [item cancelPendingSeeks];
+        [item removeObserver:self forKeyPath:k_AVPlayerStatusKey];
+    }
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
+    if (object == _playerItem) {
+        if ([keyPath isEqualToString:k_AVPlayerStatusKey]) {
+            if (!_isInBackground) {
+                AVPlayerStatus status = [[change objectForKey:@"new"] integerValue]; // 获取更改后的状态
+                if (status == AVPlayerStatusReadyToPlay) {
+                    NSLog(@"准备播放");
+                    if (_videoCanBePlayed != nil) {
+                        float duration = CMTimeGetSeconds(_playerItem.duration);// 获取视频长度
+                        NSLog(@"%.2f", duration);
+                        _videoCanBePlayed(duration);
+                    }
+                    // 播放
+                    [self play];
+                } else if (status == AVPlayerStatusFailed) {
+                    NSLog(@"AVPlayerStatusFailed");
+                } else {
+                    NSLog(@"AVPlayerStatusUnknown");
+                }
+            }
+        }
+    } else {
+        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+    }
+}
+
+- (void)setPlayerItem:(AVPlayerItem *)playerItem {
+    if (playerItem != _playerItem) {
+        [self removeItemObserver:_playerItem];
+        _playerItem = playerItem;
+        [_player replaceCurrentItemWithPlayerItem:playerItem];
+        [playerItem addObserver:self forKeyPath:k_AVPlayerStatusKey options:NSKeyValueObservingOptionNew context:nil];
+    } else {
+        [self play];
+    }
+}
+
+- (void)forcePlay {
+    [_player play];
+}
+
+- (void)forcePause {
+    [_player pause];
+}
+
+- (void)play {
+    _playing = YES;
+    AVAudioSession *session = [AVAudioSession sharedInstance];
+    [session setCategory:AVAudioSessionCategorySoloAmbient error:nil];
+    [session setActive:YES error:nil];
+    [_player play];
+}
+
+- (void)pause {
+    _playing = NO;
+    [_player pause];
+}
+
+- (void)stop {
+    if (_playing) {
+        [self changeVideoTime:0.f];
+        [self pause];
+        if (_videoPlaybackFinished != nil) {
+            _videoPlaybackFinished();
+        }
+    }
+}
+
+- (void)changeVideoTime:(float)time {
+    CMTime changedTime = CMTimeMakeWithSeconds(time, 1.0);
+    NSLog(@"changeVideoTime: %.2f", time);
+    [_playerItem seekToTime:changedTime completionHandler:nil];
+}
+
+- (void)setVideoGravity:(KSVideoLayerGravity)videoGravity {
+    _videoGravity = videoGravity;
+    AVLayerVideoGravity k_videoGravity = AVLayerVideoGravityResizeAspect;
+    switch (videoGravity) {
+        case KSVideoLayerGravityResizeAspectFill:
+            k_videoGravity = AVLayerVideoGravityResizeAspectFill;
+            break;
+        case KSVideoLayerGravityResize:
+            k_videoGravity = AVLayerVideoGravityResize;
+            break;
+        default:
+            break;
+    }
+    _playerLayer.videoGravity = k_videoGravity;
+}
+
+- (void)setVolume:(float)volume {
+    _player.volume = volume;
+}
+
+- (float)volume {
+    return _player.volume;
+}
+
+- (void)resetPlayer {
+    _playing = NO;
+    [self removeItemObserver:_playerItem];
+    _playerItem = nil;
+    [_player replaceCurrentItemWithPlayerItem:nil];
+    [NSNotificationCenter.defaultCenter postNotificationName:KSVideoLayerDidResetNotification object:self];
+}
+
+- (void)dealloc {
+    [self removeItemObserver:_playerItem];
+    _playerItem = nil;
+    [_player replaceCurrentItemWithPlayerItem:nil];
+    [_player removeTimeObserver:_playTimeObserver];
+    _playTimeObserver = nil;
+    [NSNotificationCenter.defaultCenter removeObserver:self];
+    _player = nil;
+}
+
+@end

+ 35 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerBaseView.h

@@ -0,0 +1,35 @@
+//
+//  KSVideoPlayerBaseView.h
+// 
+//
+//  Created by kinsun on 2018/12/10.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "KSVideoLayer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSVideoPlayerBaseView : UIView
+
+@property (nonatomic, assign, readonly, getter=isPlaying) BOOL playing;
+@property (nonatomic, weak, readonly) UIImageView *coverView;
+@property (nonatomic, assign) KSVideoLayerGravity videoGravity;
+@property (nonatomic, assign) float volume;
+@property (nonatomic, assign, getter=isShowToolsBar) BOOL showToolsBar;
+@property (nonatomic, copy) void (^videoTimeDidChangdWithLeftTime)(float time);
+@property (nonatomic, copy) void (^videoPlaybackFinished)(void);
+@property (nonatomic, copy) void (^videoTimeDidChangdCallback)(CMTime time);
+@property (nonatomic, copy) void (^videoCanBePlayed)(float duration);
+
+@property (nonatomic, strong, nullable) AVPlayerItem *playerItem;
+
+- (void)play;
+- (void)pause;
+- (void)changeVideoTime:(float)time;
+- (void)resetViewStatus;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 188 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerBaseView.m

@@ -0,0 +1,188 @@
+//
+//  KSVideoPlayerBaseView.m
+// 
+//
+//  Created by kinsun on 2018/12/10.
+//  Copyright © 2018年 kinsun. All rights reserved.
+//
+
+#import "KSVideoPlayerBaseView.h"
+
+@interface KSVideoPlayerBaseView ()
+
+@property (nonatomic, assign, getter=playerIsInView, readonly) BOOL playerInView;
+
+@end
+
+@implementation KSVideoPlayerBaseView {
+    __weak KSVideoLayer *_player;
+    BOOL _isHiddenAnimating;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        NSNotificationCenter *center = NSNotificationCenter.defaultCenter;
+        [center addObserver:self selector:@selector(_didChangedPlayerSuperLayer:) name:KSVideoLayerDidChangedNotification object:nil];
+        [center addObserver:self selector:@selector(_didResetPlayer:) name:KSVideoLayerDidResetNotification object:nil];
+        _videoGravity = KSVideoLayerGravityResizeAspect;
+        _volume = 1.f;
+        _player = [KSVideoLayer shareInstance];
+        self.backgroundColor = UIColor.clearColor;
+        self.clipsToBounds = YES;
+        
+        UIImageView *coverView = [[UIImageView alloc] init];
+        coverView.contentMode = UIViewContentModeScaleAspectFit;
+        coverView.clipsToBounds = YES;
+        [self addSubview:coverView];
+        _coverView = coverView;
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    _coverView.frame = self.bounds;
+}
+
+- (void)layoutSublayersOfLayer:(CALayer *)layer {
+    [super layoutSublayersOfLayer:layer];
+    if (self.playerIsInView) {
+        _player.frame = layer.bounds;
+    }
+}
+
+- (void)setShowToolsBar:(BOOL)showToolsBar {
+    _showToolsBar = showToolsBar;
+    if (_playing && showToolsBar && !_isHiddenAnimating) {
+        _isHiddenAnimating = YES;
+        __weak typeof(self) weakSelf = self;
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+            [weakSelf _autoHiddenTools];
+        });
+    }
+}
+
+- (void)_autoHiddenTools {
+    _isHiddenAnimating = NO;
+    if (_playing) self.showToolsBar = NO;
+}
+
+- (void)setHidden:(BOOL)hidden {
+    [super setHidden:hidden];
+    if (hidden) {
+        [self pause];
+    }
+}
+
+- (void)_clikeCenterButton:(UIButton *)btn {
+    if (_playing) {
+        [self pause];//暂停
+    } else {
+        [self play];//播放
+    }
+}
+
+- (void)setPlayerItem:(AVPlayerItem *)playerItem {
+    _playerItem = playerItem;
+    [self resetViewStatus];
+}
+
+- (void)_didChangedPlayerSuperLayer:(NSNotification *)noti {
+    KSVideoLayer *player = noti.object;
+    if (player == _player && player.superlayer != self.layer) {
+        [self resetViewStatus];
+    }
+}
+
+- (void)_didResetPlayer:(NSNotification *)noti {
+    if (noti.object == _player) {
+        [self resetViewStatus];
+    }
+}
+
+- (void)resetViewStatus {
+    [self pause];
+    self.playing = NO;
+    _coverView.hidden = NO;
+}
+
+- (void)setVolume:(float)volume {
+    _volume = volume;
+    if (self.playerInView) _player.volume = volume;
+}
+
+- (void)setPlaying:(BOOL)playing {
+    _playing = playing;
+}
+
+- (void)play {
+    if (_playerItem != nil && !_playing) {
+        _coverView.hidden = YES;
+        self.playing = YES;
+        CALayer *layer = self.layer;
+        KSVideoLayer *player = _player;
+        if (player.superlayer != layer) {
+            player.videoGravity = _videoGravity;
+            player.volume = _volume;
+            player.videoCanBePlayed = _videoCanBePlayed;
+            player.videoTimeDidChangdCallback = _videoTimeDidChangdCallback;
+            player.videoTimeDidChangdWithLeftTime = _videoTimeDidChangdWithLeftTime;
+            __weak typeof(self) weakSelf = self;
+            [player setVideoPlaybackFinished:^{
+                [weakSelf resetViewStatus];
+                void (^videoPlaybackFinished)(void) = weakSelf.videoPlaybackFinished;
+                if (videoPlaybackFinished != nil) {
+                    videoPlaybackFinished();
+                }
+            }];
+            [layer insertSublayer:player atIndex:0];
+            [layer setNeedsLayout];
+            [NSNotificationCenter.defaultCenter postNotificationName:KSVideoLayerDidChangedNotification object:player];
+        }
+        player.playerItem = _playerItem;
+        self.showToolsBar = YES;
+    }
+}
+
+- (void)pause {
+    if (self.playerIsInView) {
+        [_player pause];
+    }
+    self.playing = NO;
+    self.showToolsBar = YES;
+}
+
+- (BOOL)playerIsInView {
+    return _player != nil && _player.superlayer == self.layer;
+}
+
+- (void)setVideoGravity:(KSVideoLayerGravity)videoGravity {
+    _videoGravity = videoGravity;
+    _player.videoGravity = videoGravity;
+    switch (videoGravity) {
+        case KSVideoLayerGravityResize:
+            _coverView.contentMode = UIViewContentModeScaleToFill;
+            break;
+        case KSVideoLayerGravityResizeAspect:
+            _coverView.contentMode = UIViewContentModeScaleAspectFit;
+            break;
+        case KSVideoLayerGravityResizeAspectFill:
+            _coverView.contentMode = UIViewContentModeScaleAspectFill;
+            break;
+    }
+}
+
+- (void)changeVideoTime:(float)time {
+    [_player changeVideoTime:time];
+}
+
+- (void)dealloc {
+    if (self.playerIsInView) {
+        [_player resetPlayer];
+    }
+    NSNotificationCenter *center = NSNotificationCenter.defaultCenter;
+    [center removeObserver:self name:KSVideoLayerDidResetNotification object:nil];
+    [center removeObserver:self name:KSVideoLayerDidChangedNotification object:nil];
+}
+
+@end

+ 18 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerLiteView.h

@@ -0,0 +1,18 @@
+//
+//  KSVideoPlayerLiteView.h
+// 
+//
+//  Created by kinsun on 2019/4/12.
+//
+
+#import "KSVideoPlayerBaseView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSVideoPlayerLiteView : KSVideoPlayerBaseView
+
+@property (nonatomic, weak, readonly) UIButton *playButton;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 82 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/KSVideoPlayerView/KSVideoPlayerLiteView.m

@@ -0,0 +1,82 @@
+//
+//  KSVideoPlayerLiteView.m
+// 
+//
+//  Created by kinsun on 2019/4/12.
+//
+
+#import "KSVideoPlayerLiteView.h"
+
+@interface KSVideoPlayerBaseView ()
+
+- (void)setPlaying:(BOOL)playing;
+
+@end
+
+#import "KSLayout.h"
+
+@implementation KSVideoPlayerLiteView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        UIButton *playButton = [UIButton buttonWithType:UIButtonTypeCustom];
+        playButton.imageView.contentMode = UIViewContentModeCenter;
+        [playButton setImage:[UIImage imageNamed:@"icon_video_play"] forState:UIControlStateNormal];
+        [playButton setImage:[UIImage imageNamed:@"icon_video_pause"] forState:UIControlStateSelected];
+        [playButton addTarget:self action:@selector(_clikeCenterButton:) forControlEvents:UIControlEventTouchUpInside];
+        [self addSubview:playButton];
+        _playButton = playButton;
+
+        UITapGestureRecognizer *tap = [UITapGestureRecognizer.alloc initWithTarget:self action:@selector(_didClickVideo)];
+        [self addGestureRecognizer:tap];
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGSize size = self.bounds.size;
+    k_creatFrameElement;
+    k_creatSizeElementOfSize(size);
+    
+    CGSize k_size = [_playButton sizeThatFits:size];
+    viewW = k_size.width; viewH = k_size.height;
+    viewX = (windowWidth-viewW)*0.5f; viewY = (windowHeight-viewH)*0.5f;
+    k_settingFrame(_playButton);
+}
+
+- (void)_clikeCenterButton:(UIButton *)btn {
+    if (self.isPlaying) {
+        [self pause];//暂停
+    } else {
+        [self play];//播放
+    }
+    btn.selected = self.isPlaying;
+}
+
+- (void)setPlaying:(BOOL)playing {
+    [super setPlaying:playing];
+    _playButton.selected = playing;
+}
+
+- (void)setShowToolsBar:(BOOL)showToolsBar {
+    if (showToolsBar == _playButton.isHidden) {
+        _playButton.hidden = !showToolsBar;
+        CATransition *fade = [CATransition animation];
+        fade.duration = 0.4f;
+        fade.type = kCATransitionFade;
+        [_playButton.layer addAnimation:fade forKey:nil];
+    }
+    [super setShowToolsBar:showToolsBar];
+}
+
+- (void)_didClickVideo {
+    if (self.isPlaying) self.showToolsBar = !self.isShowToolsBar;
+}
+
+- (void)resetViewStatus {
+    [super resetViewStatus];
+    _playButton.selected = NO;
+}
+
+@end

+ 50 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Model/KSMediaPickerAlbumModel.swift

@@ -0,0 +1,50 @@
+//
+//  KSMediaPickerAlbumModel.swift
+// 
+//
+//  Created by kinsun on 2019/3/1.
+//
+
+import UIKit
+import Photos
+
+open class KSMediaPickerAlbumModel {
+    
+    public let assetCollection: PHAssetCollection
+    public let albumTitle: String
+    public var assetList: [KSMediaPickerItemModel]
+    
+    public init(assetCollection: PHAssetCollection, mediaType: KSMediaPickerController.mediaType) {
+        self.assetCollection = assetCollection
+        albumTitle = assetCollection.localizedTitle ?? ""
+        let assets = PHAsset.fetchAssets(in: assetCollection, options: nil)
+        var assetList = Array<KSMediaPickerItemModel>()
+        for i in (0..<assets.count).reversed() {
+            let asset = assets.object(at: i)
+            if mediaType == .all || mediaType.rawValue == asset.mediaType.rawValue {
+                let itemModel = KSMediaPickerItemModel(asset)
+                assetList.append(itemModel)
+            }
+        }
+        self.assetList = assetList
+    }
+    
+    public class func albumModel(from assetCollections: [PHFetchResult<PHAssetCollection>], mediaType: KSMediaPickerController.mediaType) -> [KSMediaPickerAlbumModel] {
+        var array = Array<KSMediaPickerAlbumModel>()
+        for result in assetCollections {
+            for i in 0..<result.count {
+                let assetCollection = result.object(at: i)
+                let isCameraRoll = assetCollection.assetCollectionSubtype  == .smartAlbumUserLibrary
+                let albumModel = KSMediaPickerAlbumModel(assetCollection: assetCollection, mediaType: mediaType)
+                if albumModel.assetList.count > 0 {
+                    if isCameraRoll {
+                        array.insert(albumModel, at: 0)
+                    } else {
+                        array.append(albumModel)
+                    }
+                }
+            }
+        }
+        return array
+    }
+}

+ 67 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Model/KSMediaPickerItemModel.swift

@@ -0,0 +1,67 @@
+//
+//  KSMediaPickerItemModel.swift
+// 
+//
+//  Created by kinsun on 2019/3/1.
+//
+
+import UIKit
+import Photos
+
+open class KSMediaPickerItemModel: NSObject {
+    
+    @objc public static let thumbSize = {() -> CGSize in
+        let screen = UIScreen.main
+        let width = screen.bounds.size.width*screen.scale*0.25
+        return CGSize(width: width, height: width)
+    }()
+    
+    @objc public static let pictureOptions = {() -> PHImageRequestOptions in
+        let options = PHImageRequestOptions()
+        options.resizeMode = .none
+        // 同步获得图片, 只会返回1张图片
+        options.isSynchronous = true
+        options.isNetworkAccessAllowed = true;
+        return options
+    }()
+    
+    @objc public static let pictureViewerOptions = {() -> PHImageRequestOptions in
+        let options = PHImageRequestOptions()
+        options.resizeMode = .none
+        options.isSynchronous = false
+        options.isNetworkAccessAllowed = true;
+        return options
+    }()
+    
+    @objc public static let videoOptions = {() -> PHVideoRequestOptions in
+        let options = PHVideoRequestOptions()
+        options.version = .current
+        options.deliveryMode = .automatic
+        options.isNetworkAccessAllowed = true;
+        return options
+    }()
+    
+    open var contentOffset: CGPoint?
+    open var zoomScale: CGFloat?
+    open var contentSize: CGSize?
+    open var imageFrame: CGRect?
+    open var isHighlight = false
+    open var isLoseFocus = false
+    @objc open var index = UInt(0) {
+        didSet {
+            if index == 0 {
+                contentOffset = nil
+                zoomScale = nil
+                contentSize = nil
+                imageFrame = nil
+            }
+        }
+    }
+    @objc open var thumb: UIImage?
+    @objc public let asset: PHAsset
+    
+    public init(_ asset: PHAsset) {
+        self.asset = asset
+        super.init()
+    }
+}

+ 37 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/Model/KSMediaPickerOutputModel.swift

@@ -0,0 +1,37 @@
+//
+//  KSMediaPickerOutputModel.swift
+// 
+//
+//  Created by kinsun on 2019/3/24.
+//
+
+import UIKit
+import Photos
+
+open class KSMediaPickerOutputModel: NSObject {
+    
+    @objc public let sourceAsset: PHAsset
+    @objc public let thumb: UIImage?
+    @objc public let image: UIImage?
+    @objc public let videoAsset: AVURLAsset?
+    @objc public let mediaType: PHAssetMediaType
+    
+    public init(asset: PHAsset, image: UIImage?, thumb: UIImage?) {
+        sourceAsset = asset
+        mediaType = asset.mediaType
+        self.thumb = thumb
+        self.image = image
+        videoAsset = nil
+        super.init()
+    }
+    
+    public init(asset: PHAsset, videoAsset: AVURLAsset?, thumb: UIImage?) {
+        sourceAsset = asset
+        mediaType = asset.mediaType
+        self.thumb = thumb
+        self.videoAsset = videoAsset
+        image = nil
+        super.init()
+    }
+    
+}

+ 227 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCameraToolBar.swift

@@ -0,0 +1,227 @@
+//
+//  KSMediaPickerCameraToolBar.swift
+// 
+//
+//  Created by kinsun on 2019/3/11.
+//
+
+import UIKit
+
+extension KSMediaPickerCameraToolBar {
+    
+    open class button: UIControl {
+        
+        public enum style: UInt {
+            case lightContent
+            case darkContent
+        }
+        
+        public enum status {
+            case status1
+            case status2
+            case status3
+        }
+        
+        required public init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        private let _imageView = {() -> UIImageView in
+            let imageView = UIImageView()
+            imageView.contentMode = .scaleAspectFit
+            return imageView
+        }()
+        
+        override public init(frame: CGRect) {
+            super.init(frame: frame)
+            addSubview(_imageView)
+        }
+        
+        override open func layoutSubviews() {
+            super.layoutSubviews()
+            _imageView.frame = bounds
+        }
+        
+        open var status = button.status.status1 {
+            didSet {
+                _didSet(status: self.status, style: self.style)
+            }
+        }
+        
+        open var style = button.style.darkContent {
+            didSet {
+                _didSet(status: self.status, style: self.style)
+            }
+        }
+        
+        private func _didSet(status: button.status, style: button.style) {
+            _imageView.image = image(of: status, of: style) ?? image(of: .status1, of: style)
+        }
+        
+        private var _lightContentStatusImageArray = [button.status: UIImage]()
+        private var _darkContentStatusImageArray = [button.status: UIImage]()
+        
+        open func set(image: UIImage, for status: button.status, of style: button.style) {
+            switch style {
+            case .lightContent:
+                _lightContentStatusImageArray[status] = image
+                break
+            case .darkContent:
+                _darkContentStatusImageArray[status] = image
+                break
+            }
+            if self.status == status, self.style == style {
+                _imageView.image = image
+            }
+        }
+        
+        open func image(of status: button.status, of style: button.style) -> UIImage? {
+            let array: [button.status: UIImage]
+            switch style {
+            case .lightContent:
+                array = _lightContentStatusImageArray
+                break
+            case .darkContent:
+                array = _darkContentStatusImageArray
+                break
+            }
+            return array[status]
+        }
+    }
+}
+
+open class KSMediaPickerCameraToolBar: UIView {
+    
+    public enum toolBarType: UInt {
+        case photos
+        case noFlashlightPhotos
+        case videos
+    }
+
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    public let closeButton = {() -> KSMediaPickerCameraToolBar.button in
+        let closeButton = KSMediaPickerCameraToolBar.button()
+        closeButton.set(image: UIImage(named: "icon_mediaPicker_camera_close")!, for: .status1, of: .lightContent)
+        closeButton.set(image: UIImage(named: "icon_mediaPicker_camera_close_b")!, for: .status1, of: .darkContent)
+        return closeButton
+    }()
+    public let priviewSizeButton = {() -> KSMediaPickerCameraToolBar.button in
+        let priviewSizeButton = KSMediaPickerCameraToolBar.button()
+        priviewSizeButton.set(image: UIImage(named: "icon_mediaPicker_camera_square")!, for: .status1, of: .lightContent)
+        priviewSizeButton.set(image: UIImage(named: "icon_mediaPicker_camera_square_b")!, for: .status1, of: .darkContent)
+        priviewSizeButton.set(image: UIImage(named: "icon_mediaPicker_camera_rectangle")!, for: .status2, of: .lightContent)
+        priviewSizeButton.set(image: UIImage(named: "icon_mediaPicker_camera_rectangle_16_9")!, for: .status3, of: .lightContent)
+        return priviewSizeButton
+    }()
+    public let flashlightButton = {() -> KSMediaPickerCameraToolBar.button in
+        let flashlightButton = KSMediaPickerCameraToolBar.button()
+        flashlightButton.set(image: UIImage(named: "icon_mediaPicker_camera_flashlight_auto")!, for: .status1, of: .lightContent)
+        flashlightButton.set(image: UIImage(named: "icon_mediaPicker_camera_flashlight_auto_b")!, for: .status1, of: .darkContent)
+        flashlightButton.set(image: UIImage(named: "icon_mediaPicker_camera_flashlight_on")!, for: .status2, of: .lightContent)
+        flashlightButton.set(image: UIImage(named: "icon_mediaPicker_camera_flashlight_on_b")!, for: .status2, of: .darkContent)
+        flashlightButton.set(image: UIImage(named: "icon_mediaPicker_camera_flashlight_off")!, for: .status3, of: .lightContent)
+        flashlightButton.set(image: UIImage(named: "icon_mediaPicker_camera_flashlight_off_b")!, for: .status3, of: .darkContent)
+        return flashlightButton
+    }()
+    public let cameraOrientation = {() -> KSMediaPickerCameraToolBar.button in
+        let cameraOrientation = KSMediaPickerCameraToolBar.button()
+        cameraOrientation.set(image: UIImage(named: "icon_mediaPicker_camera_switch")!, for: .status1, of: .lightContent)
+        cameraOrientation.set(image: UIImage(named: "icon_mediaPicker_camera_switch_b")!, for: .status1, of: .darkContent)
+        return cameraOrientation
+    }()
+    
+    open var didChangedStyleCallback: ((KSMediaPickerCameraToolBar.button.style) -> Void)?
+    
+    open var style: KSMediaPickerCameraToolBar.button.style {
+        didSet {
+            if oldValue != style {
+                _didSet(style: style)
+                if didChangedStyleCallback != nil {
+                    didChangedStyleCallback!(style)
+                }
+            }
+        }
+    }
+    open var type = KSMediaPickerCameraToolBar.toolBarType.photos {
+        didSet {
+            let flashlightIsHidden = type != .photos
+            var isNeedAnimation = false
+            if flashlightIsHidden != flashlightButton.isHidden {
+                flashlightButton.isHidden = flashlightIsHidden
+                isNeedAnimation = true
+            }
+            let priviewSizeIsHidden = type == .videos
+            if priviewSizeIsHidden != priviewSizeButton.isHidden {
+                priviewSizeButton.isHidden = priviewSizeIsHidden
+                isNeedAnimation = true
+            }
+            if isNeedAnimation {
+                UIView.animate(withDuration: 0.2) {[weak self] in
+                    self?.layoutSubviews()
+                }
+            }
+        }
+    }
+     
+    public init(frame: CGRect, style: KSMediaPickerCameraToolBar.button.style) {
+        self.style = style
+        super.init(frame: frame)
+        _didSet(style: style)
+        backgroundColor = .clear
+        
+        addSubview(closeButton)
+        addSubview(priviewSizeButton)
+        addSubview(flashlightButton)
+        addSubview(cameraOrientation)
+    }
+    
+    public convenience init(style: KSMediaPickerCameraToolBar.button.style) {
+        self.init(frame: .zero, style: style)
+    }
+    
+    override open func layoutSubviews() {
+        super.layoutSubviews()
+        let windowSize = bounds.size
+        let windowWidth = windowSize.width
+        let windowHeight = windowSize.height
+        let floatZore = CGFloat(0.0)
+        
+        var buttons = [closeButton, cameraOrientation]
+        switch type {
+        case .photos:
+            buttons.insert(priviewSizeButton, at: 1)
+            buttons.insert(flashlightButton, at: 2)
+            break
+        case .noFlashlightPhotos:
+            buttons.insert(priviewSizeButton, at: 1)
+            break
+        case .videos:
+            break
+        }
+        
+        let count = CGFloat(buttons.count)
+        var viewX = floatZore
+        let viewY = floatZore
+        let viewW = CGFloat(70.0)
+        let viewH = windowHeight
+        let margin = (windowWidth-(viewW*count))/(count-1)
+        
+        for (i, button) in buttons.enumerated() {
+            viewX = (viewW+margin)*CGFloat(i)
+            button.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        }
+    }
+    
+    private func _didSet(style: KSMediaPickerCameraToolBar.button.style) {
+        closeButton.style = style
+        priviewSizeButton.style = style
+        priviewSizeButton.style = style
+        flashlightButton.style = style
+        flashlightButton.style = style
+        cameraOrientation.style = style
+        cameraOrientation.style = style
+    }
+}

+ 447 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCameraView.swift

@@ -0,0 +1,447 @@
+//
+//  KSMediaPickerCameraView.swift
+// 
+//
+//  Created by kinsun on 2019/3/11.
+//
+
+import UIKit
+
+extension KSMediaPickerCameraView {
+    
+    public enum style {
+        case unknown
+        case photo
+        case video
+    }
+    
+    private enum previewSize: UInt {
+        case square
+        case hdPicture
+        case hdVideo
+        
+        private static let _squareSize = CGSize(width: 1.0, height: 1.0)
+        private static let _hdPictureSize = CGSize(width: 3.0, height: 4.0)
+        private static let _hdVideoSize = CGSize(width: 9.0, height: 16.0)
+        
+        public var cgSizeValue: CGSize {
+            get {
+                switch self {
+                case .square:
+                    return previewSize._squareSize
+                case .hdPicture:
+                    return previewSize._hdPictureSize
+                case .hdVideo:
+                    return previewSize._hdVideoSize
+                }
+            }
+        }
+    }
+}
+
+import AVFoundation
+
+open class KSMediaPickerCameraView: UIView, AVCaptureFileOutputRecordingDelegate {
+
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    #if arch(i386) || arch(x86_64)
+    private let _frontCameraDevice: AVCaptureDevice?
+    private let _backCameraDevice: AVCaptureDevice?
+    #else
+    private let _frontCameraDevice: AVCaptureDevice
+    private let _backCameraDevice: AVCaptureDevice
+    #endif
+    private var _videoInput: AVCaptureDeviceInput?
+    private lazy var _audioInput = {() -> AVCaptureDeviceInput? in
+        if let audio = AVCaptureDevice.default(for: .audio) {
+            return try? AVCaptureDeviceInput(device: audio)
+        }
+        return nil
+    }()
+    private lazy var _imageOutput = AVCaptureStillImageOutput()
+    private lazy var _videoOutput = {() -> AVCaptureMovieFileOutput in
+        let videoOutput = AVCaptureMovieFileOutput()
+        videoOutput.movieFragmentInterval = CMTime(value: 1, timescale: 1)
+        return videoOutput
+    }()
+    private let _session = {() -> AVCaptureSession in
+        let session = AVCaptureSession()
+        session.sessionPreset = .photo
+        return session
+    }()
+    private let _previewLayer: AVCaptureVideoPreviewLayer
+    public let toolBar = KSMediaPickerCameraToolBar(style: .darkContent)
+    
+    public let scrollView = {() -> KSMediaPickerScrollView in
+        let scrollView = KSMediaPickerScrollView()
+        scrollView.backgroundColor = .clear
+        scrollView.showsHorizontalScrollIndicator = false
+        scrollView.bounces = false
+        scrollView.isPagingEnabled = true
+        return scrollView
+    }()
+    private let _takePhotoButton = {() -> UIButton in
+        let frame = CGRect(origin: .zero, size: CGSize(width: 80.0, height: 80.0))
+        let takePhotoButton = KSBorderButton(type: .custom)
+        takePhotoButton.frame = frame
+        let layer = takePhotoButton.layer
+        layer.masksToBounds = true
+        layer.borderWidth = 8.0
+        layer.cornerRadius = frame.size.height*0.5
+        let color = UIColor.ks_main
+        let borderColor = UIColor.ks_lightMain
+        takePhotoButton.setBackgroundColor(color, for: .normal)
+        takePhotoButton.setBackgroundColor(color.withAlphaComponent(0.5), for: .highlighted)
+        takePhotoButton.setBorderColor(borderColor, for: .normal)
+        takePhotoButton.setBorderColor(borderColor.withAlphaComponent(0.5), for: .highlighted)
+        return takePhotoButton
+    }()
+    private let _takeVideoButton = RECButton(frame: CGRect(origin: .zero, size: CGSize(width: 80.0, height: 80.0)))
+    
+    override public init(frame: CGRect) {
+        #if arch(i386) || arch(x86_64)
+        _frontCameraDevice = nil
+        _backCameraDevice = nil
+        #else
+        var frontCameraDevice: AVCaptureDevice? = nil
+        var backCameraDevice: AVCaptureDevice? = nil
+        let devices = AVCaptureDevice.devices(for: .video)
+        for device in devices {
+            switch device.position {
+            case .back:
+                backCameraDevice = device
+                break
+            case .front:
+                frontCameraDevice = device
+                break
+            default:
+                break
+            }
+        }
+        _frontCameraDevice = frontCameraDevice!
+        _backCameraDevice = backCameraDevice!
+        #endif
+        
+        _previewLayer = AVCaptureVideoPreviewLayer(session: _session)
+        _previewLayer.videoGravity = .resizeAspectFill
+        _previewLayer.backgroundColor = UIColor.ks_black.cgColor
+        startRunning = _session.startRunning
+        stopRunning = _session.stopRunning
+        super.init(frame: frame)
+        backgroundColor = .clear
+        #if arch(i386) || arch(x86_64)
+        _videoInput = nil
+        #else
+        _videoInput = _videoInputFrom(device: _backCameraDevice)
+        #endif
+        if let input = _videoInput, _session.canAddInput(input) {
+            _session.addInput(input)
+        }
+        
+        layer.addSublayer(_previewLayer)
+        
+        _takePhotoButton.addTarget(self, action: #selector(_didClick(takePhotoButton:)), for: .touchUpInside)
+        scrollView.addSubview(_takePhotoButton)
+        _takeVideoButton.addTarget(self, action: #selector(_didClick(takeVideoButton:)), for: .touchUpInside)
+        _takeVideoButton.didStopRunningCallback = {[weak self] (button) in
+            self?._didFinishRecVideo(button: button)
+        }
+        scrollView.addSubview(_takeVideoButton)
+        addSubview(scrollView)
+        toolBar.cameraOrientation.addTarget(self, action: #selector(_didClick(cameraOrientation:)), for: .touchUpInside)
+        toolBar.priviewSizeButton.addTarget(self, action: #selector(_didClick(priviewSizeButton:)), for: .touchUpInside)
+        toolBar.flashlightButton.addTarget(self, action: #selector(_didClick(flashlightButton:)), for: .touchUpInside)
+        addSubview(toolBar)
+    }
+    
+    override open func layoutSubviews() {
+        super.layoutSubviews()
+        let bounds = self.bounds
+        let windowSize = bounds.size
+        let windowWidth = windowSize.width
+        let floatZore = CGFloat(0.0)
+        
+        var viewX = floatZore
+        var viewY = UIView.statusBarSize.height
+        var viewW = windowWidth
+        var viewH = UIView.navigationBarSize.height
+        toolBar.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        scrollView.frame = bounds
+        scrollView.contentSize = CGSize(width: windowWidth*2.0, height: 0.0)
+        
+        let size = _takePhotoButton.bounds.size
+        viewW = size.width
+        viewH = size.height
+        viewX = (windowWidth-viewW)*0.5
+        viewY = scrollView.bounds.size.height-viewH
+        _takePhotoButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        viewX += windowWidth
+        _takeVideoButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+    }
+    
+    override open func layoutSublayers(of layer: CALayer) {
+        let windowSize = layer.bounds.size
+        let windowWidth = windowSize.width
+        let floatZore = CGFloat(0.0)
+        
+        let viewX = floatZore
+        let viewY: CGFloat
+        let viewW = windowWidth
+        let viewH: CGFloat
+        switch _previewSizeType {
+        case .square:
+            viewY = UIView.statusBarNavigationBarSize.height
+            viewH = viewW
+            break
+        default:
+            viewY = floatZore
+            let size = _previewSizeType.cgSizeValue
+            viewH = floor(size.height/size.width*viewW)
+            break
+        }
+        _previewLayer.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        super.layoutSublayers(of: layer)
+    }
+    
+    open var style = KSMediaPickerCameraView.style.unknown {
+        didSet {
+            let style = self.style
+            if oldValue != style {
+                let priviewSizeButton = toolBar.priviewSizeButton
+                priviewSizeButton.status = style == .photo ? .status2 : .status1
+                _didClick(priviewSizeButton: priviewSizeButton)
+                _didSet(style: style)
+            }
+        }
+    }
+    
+    private func _didSet(style: KSMediaPickerCameraView.style) {
+        _session.beginConfiguration()
+        switch style {
+        case .photo:
+            _session.sessionPreset = .photo
+            _session.removeOutput(_videoOutput)
+            if let audioInput = _audioInput {
+                _session.removeInput(audioInput)
+            }
+            if _session.canAddOutput(_imageOutput) {
+                _session.addOutput(_imageOutput)
+            }
+            break
+        case .video:
+            _session.sessionPreset = .iFrame960x540
+            _session.removeOutput(_imageOutput)
+            if let audioInput = _audioInput, _session.canAddInput(audioInput) {
+                _session.addInput(audioInput)
+            }
+            if _session.canAddOutput(_videoOutput) {
+                _session.addOutput(_videoOutput)
+                if let connection = _videoOutput.connections.first,
+                    connection.isVideoOrientationSupported,
+                    connection.videoOrientation != .portrait {
+                    connection.videoOrientation = .portrait
+                }
+            }
+            break
+        default:
+            break
+        }
+        _session.commitConfiguration()
+    }
+    
+    private var _previewSizeType = KSMediaPickerCameraView.previewSize.square {
+        didSet {
+            setNeedsLayout()
+        }
+    }
+
+    public let startRunning: () -> Void
+    public let stopRunning: () -> Void
+    open var didTakePhotoCallback: ((KSMediaPickerCameraView, UIImage) -> Void)?
+    open var didTakeVideoCallback: ((KSMediaPickerCameraView, URL) -> Void)?
+    
+    open var isBackCameraDevice: Bool {
+        return _videoInput?.device == _backCameraDevice
+    }
+    
+    @objc private func _didClick(cameraOrientation: KSMediaPickerCameraToolBar.button) {
+        #if arch(i386) || arch(x86_64)
+        #else
+        guard let input = _videoInput else {
+            return
+        }
+        
+        let trans = CATransition()
+        trans.duration = 0.5
+        trans.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
+        trans.type = CATransitionType(rawValue: "oglFlip")
+        
+        var device = input.device
+        if device == _frontCameraDevice {
+            device = _backCameraDevice
+            trans.subtype = .fromLeft
+        } else if device == _backCameraDevice {
+            device = _frontCameraDevice
+            trans.subtype = .fromRight
+        }
+        guard let newInput = _videoInputFrom(device: device) else {
+            return
+        }
+        _session.beginConfiguration()
+        _session.removeInput(input)
+        if _session.canAddInput(newInput) {
+            _session.addInput(newInput)
+            _videoInput = newInput
+            if self.style == .video {
+                toolBar.type = .videos
+            } else {
+                toolBar.type = device == _backCameraDevice ? .photos : .noFlashlightPhotos
+            }
+        } else {
+            _session.addInput(input)
+        }
+        _session.commitConfiguration()
+        _previewLayer.add(trans, forKey: nil)
+        #endif
+    }
+    
+    private func _videoInputFrom(device: AVCaptureDevice) -> AVCaptureDeviceInput? {
+        let input: AVCaptureDeviceInput?
+        do {
+            try input = AVCaptureDeviceInput(device: device)
+        } catch {
+            input = nil
+        }
+        return input
+    }
+    
+    @objc private func _didClick(priviewSizeButton: KSMediaPickerCameraToolBar.button) {
+        let status = priviewSizeButton.status
+        let newStatus: KSMediaPickerCameraToolBar.button.status
+        let sizeType: KSMediaPickerCameraView.previewSize
+        switch self.style {
+        case .photo:
+            switch status {
+            case .status1://1:1
+                newStatus = .status2
+                sizeType = .hdPicture
+                toolBar.style = .lightContent
+                break
+            case .status2://3:4
+                newStatus = .status1
+                sizeType = .square
+                toolBar.style = .darkContent
+                break
+            default:
+                return
+            }
+            break
+        case .video:
+            switch status {
+            case .status1://1:1
+                newStatus = .status3
+                sizeType = .hdVideo
+                break
+            case .status3://9:16
+                newStatus = .status1
+                sizeType = .square
+                break
+            default:
+                return
+            }
+            break
+        default:
+            return
+        }
+        priviewSizeButton.status = newStatus
+        _previewSizeType = sizeType
+    }
+    
+    @objc private func _didClick(flashlightButton: KSMediaPickerCameraToolBar.button) {
+        guard let device = _videoInput?.device,
+        self.style == .photo else {
+            return
+        }
+        try? device.lockForConfiguration()
+        let status = flashlightButton.status
+        let newStatus: KSMediaPickerCameraToolBar.button.status
+        let flashMode: AVCaptureDevice.FlashMode
+        switch status {
+        case .status1://auto
+            newStatus = .status2
+            flashMode = .on
+            break
+        case .status2://on
+            newStatus = .status3
+            flashMode = .off
+            break
+        case .status3://off
+            newStatus = .status1
+            flashMode = .auto
+            break
+        }
+        if device.isFlashModeSupported(flashMode) {
+            flashlightButton.status = newStatus
+            device.flashMode = flashMode
+        }
+    }
+    
+    @objc private func _didClick(takePhotoButton: KSBorderButton) {
+        guard let conntion = _imageOutput.connection(with: .video) else {
+            return
+        }
+        _imageOutput.captureStillImageAsynchronously(from: conntion, completionHandler: _didTakePhotoAfter)
+    }
+    
+    private func _didTakePhotoAfter(imageDataSampleBuffer: CMSampleBuffer?, error: Error?) {
+        guard let k_imageDataSampleBuffer = imageDataSampleBuffer,
+            let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(k_imageDataSampleBuffer) else {
+            return
+        }
+        let image = UIImage(JPEGData: imageData, of: _previewSizeType.cgSizeValue)
+        stopRunning()
+        if didTakePhotoCallback != nil {
+            didTakePhotoCallback!(self, image)
+        }
+    }
+    
+    @objc private func _didClick(takeVideoButton: RECButton) {
+        if takeVideoButton.isRunning {
+            _session.stopRunning()
+            _videoOutput.stopRecording()
+        } else {
+            takeVideoButton.startRunning()
+            let dateFormat = DateFormatter()
+            dateFormat.dateFormat = "yyyy_MM_dd_HH_mm_ss"
+            let tmpPath = NSTemporaryDirectory()
+            let filePath = tmpPath+dateFormat.string(from: Date())+".mov"
+            let fileURL = URL(fileURLWithPath: filePath)
+            _videoOutput.startRecording(to: fileURL, recordingDelegate: self)
+            _session.startRunning()
+        }
+    }
+    
+    private func _didFinishRecVideo(button: RECButton) {
+        if _videoFileURL != nil {
+            if didTakeVideoCallback != nil {
+                didTakeVideoCallback!(self, _videoFileURL!)
+            }
+            _videoFileURL = nil
+        }
+    }
+    
+    public func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
+        
+    }
+    
+    private var _videoFileURL: URL?
+    public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
+        _videoFileURL = outputFileURL
+        _takeVideoButton.stopRunning()
+    }
+}

+ 20 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCollectionView.h

@@ -0,0 +1,20 @@
+//
+//  KSMediaPickerCollectionView.h
+// 
+//
+//  Created by kinsun on 2019/3/10.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSMediaPickerCollectionView : UICollectionView
+
+@property (nonatomic, copy, nullable) void (^handlePanCallback)(UIPanGestureRecognizer *pan);
+@property (nonatomic, copy, nullable) void (^scrollViewDidScrollCallback)(KSMediaPickerCollectionView *scrollView);
+@property (nonatomic, copy, nullable) void (^scrollViewDidEndDraggingCallback)(KSMediaPickerCollectionView *scrollView, BOOL decelerate);
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 49 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerCollectionView.m

@@ -0,0 +1,49 @@
+//
+//  KSMediaPickerCollectionView.m
+// 
+//
+//  Created by kinsun on 2019/3/10.
+//
+
+#import "KSMediaPickerCollectionView.h"
+
+@interface UICollectionView ()
+
+- (void)handlePan:(UIPanGestureRecognizer *)pan;
+- (void)_scrollViewDidEndDraggingForDelegateWithDeceleration:(BOOL)decelerate;
+- (void)_notifyDidScroll;
+
+@end
+
+@implementation KSMediaPickerCollectionView
+
+- (void)setContentSize:(CGSize)contentSize {
+    CGFloat height = self.bounds.size.height;
+    if (contentSize.height < height) {
+        contentSize.height = height;
+    }
+    [super setContentSize:contentSize];
+}
+
+- (void)handlePan:(UIPanGestureRecognizer *)pan {
+    if (_handlePanCallback != nil) {
+        _handlePanCallback(pan);
+    }
+    [super handlePan:pan];
+}
+
+- (void)_scrollViewDidEndDraggingForDelegateWithDeceleration:(BOOL)decelerate {
+    if (_scrollViewDidEndDraggingCallback != nil) {
+        _scrollViewDidEndDraggingCallback(self, decelerate);
+    }
+    [super _scrollViewDidEndDraggingForDelegateWithDeceleration:decelerate];
+}
+
+- (void)_notifyDidScroll {
+    if (_scrollViewDidScrollCallback != nil) {
+        _scrollViewDidScrollCallback(self);
+    }
+    [super _notifyDidScroll];
+}
+
+@end

+ 56 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerNavigationView.swift

@@ -0,0 +1,56 @@
+//
+//  KSMediaPickerNavigationView.swift
+// 
+//
+//  Created by kinsun on 2019/3/5.
+//
+
+import UIKit
+
+extension KSMediaPickerView {
+    
+    open class navigationView: UIView {
+        
+        required public init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        public let nextButton = {() -> UIButton in
+            let nextButton = UIButton(type: .custom)
+            nextButton.titleLabel?.font = .systemFont(ofSize: 14.0)
+            nextButton.setTitle("NEXT".ks_mediaPickerKeyToLocalized, for: .normal)
+            nextButton.setTitleColor(.ks_wordMain, for: .normal)
+            nextButton.setTitleColor(.ks_wordMain_2, for: .disabled)
+            return nextButton
+        }()
+        
+        public let closeButton = {() -> UIButton in
+            let closeButton = UIButton(type: .custom)
+            closeButton.setImage(UIImage(named: "icon_mediaPicker_camera_close_b"), for: .normal)
+            return closeButton
+        }()
+        
+        override public init(frame: CGRect) {
+            super.init(frame: frame)
+            backgroundColor = .ks_white
+            addSubview(nextButton)
+            addSubview(closeButton)
+        }
+        
+        override open func layoutSubviews() {
+            super.layoutSubviews()
+            let windowSize = bounds.size
+            let windowWidth = windowSize.width
+            
+            var viewX = CGFloat(0.0)
+            let viewY = UIView.statusBarSize.height
+            let viewH = windowSize.height-viewY
+            var viewW = viewH+30.0
+            closeButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+            
+            viewW = nextButton.sizeThatFits(windowSize).width+30.0
+            viewX = windowWidth-viewW
+            nextButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        }
+    }
+}

+ 455 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerPreviewView.swift

@@ -0,0 +1,455 @@
+//
+//  KSMediaPickerPreviewView.swift
+// 
+//
+//  Created by kinsun on 2019/3/5.
+//
+
+import UIKit
+
+extension KSMediaPickerPreviewView {
+    
+    private class scrollView: UIScrollView, UIScrollViewDelegate {
+        
+        private enum imageDirection {
+            case equal
+            case transversal
+            case lengthwise
+        }
+        
+        required init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        public let imageView = UIImageView()
+        
+        override init(frame: CGRect) {
+            super.init(frame: frame)
+            backgroundColor = .clear
+            showsVerticalScrollIndicator = false
+            showsHorizontalScrollIndicator = false
+            alwaysBounceVertical = true
+            alwaysBounceHorizontal = true
+            maximumZoomScale = 3.0
+            clipsToBounds = true
+            if #available(iOS 11.0, *) {
+                contentInsetAdjustmentBehavior = .never
+            }
+            addSubview(imageView)
+            delegate = self
+        }
+        
+        private var _isSquare = false
+        
+        override open var frame: CGRect {
+            set {
+                if frame.size != newValue.size {
+                    let windowSize = newValue.size
+                    _isSquare = floor(windowSize.width) == floor(windowSize.height)
+                    _imageDirection = _imageDirection(from: _imageSize, windowSize)
+                }
+                if _isNeedLayoutSubviews {
+                    zoomScale = 1.0
+                    contentOffset = .zero
+                }
+                super.frame = newValue
+            }
+            get {
+                return super.frame
+            }
+        }
+        
+        private var _isNeedLayoutSubviews = true
+        
+        public func set(frame: CGRect, isNeedLayoutSubviews: Bool) {
+            _isNeedLayoutSubviews = isNeedLayoutSubviews
+            self.frame = frame
+        }
+        
+        open var itemModel: KSMediaPickerItemModel? {
+            didSet {
+                guard let k_itemModel = itemModel else {
+                    return
+                }
+                let asset = k_itemModel.asset
+                let floatWidth = CGFloat(asset.pixelWidth)
+                let floatHeight = CGFloat(asset.pixelHeight)
+                _imageSize = CGSize(width: floatWidth, height: floatHeight)
+            }
+        }
+        
+        private var _imageSize = CGSize.zero {
+            didSet {
+                _imageDirection = _imageDirection(from: _imageSize, frame.size)
+                _isNeedLayoutSubviews = true
+                setNeedsLayout()
+            }
+        }
+        
+        override func layoutSubviews() {
+            super.layoutSubviews()
+            guard _isNeedLayoutSubviews || imageView.frame.size == .zero else {
+                return
+            }
+            _isNeedLayoutSubviews = false
+            let offset: CGPoint
+            if _imageDirection == .equal {
+                imageView.frame = bounds
+                offset = .zero
+            } else if _imageSize != .zero {
+                let windowSize = frame.size
+                let windowWidth = windowSize.width
+                let windowHeight = windowSize.height
+                let floatZore = CGFloat(0.0)
+                let viewX: CGFloat
+                let viewY: CGFloat
+                let viewW: CGFloat
+                let viewH: CGFloat
+                
+                let imageWidth = _imageSize.width
+                let imageHeight = _imageSize.height
+                
+                if _imageDirection == .transversal {
+                    viewH = windowHeight
+                    viewW = imageWidth/imageHeight*viewH
+                    viewY = floatZore
+                    viewX = (windowWidth-viewW)*0.5
+                } else {
+                    viewW = windowWidth
+                    viewH = imageHeight/imageWidth*viewW
+                    viewX = floatZore
+                    viewY = (windowHeight-viewH)*0.5
+                }
+                imageView.frame = CGRect(origin: .zero, size: CGSize(width: viewW, height: viewH))
+                offset = CGPoint(x: -viewX, y: -viewY)
+            } else {
+                offset = .zero
+            }
+            contentSize = imageView.frame.size
+            zoomScale = itemModel?.zoomScale ?? 1.0
+            contentOffset = itemModel?.contentOffset ?? offset
+            
+            let minimumZoomScale: CGFloat
+            if _isSquare {
+                switch _imageDirection {
+                case .equal:
+                    minimumZoomScale = 1.0
+                    break
+                case .transversal:
+                    minimumZoomScale = frame.size.width/imageView.frame.size.width
+                    break
+                case .lengthwise:
+                    minimumZoomScale = frame.size.height/imageView.frame.size.height
+                    break
+                }
+            } else {
+                minimumZoomScale = 1.0
+            }
+            self.minimumZoomScale = minimumZoomScale
+        }
+        
+        private func _imageDirection(from imageSize: CGSize, _ superSize: CGSize) -> KSMediaPickerPreviewView.scrollView.imageDirection {
+            let superWidth = floor(superSize.width)
+            let superHeight = floor(superSize.height)
+            let imageWidth = floor(imageSize.width)
+            let imageHeight = floor(imageSize.height)
+            let constrainImageHeight = floor(imageHeight/imageWidth*superWidth)
+            let dirction: KSMediaPickerPreviewView.scrollView.imageDirection
+            if superHeight == constrainImageHeight {
+                dirction = .equal
+            } else {
+                let maxHeight = max(superHeight, constrainImageHeight)
+                if maxHeight == superHeight {
+                    dirction = .transversal
+                } else {
+                    dirction = .lengthwise
+                }
+            }
+            return dirction
+        }
+        
+        private var _imageDirection = KSMediaPickerPreviewView.scrollView.imageDirection.equal
+        
+        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
+            return imageView
+        }
+        
+        func scrollViewDidZoom(_ scrollView: UIScrollView) {
+            let contentSize = scrollView.contentSize
+            let contentSizeWidth = floor(contentSize.width)
+            let contentSizeHeight = floor(contentSize.height)
+            let size = scrollView.frame.size
+            
+            var center = scrollView.center
+            if contentSizeWidth >= floor(size.width) {
+                center.x = contentSizeWidth*0.5
+            }
+            if contentSizeHeight >= floor(size.height) {
+                center.y = contentSizeHeight*0.5
+            }
+            imageView.center = center
+        }
+    }
+}
+
+import Photos
+
+open class KSMediaPickerPreviewView: UIView {
+    
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    private let _videoView = {() -> KSVideoPlayerBaseView in
+        let videoView = KSVideoPlayerBaseView()
+        videoView.videoGravity = .resizeAspect
+        videoView.videoPlaybackFinished = {[weak videoView] in
+            videoView?.play()
+        }
+        videoView.isHidden = true
+        return videoView
+    }()
+    
+    private let _scrollview = KSMediaPickerPreviewView.scrollView()
+    
+    private let _changeSizeButton = {() -> UIButton in
+        let changeSizeButton = UIButton(type: .custom)
+        changeSizeButton.setImage(UIImage(named: "icon_mediaPicker_preview_nocut"), for: .normal)
+        changeSizeButton.setImage(UIImage(named: "icon_mediaPicker_preview_cut"), for: .selected)
+        changeSizeButton.backgroundColor = .clear
+        return changeSizeButton
+    }()
+    
+    private let _zoomButton = {() -> UIButton in
+        let zoomButton = UIButton(type: .custom)
+        zoomButton.setImage(UIImage(named: "icon_mediaPicker_preview_aspect_fit"), for: .normal)
+        zoomButton.setImage(UIImage(named: "icon_mediaPicker_preview_aspect_fill"), for: .selected)
+        let bundle = Bundle.main
+        zoomButton.setTitle("MEDIA_PICKER_SCALE_ASPECT_FIT".ks_mediaPickerKeyToLocalized(in: bundle), for: .normal)
+        zoomButton.setTitle("MEDIA_PICKER_SCALE_ASPECT_FILL".ks_mediaPickerKeyToLocalized(in: bundle), for: .selected)
+        zoomButton.titleLabel?.font = UIFont.systemFont(ofSize: 12.0)
+        zoomButton.setTitleColor(.ks_white, for: .normal)
+        zoomButton.backgroundColor = UIColor.ks_black.withAlphaComponent(0.3)
+        return zoomButton
+    }()
+
+    override public init(frame: CGRect) {
+        super.init(frame: frame)
+        backgroundColor = .ks_background
+        clipsToBounds = true
+        addSubview(_scrollview)
+        
+        _zoomButton.addTarget(self, action: #selector(_didClick(zoomButton:)), for: .touchUpInside)
+        addSubview(_zoomButton)
+        _changeSizeButton.addTarget(self, action: #selector(_didClick(changeSizeButton:)), for: .touchUpInside)
+        addSubview(_changeSizeButton)
+        
+        addSubview(_videoView)
+    }
+    
+    override open func layoutSubviews() {
+        super.layoutSubviews()
+        let bounds = self.bounds
+        _videoView.frame = bounds
+        
+        let windowSize = bounds.size
+        let windowWidth = windowSize.width
+        let windowHeight = windowSize.height
+        
+        let scrollviewSize = _scrollview.frame.size
+        var viewW = scrollviewSize.width
+        var viewH = scrollviewSize.height
+        var viewX = (windowWidth-viewW)*0.5
+        var viewY = (windowHeight-viewH)*0.5
+        _scrollview.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        viewW = _zoomButton.sizeThatFits(windowSize).width+12.0
+        viewH = CGFloat(20.0)
+        viewX = CGFloat(10.0)
+        viewY = windowHeight-viewH-10.0
+        _zoomButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        _zoomButton.layer.cornerRadius = viewH*0.5
+        
+        viewW = 30.0
+        viewH = viewW
+        viewY = windowHeight-viewH-10.0
+        _changeSizeButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+//        _changeSizeButton.layer.cornerRadius = viewH*0.5
+    }
+    
+    //isSelected = false 显示留白 isSelected = true 显示充满
+    @objc private func _didClick(zoomButton: UIButton) {
+        let scrollviewZoomScale = _scrollview.zoomScale
+        let zoomScale: CGFloat
+        if scrollviewZoomScale == 1.0 {
+            zoomScale = _scrollview.minimumZoomScale
+            zoomButton.isSelected = true
+        } else {
+            zoomScale = 1.0
+            zoomButton.isSelected = false
+        }
+        _scrollview.setZoomScale(zoomScale, animated: true)
+    }
+    
+    @objc private func _didClick(changeSizeButton: UIButton) {
+        let isChangedSize = changeSizeButton.isSelected
+        changeSizeButton.isSelected = !isChangedSize
+        let frame: CGRect
+        if isChangedSize {
+            frame = bounds
+        } else {
+            let windowSize = bounds.size
+            let windowWidth = windowSize.width
+            let windowHeight = windowSize.height
+            
+            let viewW = _minScrollViewSize.width
+            let viewH = _minScrollViewSize.height
+            let viewX = (windowWidth-viewW)*0.5
+            let viewY = (windowHeight-viewH)*0.5
+            frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        }
+        UIView.animate(withDuration: 0.2, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .layoutSubviews, animations: {[weak self] in
+            self?._scrollview.set(frame: frame, isNeedLayoutSubviews: true)
+        }, completion: nil)
+    }
+    
+    static private let _minScale = CGFloat(3.0/4.0)
+    
+    private var _minScrollViewSize = CGSize.zero
+    private var _normalScrollViewSize = CGSize.zero
+    
+    private var _itemModel: KSMediaPickerItemModel? {
+        didSet {
+            guard let itemModel = _itemModel else {
+                return
+            }
+            let asset = itemModel.asset
+            if asset.mediaType == .video {
+                _zoomButton.isHidden = true
+                _videoView.isHidden = false
+                _scrollview.isHidden = true
+                _changeSizeButton.isHidden = true
+                _videoView.coverView?.image = itemModel.thumb
+                PHImageManager.default().requestAVAsset(forVideo: asset, options: KSMediaPickerItemModel.videoOptions) {[weak self] (urlAsset, audioMix, info) in
+                    guard let videoView = self?._videoView, let videoAsset = urlAsset else {
+                        return
+                    }
+                    if Thread.current.isMainThread {
+                        videoView.playerItem = AVPlayerItem(asset: videoAsset)
+                        videoView.play()
+                    } else {
+                        DispatchQueue.main.async {
+                            videoView.playerItem = AVPlayerItem(asset: videoAsset)
+                            videoView.play()
+                        }
+                    }
+                }
+            } else {
+                let mainSize = UIScreen.main.bounds.size
+                _videoView.isHidden = true
+                if _videoView.isPlaying {
+                    _videoView.pause()
+                }
+                _scrollview.isHidden = false
+                let pixelWidth = asset.pixelWidth
+                let pixelHeight = asset.pixelHeight
+                
+                _scrollview.itemModel = itemModel
+                
+                let windowWidth = mainSize.width
+                if _isStandard {
+                    _zoomButton.isHidden = true
+                    _normalScrollViewSize = CGSize(width: windowWidth, height: windowWidth)
+                    if pixelWidth == pixelHeight {
+                        _changeSizeButton.isHidden = true
+                        _minScrollViewSize = _normalScrollViewSize
+                    } else {
+                        _changeSizeButton.isHidden = false
+                        let maxWidth = max(pixelHeight, pixelWidth)
+                        let minScale = KSMediaPickerPreviewView._minScale
+                        let floatWidth = CGFloat(pixelWidth)
+                        let floatHeight = CGFloat(pixelHeight)
+                        let scrollViewSize: CGSize
+                        if maxWidth == pixelWidth {//横向
+                            let scale = floatHeight/floatWidth
+                            let minHeight: CGFloat
+                            let minWidth = windowWidth
+                            if scale > minScale {
+                                minHeight = floor(floatHeight*minWidth/floatWidth)
+                            } else {
+                                minHeight = floor(minWidth*minScale)
+                            }
+                            scrollViewSize = CGSize(width: minWidth, height: minHeight)
+                        } else {//纵向
+                            let scale = floatWidth/floatHeight
+                            let minWidth: CGFloat
+                            let minHeight = windowWidth
+                            if scale > minScale {
+                                minWidth = floor(floatWidth*minHeight/floatHeight)
+                            } else {
+                                minWidth = floor(minHeight*minScale)
+                            }
+                            scrollViewSize = CGSize(width: minWidth, height: minHeight)
+                        }
+                        _minScrollViewSize = scrollViewSize
+                    }
+                } else {
+                    _changeSizeButton.isHidden = true
+                    _zoomButton.isSelected = false
+                    _zoomButton.isHidden = _changeSizeButton.isSelected
+                }
+                _scrollview.set(frame: CGRect(origin: .zero, size: _changeSizeButton.isSelected ? _minScrollViewSize : _normalScrollViewSize), isNeedLayoutSubviews: true)
+                setNeedsLayout()
+                _scrollview.imageView.image = itemModel.thumb
+                PHImageManager.default().requestImage(for: asset, targetSize: mainSize, contentMode: .aspectFit, options: KSMediaPickerItemModel.pictureOptions) {[weak self] (image, info) in
+                    self?._scrollview.imageView.image = image
+                }
+            }
+        }
+    }
+    
+    private var _isStandard = false
+    
+    public func set(itemModel: KSMediaPickerItemModel, isStandard: Bool = false) {
+        saveCurrentState()
+        _isStandard = isStandard
+        _itemModel = itemModel
+    }
+    
+    public func saveCurrentState() {
+        if let k_itemModel = _itemModel, k_itemModel.index > 0 {
+            if k_itemModel.asset.mediaType == .image {
+                k_itemModel.contentOffset = _scrollview.contentOffset
+                k_itemModel.zoomScale = _scrollview.zoomScale
+                let scrollviewFrame = _scrollview.frame
+                k_itemModel.contentSize = scrollviewFrame.size
+                var rect = _scrollview.convert(_scrollview.imageView.frame, to: self)
+                let scrollviewOrigin = scrollviewFrame.origin
+                rect.origin.x -= scrollviewOrigin.x
+                rect.origin.y -= scrollviewOrigin.y
+                k_itemModel.imageFrame = rect
+            } else {
+                k_itemModel.contentSize = _videoView.bounds.size
+            }
+        }
+    }
+    
+    open var isStandard: Bool {
+        return _isStandard
+    }
+    
+    open var itemModel: KSMediaPickerItemModel? {
+        return _itemModel
+    }
+    
+    public func videoPlay() {
+        if !_videoView.isHidden {
+            _videoView.play()
+        }
+    }
+    public func videoPause() {
+        if !_videoView.isHidden || _videoView.isPlaying {
+            _videoView.pause()
+        }
+    }
+}

+ 196 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerRECButton.swift

@@ -0,0 +1,196 @@
+//
+//  KSMediaPickerRECButton.swift
+// 
+//
+//  Created by kinsun on 2019/3/13.
+//
+
+import UIKit
+
+extension KSMediaPickerCameraView {
+    
+    open class RECButton: UIControl {
+        
+        required public init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        private let _recLayer = RECButton.RECLayer()
+        
+        override public init(frame: CGRect) {
+            super.init(frame: frame)
+            backgroundColor = .clear
+            layer.addSublayer(_recLayer)
+        }
+        
+        override open func layoutSublayers(of layer: CALayer) {
+            super.layoutSublayers(of: layer)
+            _recLayer.frame = layer.bounds
+        }
+        
+        override open var isHighlighted: Bool {
+            didSet {
+                alpha = isHighlighted ? 0.5 : 1.0
+            }
+        }
+        
+        open var didStopRunningCallback: ((RECButton) -> Void)?
+        open var numberOfSecondsSpentInATurn = TimeInterval(30.0)
+        open var maxRunningSeconds = TimeInterval(60.0)
+        private var _currentTime = TimeInterval(0.0)
+        private var _isRunning = false
+        open var isRunning: Bool {
+            get {
+                return _isRunning
+            }
+        }
+        
+        private var _timer: Timer?
+        
+        open func startRunning() {
+            stopRunning()
+            if !_isRunning {
+                _isRunning = true
+                let timer = Timer(timeInterval: 0.1, target: self, selector: #selector(_timerArrive(_:)), userInfo: nil, repeats: true)
+                RunLoop.main.add(timer, forMode: .common)
+                _timer = timer
+                _recLayer.isChangeToSquare = true
+                _timer?.fire()
+            }
+        }
+        
+        open func stopRunning() {
+            if _isRunning {
+                _timer?.invalidate()
+                _timer = nil
+                _recLayer.isChangeToSquare = false
+                _recLayer.progress = 0.0
+                _currentTime = 0.0
+                _isRunning = false
+                if didStopRunningCallback != nil {
+                    didStopRunningCallback!(self)
+                }
+            }
+        }
+        
+        @objc private func _timerArrive(_ timer: Timer) {
+            _currentTime += 0.1
+            _recLayer.progress = Double(_currentTime/numberOfSecondsSpentInATurn)
+            if _currentTime >= maxRunningSeconds {
+                stopRunning()
+            }
+        }
+    }
+
+}
+
+extension KSMediaPickerCameraView.RECButton {
+    
+    private class RECLayer: CALayer {
+        
+        required init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        private let _backCircleLayer = {() -> CAShapeLayer in
+            let backCircleLayer = CAShapeLayer()
+            backCircleLayer.fillColor = UIColor.clear.cgColor
+            backCircleLayer.strokeColor = UIColor.ks_white.withAlphaComponent(0.4).cgColor
+            backCircleLayer.lineWidth = 8.0
+            return backCircleLayer
+        }()
+        
+        private let _frontCircleLayer = {() -> CAShapeLayer in
+            let frontCircleLayer = CAShapeLayer()
+            frontCircleLayer.fillColor = UIColor.clear.cgColor
+            frontCircleLayer.strokeColor = UIColor.ks_white.cgColor
+            frontCircleLayer.lineWidth = 8.0
+            return frontCircleLayer
+        }()
+        
+        private let _centerLayer = {() -> CALayer in
+            let centerLayer = CALayer()
+            centerLayer.backgroundColor = UIColor.ks_white.cgColor
+            centerLayer.masksToBounds = true
+            return centerLayer
+        }()
+        
+        open var isChangeToSquare = false {
+            didSet {
+                setNeedsLayout()
+            }
+        }
+        
+        open var progress = 0.0 {
+            didSet {
+                setNeedsDisplay()
+            }
+        }
+        
+        override public init() {
+            super.init()
+            backgroundColor = UIColor.clear.cgColor
+            addSublayer(_backCircleLayer)
+            addSublayer(_frontCircleLayer)
+            addSublayer(_centerLayer)
+        }
+        
+        override func layoutSublayers() {
+            super.layoutSublayers()
+            let windowSize = bounds.size
+            let windowWidth = windowSize.width
+            let windowHeight = windowSize.height
+            
+            let lineWidth = _backCircleLayer.lineWidth
+            let x = lineWidth*0.5
+            let y = x
+            let width = windowWidth-x*2.0
+            let height = windowHeight-y*2.0
+            let frame = CGRect(x: x, y: y, width: width, height: height)
+            _backCircleLayer.frame = frame
+            _frontCircleLayer.frame = frame
+            _backCircleLayer.path = UIBezierPath(ovalIn: _backCircleLayer.bounds).cgPath
+            
+            let viewX: CGFloat
+            let viewY: CGFloat
+            let viewW: CGFloat
+            let viewH: CGFloat
+            if isChangeToSquare {
+                viewW = windowWidth*0.5
+                viewH = viewW
+                viewX = (windowWidth-viewW)*0.5
+                viewY = (windowHeight-viewH)*0.5
+                _centerLayer.cornerRadius = 5.0
+            } else {
+                viewX = _backCircleLayer.lineWidth
+                viewY = viewX
+                viewW = windowWidth-viewX*2.0
+                viewH = windowHeight-viewY*2.0
+                _centerLayer.cornerRadius = viewW*0.5
+            }
+            _centerLayer.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        }
+        
+        override func draw(in ctx: CGContext) {
+            super.draw(in: ctx)
+            let circlePath: UIBezierPath
+            let size = _frontCircleLayer.bounds.size
+            let width = size.width
+            let height = size.height
+            let center = CGPoint(x: width*0.5, y: height*0.5)
+            let radius = min(width, height)*0.5
+            let pi = CGFloat.pi*2.0
+            let startAngle = -(pi*0.25)
+            let endAngle = CGFloat(progress)*pi+startAngle
+            
+            let isDoubleLoop = Int(progress)%2 == 0
+            if isDoubleLoop {
+                circlePath = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
+            } else {
+                circlePath = UIBezierPath(arcCenter: center, radius: radius, startAngle: endAngle, endAngle: startAngle, clockwise: true)
+            }
+            _frontCircleLayer.path = circlePath.cgPath
+        }
+    }
+
+}

+ 26 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerScrollView.h

@@ -0,0 +1,26 @@
+//
+//  KSMediaPickerScrollView.h
+//  KSMediaPickerDemo
+//
+//  Created by kinsun on 2019/4/29.
+//  Copyright © 2019年 kinsun. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol KSMediaPickerScrollViewDelegate <NSObject, UIScrollViewDelegate>
+
+@optional
+- (void)scrollViewDidEndScroll:(UIScrollView *)scrollView;
+
+@end
+
+@interface KSMediaPickerScrollView : UIScrollView
+
+@property (nonatomic, weak) id<KSMediaPickerScrollViewDelegate> delegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 67 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerScrollView.m

@@ -0,0 +1,67 @@
+//
+//  KSMediaPickerScrollView.m
+//  KSMediaPickerDemo
+//
+//  Created by kinsun on 2019/4/29.
+//  Copyright © 2019年 kinsun. All rights reserved.
+//
+
+#import "KSMediaPickerScrollView.h"
+
+@interface UIScrollView ()
+
+- (void)_scrollViewDidEndDeceleratingForDelegate;
+- (void)_scrollViewDidEndDraggingForDelegateWithDeceleration:(BOOL)deceleration;
+- (void)_delegateScrollViewAnimationEnded;
+
+@end
+
+@implementation KSMediaPickerScrollView
+@dynamic delegate;
+
+- (void)_scrollViewDidEndDeceleratingForDelegate {
+    [super _scrollViewDidEndDeceleratingForDelegate];
+    __weak id<KSMediaPickerScrollViewDelegate> delegate = self.delegate;
+    if (delegate != nil) {
+        SEL selector = @selector(scrollViewDidEndScroll:);
+        if ([delegate respondsToSelector:selector]) {
+            BOOL scrollToScrollStop = !self.tracking && !self.dragging && !self.decelerating;
+            if (scrollToScrollStop) {
+#pragma clang diagnostic ignored"-Warc-performSelector-leaks"
+                [delegate performSelector:selector withObject:self];
+            }
+        }
+    }
+}
+
+- (void)_scrollViewDidEndDraggingForDelegateWithDeceleration:(BOOL)decelerate {
+    [super _scrollViewDidEndDraggingForDelegateWithDeceleration:decelerate];
+    if (!decelerate) {
+        __weak id<KSMediaPickerScrollViewDelegate> delegate = self.delegate;
+        if (delegate != nil) {
+            SEL selector = @selector(scrollViewDidEndScroll:);
+            if ([delegate respondsToSelector:selector]) {
+                BOOL dragToDragStop = self.tracking && !self.dragging && !self.decelerating;
+                if (dragToDragStop) {
+#pragma clang diagnostic ignored"-Warc-performSelector-leaks"
+                    [delegate performSelector:selector withObject:self];
+                }
+            }
+        }
+    }
+}
+
+- (void)_delegateScrollViewAnimationEnded {
+    [super _delegateScrollViewAnimationEnded];
+    __weak id<KSMediaPickerScrollViewDelegate> delegate = self.delegate;
+    if (delegate != nil) {
+        SEL selector = @selector(scrollViewDidEndScroll:);
+        if ([delegate respondsToSelector:selector]) {
+#pragma clang diagnostic ignored"-Warc-performSelector-leaks"
+            [delegate performSelector:selector withObject:self];
+        }
+    }
+}
+
+
+@end

+ 112 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerSelectIndicator.swift

@@ -0,0 +1,112 @@
+//
+//  KSMediaPickerSelectIndicator.swift
+//  KSMediaPickerDemo
+//
+//  Created by kinsun on 2019/5/8.
+//  Copyright © 2019年 kinsun. All rights reserved.
+//
+
+import UIKit
+
+extension KSMediaPickerViewImageCell {
+    
+    open class selectIndicator: UIControl {
+        
+        required public init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        private let _normalLayer = {() -> CALayer in
+            let normalLayer = CALayer()
+            normalLayer.backgroundColor = UIColor.ks_black.cgColor
+            normalLayer.borderColor = UIColor.ks_white.cgColor
+            normalLayer.borderWidth = 1.0
+            normalLayer.masksToBounds = true
+            normalLayer.contents = UIImage(named: "icon_ImagePicker_Selected")?.cgImage
+            normalLayer.opacity = 0.5
+            return normalLayer
+        }()
+        
+        private let _selectLayer = {() -> CALayer in
+            let selectLayer = CALayer()
+            selectLayer.backgroundColor = UIColor.ks_main.cgColor
+            selectLayer.borderColor = UIColor.ks_white.cgColor
+            selectLayer.borderWidth = 1.0
+            selectLayer.masksToBounds = true
+            selectLayer.isHidden = true
+            return selectLayer
+        }()
+        
+        private let _textLayer = {() -> CATextLayer in
+            let textLayer = CATextLayer()
+            textLayer.isWrapped = true
+            textLayer.alignmentMode = .center
+            textLayer.contentsScale = UIScreen.main.scale
+            let font = UIFont.systemFont(ofSize: 12.0)
+            let fontRef = CGFont(font.fontName as CFString)
+            textLayer.font = fontRef
+            textLayer.fontSize = font.pointSize
+            textLayer.foregroundColor = UIColor.ks_white.cgColor
+            return textLayer
+        }()
+        
+        override public init(frame: CGRect) {
+            super.init(frame: frame)
+            layer.addSublayer(_normalLayer)
+            layer.addSublayer(_selectLayer)
+            _selectLayer.addSublayer(_textLayer)
+        }
+        
+        override open func layoutSublayers(of layer: CALayer) {
+            super.layoutSublayers(of: layer)
+            let windowSize = layer.bounds.size
+            let windowWidth = windowSize.width
+            let windowHeight = windowSize.height
+            
+            let viewW = CGFloat(22.0)
+            var viewH = viewW
+            var viewX = (windowWidth-viewW)*0.5
+            var viewY = (windowHeight-viewH)*0.5
+            let frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+            _normalLayer.frame = frame
+            _selectLayer.frame = frame
+            let cornerRadius = viewW*0.5
+            _normalLayer.cornerRadius = cornerRadius
+            _selectLayer.cornerRadius = cornerRadius
+            
+            if isMultipleSelected {
+                viewH = _textLayer.fontSize
+                viewX = 0.0
+                viewY = (22.0-viewH)*0.5-1.0
+                _textLayer.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+            }
+        }
+        
+        open var index = UInt(0) {
+            didSet {
+                let isSelected = index > 0
+                if isMultipleSelected && isSelected {
+                    _textLayer.string = "\(index)"
+                }
+                _selectLayer.isHidden = !isSelected
+                _normalLayer.isHidden = isSelected
+            }
+        }
+        
+        open var isMultipleSelected = true {
+            didSet {
+                CATransaction.begin()
+                CATransaction.setDisableActions(true)
+                if isMultipleSelected {
+                    _textLayer.isHidden = false
+                    _selectLayer.contents = nil
+                } else {
+                    _textLayer.isHidden = true
+                    _selectLayer.contents = _normalLayer.contents
+                }
+                CATransaction.commit()
+                setNeedsLayout()
+            }
+        }
+    }
+}

+ 486 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerView.swift

@@ -0,0 +1,486 @@
+//
+//  KSMediaPickerView.swift
+// 
+//
+//  Created by kinsun on 2019/3/1.
+//
+
+import UIKit
+
+extension KSMediaPickerView {
+    
+    private class segmentedControl: KSSegmentedControl {
+        
+        fileprivate enum style {
+            case light
+            case dark
+        }
+        
+        private var _style = KSMediaPickerView.segmentedControl.style.light {
+            didSet {
+                _didSet(style: _style)
+            }
+        }
+        open var style: KSMediaPickerView.segmentedControl.style {
+            set {
+                if newValue != _style {
+                    _style = newValue
+                }
+            }
+            get {
+                return _style
+            }
+        }
+        
+        override public init(frame: CGRect) {
+            let bundle = Bundle.main
+            let items = ["MEDIA_PICKER_ALBUM_TAB_TITLE".ks_mediaPickerKeyToLocalized(in: bundle),
+                         "MEDIA_PICKER_CAMERA_TAB_TITLE".ks_mediaPickerKeyToLocalized(in: bundle),
+                         "MEDIA_PICKER_VIDEOCORDER_TAB_TITLE".ks_mediaPickerKeyToLocalized(in: bundle)]
+            super.init(frame: frame, items: items)
+            font = UIFont.systemFont(ofSize: 17.0)
+            _didSet(style: .light)
+        }
+        
+        private func _didSet(style: KSMediaPickerView.segmentedControl.style) {
+            switch style {
+            case .light:
+                normalTextColor = .ks_wordMain_2
+                selectedTextColor = .ks_main
+                indndicatorColor = .ks_main
+                break
+            case .dark:
+                let color = UIColor.ks_white
+                normalTextColor = color
+                selectedTextColor = color
+                indndicatorColor = color
+                break
+            }
+        }
+        
+        required init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+    }
+}
+
+open class KSMediaPickerView: UIView, KSMediaPickerScrollViewDelegate {
+    
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    public let scrollView = {() -> KSMediaPickerScrollView in
+        let scrollView = KSMediaPickerScrollView()
+        scrollView.showsHorizontalScrollIndicator = false
+        scrollView.isPagingEnabled = true
+        scrollView.bounces = false
+        if #available(iOS 11.0, *) {
+            scrollView.contentInsetAdjustmentBehavior = .never
+        }
+        return scrollView
+    }()
+    
+    public let albumNavigationView = KSMediaPickerView.navigationView()
+    
+    public let collectionView = {() -> KSMediaPickerCollectionView in
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .vertical
+        
+        let collectionView = KSMediaPickerCollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.backgroundColor = .clear
+        collectionView.alwaysBounceVertical = true
+        collectionView.clipsToBounds = true
+        collectionView.bounces = false
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        return collectionView
+    }()
+    
+    public let previewView = KSMediaPickerPreviewView()
+    
+    private let _toolBarSafeAreaView = {() -> UIView in
+        let toolBarSafeAreaView = UIView()
+        toolBarSafeAreaView.backgroundColor = .clear
+        return toolBarSafeAreaView
+    }()
+    
+    public let segmentedControl: KSSegmentedControl = KSMediaPickerView.segmentedControl(frame: .zero)
+    
+    private let _blackBackgroundLayer = {() -> CALayer in
+        let blackBackgroundLayer = CALayer()
+        blackBackgroundLayer.opacity = 0.0
+        blackBackgroundLayer.backgroundColor = UIColor.ks_black.cgColor
+        return blackBackgroundLayer
+    }()
+    
+    public let cameraView = KSMediaPickerCameraView()
+    
+    override public init(frame: CGRect) {
+        super.init(frame: frame)
+        backgroundColor = .ks_white
+        layer.addSublayer(_blackBackgroundLayer)
+        
+        scrollView.addSubview(collectionView)
+        scrollView.addSubview(previewView)
+        albumNavigationView.nextButton.isEnabled = false
+        scrollView.addSubview(albumNavigationView)
+        
+        cameraView.scrollView.delegate = self
+        scrollView.addSubview(cameraView)
+        
+        scrollView.delegate = self
+        addSubview(scrollView)
+        
+        collectionView.handlePanCallback = {[weak self] (pan) in
+            self?._collectionView(did: pan)
+        }
+        collectionView.scrollViewDidScrollCallback = {[weak self] (scrollView) in
+            self?._collectionViewDidScroll(scrollView)
+        }
+        collectionView.scrollViewDidEndDraggingCallback = {[weak self] (scrollView, decelerate) in
+            self?._collectionViewDidEndDragging(scrollView, decelerate: decelerate)
+        }
+        self.segmentedControl.didClickItem = {[weak self] (segmentedControl, index) in
+            self?.didClick(segmentedControl: segmentedControl, index: index)
+        }
+        
+        _toolBarSafeAreaView.addSubview(self.segmentedControl)
+        addSubview(_toolBarSafeAreaView)
+    }
+    
+    override open func layoutSublayers(of layer: CALayer) {
+        super.layoutSublayers(of: layer)
+        _blackBackgroundLayer.frame = layer.bounds
+    }
+    
+    override open func layoutSubviews() {
+        super.layoutSubviews()
+        let bounds = self.bounds
+        scrollView.frame = bounds
+        
+        let safeArea = UIEdgeInsets.safeAreaInsets
+        
+        let windowSize = bounds.size
+        let windowWidth = windowSize.width
+        let windowHeight = windowSize.height
+        let floatZore = CGFloat(0.0)
+        let safeBottomMargin = safeArea.bottom
+        
+        scrollView.contentSize = CGSize(width: windowWidth*2.0, height: 0.0)
+        
+        var viewW = windowWidth
+        var viewH = safeBottomMargin+48.0
+        var viewX = floatZore
+        var viewY = windowHeight-viewH
+        _toolBarSafeAreaView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        viewY = floatZore
+        viewH = 48.0
+        self.segmentedControl.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        let margin = CGFloat(3.0)
+        let columnCount = UInt(4)
+        let itemW = floor((windowWidth-margin*CGFloat(columnCount-1))/CGFloat(columnCount))
+        let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
+        layout.itemSize = CGSize(width: itemW, height: itemW)
+        layout.minimumLineSpacing = margin
+        layout.minimumInteritemSpacing = margin
+        layout.sectionInset = .zero
+        
+        viewX = floatZore
+        viewY = floatZore
+        viewW = windowWidth
+        viewH = UIView.statusBarNavigationBarSize.height
+        albumNavigationView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        let navHeight = albumNavigationView.frame.maxY
+        let baseY = previewView.frame.origin.y
+        viewX = floatZore
+        if baseY == 0 {
+            viewY = navHeight
+            _baseY = viewY
+        } else {
+            viewY = baseY
+        }
+        viewW = windowWidth
+        viewH = viewW
+        previewView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        let previewViewFrameMaxY = previewView.frame.maxY
+        viewY = floatZore
+        viewH = previewViewFrameMaxY+20.0
+        _previewGestureCorrespondingArea = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        
+        let toolBarSafeAreaViewHeight = _toolBarSafeAreaView.bounds.size.height
+        
+        viewX = floatZore
+        viewY = floatZore
+        viewW = windowWidth
+        viewH = windowHeight-toolBarSafeAreaViewHeight
+        let frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        collectionView.frame = frame
+        let conetntInset = UIEdgeInsets(top: previewViewFrameMaxY+3.0, left: 0.0, bottom: 0.0, right: 0.0)
+        collectionView.contentInset = conetntInset
+        collectionView.scrollIndicatorInsets = conetntInset
+        
+        viewX = collectionView.frame.maxX
+        viewY = floatZore
+        viewW = windowWidth
+        viewH = windowHeight-toolBarSafeAreaViewHeight
+        cameraView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+    }
+    
+    private var _baseY: CGFloat?
+    private var _previewGestureCorrespondingArea: CGRect?
+    private var _isInGestureCorrespondingArea = false
+    
+    private var _panBeginLocationY = CGFloat(0)
+    private var _isScrollDown = false
+    private var _isRetract = false {
+        didSet {
+            if albumNavigationView.isHidden != _isRetract {
+                let trans = CATransition()
+                trans.duration = 0.2
+                trans.type = .push
+                trans.subtype = _isRetract ? .fromTop : .fromBottom
+                albumNavigationView.isHidden = _isRetract
+                albumNavigationView.layer.add(trans, forKey: nil)
+            }
+        }
+    }
+    
+    private func _collectionView(did pan: UIPanGestureRecognizer) {
+        switch pan.state {
+        case .began:
+            _panBeginLocationY = pan.location(in: self).y
+            break
+        case .changed:
+            guard let baseY = _baseY else {
+                return
+            }
+            let location = pan.location(in: self)
+            let locationY = location.y
+            _isScrollDown = locationY > _panBeginLocationY
+            _isInGestureCorrespondingArea = _previewGestureCorrespondingArea != nil && _previewGestureCorrespondingArea!.contains(location)
+            if _isInGestureCorrespondingArea {
+                var previewFrame = previewView.frame
+                var y = locationY-previewFrame.size.height
+                if y >= baseY {
+                    y = baseY
+                }
+                previewFrame.origin.y = y
+                previewView.frame = previewFrame
+                
+                _previewGestureCorrespondingArea!.size.height = previewFrame.maxY+20.0
+            }
+            _panBeginLocationY = locationY
+            break
+        case .cancelled, .ended, .failed:
+            guard _isInGestureCorrespondingArea, let baseY = _baseY else {
+                return
+            }
+            var previewFrame = previewView.frame
+            let maxY = previewFrame.maxY
+            let boundary = (previewFrame.size.height+baseY)*(_isScrollDown ? 0.2 : 0.8)
+            if maxY < boundary {
+                _isRetract = true
+                previewFrame.origin.y = baseY-previewFrame.size.height
+            } else {
+                _isRetract = false
+                previewFrame.origin.y = baseY
+            }
+            
+            let height = previewFrame.maxY
+            _previewGestureCorrespondingArea!.size.height = height+20.0
+            
+            var topPoint: CGPoint? = nil
+            let offsetY = -collectionView.contentOffset.y
+            if offsetY > height {
+                topPoint = CGPoint(x: 0.0, y: -(height+3.0))
+            }
+            UIView.animate(withDuration: 0.2, animations: {[weak self, weak previewView] in
+                previewView?.frame = previewFrame
+                guard let k_topPoint = topPoint else {
+                    return
+                }
+                self?.collectionView.contentOffset = k_topPoint
+            })
+            break
+        default:
+            break
+        }
+    }
+    
+    private func _collectionViewDidScroll(_ scrollView: KSMediaPickerCollectionView) {
+        guard !_isInGestureCorrespondingArea, _isScrollDown, _isRetract, let baseY = _baseY else {
+            return
+        }
+        let offsetY = -(scrollView.contentOffset.y)
+        if offsetY >= baseY {
+            var previewFrame = previewView.frame
+            var y = offsetY-previewFrame.size.height
+            if y >= baseY {
+                y = baseY
+            }
+            previewFrame.origin.y = y
+            previewView.frame = previewFrame
+            
+            _previewGestureCorrespondingArea!.size.height = previewFrame.maxY+20.0
+        }
+    }
+    
+    private func _collectionViewDidEndDragging(_ scrollView: KSMediaPickerCollectionView, decelerate: Bool) {
+        var previewFrame = previewView.frame
+        let maxY = previewFrame.maxY
+        guard scrollView.contentOffset.y <= -maxY, !_isInGestureCorrespondingArea, let baseY = _baseY else {
+            return
+        }
+        let boundary = (previewFrame.size.height+baseY)*(_isScrollDown ? 0.2 : 0.8)
+        if maxY < boundary && !_isRetract {
+            _isRetract = true
+            previewFrame.origin.y = baseY-previewFrame.size.height
+        } else if _isRetract {
+            _isRetract = false
+            previewFrame.origin.y = baseY
+        } else {
+            return
+        }
+        
+        let height = previewFrame.maxY
+        _previewGestureCorrespondingArea!.size.height = height+20.0
+        
+        let topPoint = CGPoint(x: 0.0, y: -(height+3.0))
+        UIView.animate(withDuration: 0.2, animations: {[weak self, weak previewView] in
+            previewView?.frame = previewFrame
+            self?.collectionView.contentOffset = topPoint
+        })
+    }
+    
+    public func showPreview(_ animated: Bool) {
+        var previewFrame = previewView.frame
+        previewFrame.origin.y = _baseY ?? 0
+        _isRetract = false
+        if animated {
+            UIView.animate(withDuration: 0.2, animations: {[weak self] in
+                self?.previewView.frame = previewFrame
+            }) {[weak self] (finish) in
+                self?.setNeedsLayout()
+            }
+        } else {
+            setNeedsLayout()
+        }
+    }
+    
+    public func collectionViewScrollToTop() {
+        let point = CGPoint(x: 0.0, y: -collectionView.contentInset.top)
+        if !point.equalTo(collectionView.contentOffset) {
+            collectionView.setContentOffset(point, animated: false)
+            showPreview(false)
+        }
+    }
+    
+    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        switch scrollView {
+        case self.scrollView:
+            let offsetX = scrollView.contentOffset.x
+            let width = scrollView.bounds.size.width
+            guard offsetX <= scrollView.contentSize.width-width else {
+                return
+            }
+            let segmentedControl = self.segmentedControl
+            let page = UInt(ceil((offsetX-width*0.5)/width))
+            if page != segmentedControl.selectedSegmentIndex {
+                segmentedControl.selectedSegmentIndex = page
+            }
+            segmentedControl.updateIndicatorProportion(offsetX/width)
+            return
+        case cameraView.scrollView:
+            let offsetX = scrollView.contentOffset.x
+            let width = scrollView.contentSize.width-scrollView.bounds.size.width
+            CATransaction.begin()
+            _blackBackgroundLayer.opacity = Float(offsetX/width)
+            CATransaction.commit()
+            let seg = self.segmentedControl as! KSMediaPickerView.segmentedControl
+            let toolBar = cameraView.toolBar
+            let page = ceil((offsetX-width*0.5)/width)
+            if page == 0.0 {
+                seg.style = .light
+                toolBar.style = .darkContent
+                toolBar.type = cameraView.isBackCameraDevice ? .photos : .noFlashlightPhotos
+            } else {
+                seg.style = .dark
+                toolBar.style = .lightContent
+                toolBar.type = .videos
+            }
+            let u_page = UInt(page)+1
+            if u_page != seg.selectedSegmentIndex {
+                seg.selectedSegmentIndex = u_page
+            }
+            seg.updateIndicatorProportion((offsetX+width)/width)
+            return
+        default:
+            return
+        }
+    }
+    
+    public func scrollViewDidEndScroll(_ scrollView: UIScrollView) {
+        let page = self.segmentedControl.selectedSegmentIndex
+        if page == 0 {
+            cameraView.stopRunning()
+            if let callback = cameraView.toolBar.didChangedStyleCallback {
+                callback(.darkContent)
+            }
+            previewView.videoPlay()
+        } else {
+            previewView.videoPause()
+            if page == 1 {
+                cameraView.style = .photo
+            } else {
+                cameraView.style = .video
+            }
+            if let callback = cameraView.toolBar.didChangedStyleCallback {
+                callback(cameraView.toolBar.style)
+            }
+            cameraView.startRunning()
+        }
+    }
+    
+    public func didClick(segmentedControl: KSSegmentedControl, index: Int) {
+        switch index {
+        case 0:
+            scrollView.setContentOffset(.zero, animated: true)
+            cameraView.scrollView.contentOffset = .zero
+            break
+        case 1:
+            switch segmentedControl.selectedSegmentIndex {
+            case 0:
+                scrollView.setContentOffset(CGPoint(x: bounds.size.width, y: 0.0), animated: true)
+                cameraView.scrollView.contentOffset = .zero
+                break
+            case 2:
+                cameraView.scrollView.setContentOffset(.zero, animated: true)
+                break
+            default:
+                break
+            }
+            break
+        case 2:
+            switch segmentedControl.selectedSegmentIndex {
+            case 0:
+                scrollView.contentOffset = CGPoint(x: bounds.size.width, y: 0.0)
+                cameraView.scrollView.setContentOffset(CGPoint(x: bounds.size.width, y: 0.0), animated: true)
+                break
+            case 1:
+                cameraView.scrollView.setContentOffset(CGPoint(x: bounds.size.width, y: 0.0), animated: true)
+                break
+            default:
+                break
+            }
+            break
+        default:
+            break
+        }
+    }
+}

+ 141 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerViewImageCell.swift

@@ -0,0 +1,141 @@
+//
+//  KSMediaPickerViewImageCell.swift
+// 
+//
+//  Created by kinsun on 2019/3/1.
+//
+
+import UIKit
+import Photos
+
+open class KSMediaPickerViewImageCell: UICollectionViewCell {
+    
+    public let imageView = {() -> UIImageView in
+        let imageView = UIImageView()
+        imageView.contentMode = .scaleAspectFill
+        return imageView
+    }()
+    
+    private let _indView = KSMediaPickerViewImageCell.selectIndicator()
+    
+    private let _shelterLayer = {() -> CALayer in
+        let shelterLayer = CALayer()
+        shelterLayer.backgroundColor = UIColor.ks_white.withAlphaComponent(0.5).cgColor
+        shelterLayer.isHidden = true
+        return shelterLayer
+    }()
+    
+    private let _highlightView = {() -> UIView in
+        let highlightView = UIView()
+        highlightView.isHidden = true
+        highlightView.isUserInteractionEnabled = false
+        highlightView.backgroundColor = UIColor.ks_main.withAlphaComponent(0.5)
+        highlightView.layer.borderWidth = 2.0
+        highlightView.layer.borderColor = UIColor.ks_main.cgColor
+        return highlightView
+    }()
+    
+    override public init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.clipsToBounds = true
+        viewWillFinishInit()
+        contentView.addSubview(_highlightView)
+        contentView.addSubview(_indView)
+        _indView.addTarget(self, action: #selector(_didClick(selectedItem:)), for: .touchUpInside)
+        contentView.layer.addSublayer(_shelterLayer)
+    }
+    
+    open func viewWillFinishInit() {
+        contentView.addSubview(imageView)
+    }
+    
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override open func layoutSubviews() {
+        super.layoutSubviews()
+        let bounds = contentView.bounds
+        imageView.frame = bounds
+        _highlightView.frame = bounds
+        
+        let viewW = CGFloat(36.0)
+        let viewH = viewW
+        let viewX = bounds.size.width-viewW
+        let viewY = CGFloat(0.0)
+        _indView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+    }
+    
+    override open func layoutSublayers(of layer: CALayer) {
+        super.layoutSublayers(of: layer)
+        _shelterLayer.frame = contentView.layer.bounds
+    }
+    
+    open var isMultipleSelected: Bool {
+        set {
+            _indView.isMultipleSelected = newValue
+        }
+        get {
+            return _indView.isMultipleSelected
+        }
+    }
+    
+    open var isLoseFocus: Bool {
+        set {
+            _shelterLayer.isHidden = !newValue
+        }
+        get {
+            return !_shelterLayer.isHidden
+        }
+    }
+    
+    open var didSelectedItem: ((KSMediaPickerViewImageCell) -> UInt)?
+    
+    open var itemModel: KSMediaPickerItemModel! {
+        didSet {
+            isLoseFocus = itemModel.isLoseFocus
+            let thumb = itemModel.thumb
+            if thumb == nil {
+                PHImageManager.default().requestImage(for: itemModel.asset, targetSize: KSMediaPickerItemModel.thumbSize, contentMode:.aspectFit , options: KSMediaPickerItemModel.pictureViewerOptions) {[weak self] (image, info) in
+                    self?._updateThumb(image)
+                }
+            } else {
+                imageView.image = thumb
+            }
+            _indView.index = itemModel.index
+            itemIsHighlight = itemModel.isHighlight
+        }
+    }
+    
+    private func _updateThumb(_ image: UIImage?) {
+        itemModel.thumb = image
+        imageView.image = image
+    }
+    
+    @objc private func _didClick(selectedItem: KSMediaPickerViewImageCell.selectIndicator) {
+        guard didSelectedItem != nil else {
+            return
+        }
+        let index = didSelectedItem!(self)
+        selectedItem.index = index
+        itemModel.index = index
+    }
+    
+    open var itemIsHighlight: Bool {
+        set {
+            _highlightView.isHidden = !newValue
+        }
+        get {
+            return !_highlightView.isHidden
+        }
+    }
+    
+    open var imageViewFrameInSuperView: CGRect {
+        get {
+            let wrapperView = superview
+            let collectionView = wrapperView?.superview
+            let view = collectionView?.superview
+            return convert(imageView.frame, to: view)
+        }
+    }
+}

+ 119 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/View/KSMediaPickerViewVideoCell.swift

@@ -0,0 +1,119 @@
+//
+//  KSMediaPickerViewVideoCell.swift
+// 
+//
+//  Created by kinsun on 2019/3/5.
+//
+
+import UIKit
+
+open class KSMediaPickerViewVideoCell: KSMediaPickerViewImageCell {
+    
+    private let _infoView = KSMediaPickerViewVideoCell.infomationView()
+    
+    override open func viewWillFinishInit() {
+        super.viewWillFinishInit()
+        contentView.addSubview(_infoView)
+    }
+    
+    override open func layoutSubviews() {
+        super.layoutSubviews()
+        let windowSize = bounds.size
+        let viewW = windowSize.width
+        let viewH = CGFloat(20.0)
+        let viewX = CGFloat(0.0)
+        let viewY = windowSize.height-viewH
+        _infoView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+    }
+    
+    override open var itemModel: KSMediaPickerItemModel! {
+        didSet {
+            let duration = itemModel.asset.duration
+            _infoView.text = String(format: "%02.0f:%02td", duration/60.0, Int(duration)%60)
+        }
+    }
+}
+
+import CoreGraphics
+
+extension KSMediaPickerViewVideoCell {
+    
+    private class infomationView: UIView {
+        
+        open var text: String? {
+            get {
+                return _textLayer.string as? String
+            }
+            set {
+                _textLayer.string = newValue
+            }
+        }
+        
+        private let _gradientLayer = {() -> CAGradientLayer in
+            let gradientLayer = CAGradientLayer()
+            gradientLayer.colors = [UIColor.ks_black.withAlphaComponent(0.8).cgColor,
+                                    UIColor.clear.cgColor]
+            gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
+            gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
+            gradientLayer.locations = [NSNumber(value: 0), NSNumber(value: 1)]
+            return gradientLayer
+        }()
+        
+        private let _videoIndLayer = {() -> CALayer in
+            let videoIndLayer = CALayer()
+            videoIndLayer.contents = UIImage(named: "icon_ImagePicker_play")?.cgImage
+            return videoIndLayer
+        }()
+        
+        private let _textLayer = {() -> CATextLayer in
+            let textLayer = CATextLayer()
+            textLayer.isWrapped = true
+            textLayer.alignmentMode = .right
+            textLayer.contentsScale = UIScreen.main.scale
+            
+            let font = UIFont.systemFont(ofSize: 12.0)
+            textLayer.font = CGFont(font.fontName as CFString)
+            textLayer.fontSize = font.pointSize
+            textLayer.foregroundColor = UIColor.ks_white.cgColor
+            return textLayer
+        }()
+        
+        override init(frame: CGRect) {
+            super.init(frame: frame)
+            
+            backgroundColor = UIColor.clear
+            
+            layer.addSublayer(_gradientLayer)
+            layer.addSublayer(_videoIndLayer)
+            layer.addSublayer(_textLayer)
+        }
+        
+        required init?(coder aDecoder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        override func layoutSublayers(of layer: CALayer) {
+            super.layoutSublayers(of: layer)
+            let bounds = self.bounds
+            _gradientLayer.frame = bounds
+            
+            let windowSize = bounds.size
+            let windowWidth = windowSize.width
+            let windowHeight = windowSize.height
+            let margin = CGFloat(8.0)
+            
+            var viewW = CGFloat(12.0)
+            var viewH = viewW
+            var viewX = margin
+            var viewY = (windowHeight-viewH)*0.5
+            _videoIndLayer.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+            
+            viewX = _videoIndLayer.frame.maxX
+            viewW = windowWidth-viewX-margin
+            viewH = _textLayer.fontSize
+            viewY = (windowHeight-viewH)*0.5-1.0
+            _textLayer.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
+        }
+        
+    }
+}

+ 6 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_Selected.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_Selected.imageset/icon_ImagePicker_Selected@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_Selected.imageset/icon_ImagePicker_Selected@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_play.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_play.imageset/icon_ImagePicker_play@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_ImagePicker_play.imageset/icon_ImagePicker_play@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close.imageset/icon_mediaPicker_camera_close@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close.imageset/icon_mediaPicker_camera_close@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close_b.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close_b.imageset/icon_mediaPicker_camera_close_b@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_close_b.imageset/icon_mediaPicker_camera_close_b@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto.imageset/icon_mediaPicker_camera_flashlight_auto@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto.imageset/icon_mediaPicker_camera_flashlight_auto@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto_b.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto_b.imageset/icon_mediaPicker_camera_flashlight_auto_b@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_auto_b.imageset/icon_mediaPicker_camera_flashlight_auto_b@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off.imageset/icon_mediaPicker_camera_flashlight_off@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off.imageset/icon_mediaPicker_camera_flashlight_off@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off_b.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off_b.imageset/icon_mediaPicker_camera_flashlight_off_b@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_off_b.imageset/icon_mediaPicker_camera_flashlight_off_b@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on.imageset/icon_mediaPicker_camera_flashlight_on@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on.imageset/icon_mediaPicker_camera_flashlight_on@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on_b.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on_b.imageset/icon_mediaPicker_camera_flashlight_on_b@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_flashlight_on_b.imageset/icon_mediaPicker_camera_flashlight_on_b@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle.imageset/icon_mediaPicker_camera_rectangle@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle.imageset/icon_mediaPicker_camera_rectangle@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle_16_9.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle_16_9.imageset/icon_mediaPicker_camera_rectangle_16_9@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_rectangle_16_9.imageset/icon_mediaPicker_camera_rectangle_16_9@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square.imageset/icon_mediaPicker_camera_square@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square.imageset/icon_mediaPicker_camera_square@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square_b.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square_b.imageset/icon_mediaPicker_camera_square_b@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_square_b.imageset/icon_mediaPicker_camera_square_b@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch.imageset/icon_mediaPicker_camera_switch@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch.imageset/icon_mediaPicker_camera_switch@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch_b.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch_b.imageset/icon_mediaPicker_camera_switch_b@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_camera_switch_b.imageset/icon_mediaPicker_camera_switch_b@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fill.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fill.imageset/icon_mediaPicker_preview_aspect_fill@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fill.imageset/icon_mediaPicker_preview_aspect_fill@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fit.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fit.imageset/icon_mediaPicker_preview_aspect_fit@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_aspect_fit.imageset/icon_mediaPicker_preview_aspect_fit@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_cut.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_cut.imageset/icon_mediaPicker_preview_cut@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_cut.imageset/icon_mediaPicker_preview_cut@3x.png


+ 22 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_nocut.imageset/Contents.json

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

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_nocut.imageset/icon_mediaPicker_preview_nocut@2x.png


+ 0 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/PublishModule.xcassets/icon_mediaPicker_preview_nocut.imageset/icon_mediaPicker_preview_nocut@3x.png


Некоторые файлы не были показаны из-за большого количества измененных файлов