Browse Source

接入tx IM基础功能

Steven 1 year ago
parent
commit
2ecf328dac
100 changed files with 7184 additions and 5071 deletions
  1. 81 75
      KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj
  2. 1 1
      KulexiuForStudent/KulexiuForStudent.xcodeproj/xcshareddata/xcschemes/KulexiuForStudent.xcscheme
  3. 19 0
      KulexiuForStudent/KulexiuForStudent/AppDelegate+AppService.h
  4. 16 0
      KulexiuForStudent/KulexiuForStudent/AppDelegate+AppService.m
  5. 2 0
      KulexiuForStudent/KulexiuForStudent/AppDelegate.h
  6. 27 3
      KulexiuForStudent/KulexiuForStudent/AppDelegate.m
  7. 11 24
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSBaseWKWebViewController.m
  8. 2 32
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m
  9. 1 1
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSRCIMDataSource.m
  10. 1 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSTabBarViewController.h
  11. 27 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/KSLoginManager.h
  12. 106 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/KSLoginManager.m
  13. 38 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/TXIMLinsenter.h
  14. 171 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/TXIMLinsenter.m
  15. 1 1
      KulexiuForStudent/KulexiuForStudent/Common/Base/RCConnectionManager.m
  16. 20 14
      KulexiuForStudent/KulexiuForStudent/Common/Define/KSDomain.h
  17. 1 0
      KulexiuForStudent/KulexiuForStudent/Common/Define/PrefixHeader.pch
  18. 5 4
      KulexiuForStudent/KulexiuForStudent/Common/Define/UserKeyHeader.h
  19. 6 0
      KulexiuForStudent/KulexiuForStudent/Info.plist
  20. 11 7
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.h
  21. 33 792
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.m
  22. 2 6
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatListViewController.h
  23. 64 233
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatListViewController.m
  24. 17 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSConversationListController.h
  25. 715 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSConversationListController.m
  26. 24 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSGroupConversationController.h
  27. 93 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSGroupConversationController.m
  28. 5 5
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupMemberViewController.m
  29. 24 46
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupSettingViewController.m
  30. 1 1
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupMemberListCell.m
  31. 0 27
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Controller/KSSearchHistoryMessageController.h
  32. 0 318
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Controller/KSSearchHistoryMessageController.m
  33. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSChatSearchBar.h
  34. 167 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSChatSearchBar.m
  35. 16 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchResultListController.h
  36. 367 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchResultListController.m
  37. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchViewController.h
  38. 339 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchViewController.m
  39. 0 40
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Model/KSSearchResultModel.h
  40. 0 44
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Model/KSSearchResultModel.m
  41. 0 17
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSRCSearchBar.h
  42. 0 36
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSRCSearchBar.m
  43. 0 19
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchRCLabel.h
  44. 0 87
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchRCLabel.m
  45. 0 30
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchResultViewCell.h
  46. 0 153
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchResultViewCell.m
  47. 41 31
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m
  48. 6 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatListSearchView.h
  49. 11 5
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatListSearchView.m
  50. 0 1
      KulexiuForStudent/KulexiuForStudent/Module/Course/AccompanyCourse/Controller/AccompanyDetailViewController.m
  51. 6 5
      KulexiuForStudent/KulexiuForStudent/Module/Course/Controller/CourseViewController.m
  52. 5 3
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.m
  53. 0 4
      KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m
  54. 12 12
      KulexiuForStudent/KulexiuForStudent/Module/Live/Controller/LiveVideoRoomViewController.m
  55. 1 1
      KulexiuForStudent/KulexiuForStudent/Module/Live/View/SeatContentView.m
  56. 0 23
      KulexiuForStudent/KulexiuForStudent/Module/Login/Controller/SubjectChooseViewController.h
  57. 0 294
      KulexiuForStudent/KulexiuForStudent/Module/Login/Controller/SubjectChooseViewController.m
  58. 6 5
      KulexiuForStudent/KulexiuForStudent/Module/Login/Guide/Controller/GuideViewController.m
  59. 3 2
      KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfoManager.h
  60. 34 75
      KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfoManager.m
  61. 0 4
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Controller/MineViewController.m
  62. 11 9
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Homework/View/HomeworkBodyView.m
  63. 11 8
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLessonBodyView.m
  64. 1 17
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/ModifyPhoneChangeController.m
  65. 1 18
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/ModifyViewController.m
  66. 1 18
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/SettingViewController.m
  67. 1 24
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/UserSettingViewController.m
  68. 1 17
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/DeleteAccount/Controller/AccountDeleteViewController.m
  69. 1 1
      KulexiuForStudent/KulexiuForStudent/Module/SealClass/Sections/NewWhiteboard/KSWhiteboardView.m
  70. 28 3
      KulexiuForStudent/Podfile
  71. 224 12
      KulexiuForStudent/Podfile.lock
  72. 224 12
      KulexiuForStudent/Pods/Manifest.lock
  73. 4040 2363
      KulexiuForStudent/Pods/Pods.xcodeproj/project.pbxproj
  74. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/AFNetworking.xcscheme
  75. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Bugly.xcscheme
  76. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/CHIPageControl.xcscheme
  77. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/IQKeyboardManager.xcscheme
  78. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JCore.xcscheme
  79. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JPush.xcscheme
  80. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXCategoryView.xcscheme
  81. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXPagingView.xcscheme
  82. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MBProgressHUD.xcscheme
  83. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJExtension.xcscheme
  84. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJRefresh.xcscheme
  85. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Masonry.xcscheme
  86. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent-KulexiuForStudentUITests.xcscheme
  87. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent.xcscheme
  88. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudentTests.xcscheme
  89. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RSKImageCropper.xcscheme
  90. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Reachability.xcscheme
  91. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RongCloudIM.xcscheme
  92. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RongCloudRTC.xcscheme
  93. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SDWebImage.xcscheme
  94. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SSZipArchive.xcscheme
  95. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SocketRocket.xcscheme
  96. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard-Whiteboard.xcscheme
  97. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard.xcscheme
  98. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/YYModel.xcscheme
  99. 0 58
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/ZKCycleScrollView.xcscheme
  100. 40 5
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/xcschememanagement.plist

+ 81 - 75
KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj

@@ -9,7 +9,6 @@
 /* Begin PBXBuildFile section */
 		2723B5A227F1578300E0B90B /* CreateFansGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B59B27F1577E00E0B90B /* CreateFansGroupViewController.m */; };
 		2723B5A327F1578300E0B90B /* KSChatListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B59C27F1577F00E0B90B /* KSChatListViewController.m */; };
-		2723B5A427F1578300E0B90B /* KSChatConversationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B59E27F1578000E0B90B /* KSChatConversationViewController.m */; };
 		2723B5A527F1578300E0B90B /* ChatAddressViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5A027F1578100E0B90B /* ChatAddressViewController.m */; };
 		2723B5BA27F157B100E0B90B /* ChatAddressHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2723B5A627F157A200E0B90B /* ChatAddressHeaderView.xib */; };
 		2723B5BB27F157B100E0B90B /* ChatAddressBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5A727F157A300E0B90B /* ChatAddressBodyView.m */; };
@@ -27,11 +26,6 @@
 		2723B5CD27F157BE00E0B90B /* GroupListModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5C827F157B900E0B90B /* GroupListModel.m */; };
 		2723B5CE27F157BE00E0B90B /* KSRCloudMediaManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5CA27F157BB00E0B90B /* KSRCloudMediaManager.m */; };
 		2723B5CF27F157BE00E0B90B /* GroupMemberModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5CC27F157BE00E0B90B /* GroupMemberModel.m */; };
-		2723B61827F157D500E0B90B /* KSSearchHistoryMessageController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5D327F157D300E0B90B /* KSSearchHistoryMessageController.m */; };
-		2723B61927F157D500E0B90B /* KSSearchResultModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5D627F157D300E0B90B /* KSSearchResultModel.m */; };
-		2723B61A27F157D500E0B90B /* KSSearchResultViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5D827F157D300E0B90B /* KSSearchResultViewCell.m */; };
-		2723B61B27F157D500E0B90B /* KSSearchRCLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5DA27F157D300E0B90B /* KSSearchRCLabel.m */; };
-		2723B61C27F157D500E0B90B /* KSRCSearchBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5DB27F157D300E0B90B /* KSRCSearchBar.m */; };
 		2723B61D27F157D500E0B90B /* GroupNoticeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5E027F157D400E0B90B /* GroupNoticeViewController.m */; };
 		2723B61E27F157D500E0B90B /* GroupNoticeEditController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5E227F157D400E0B90B /* GroupNoticeEditController.m */; };
 		2723B61F27F157D500E0B90B /* GroupNoticeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2723B5E627F157D400E0B90B /* GroupNoticeModel.m */; };
@@ -438,6 +432,15 @@
 		BC27A076280FF61300F91E27 /* AccompanyDetailBottomView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A075280FF61300F91E27 /* AccompanyDetailBottomView.xib */; };
 		BC27A079280FFA2200F91E27 /* EvaluateDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC27A078280FFA2200F91E27 /* EvaluateDetailModel.m */; };
 		BC28582B2809036D0024697C /* StudentInfoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC28582A2809036D0024697C /* StudentInfoModel.m */; };
+		BC2888582A80F7BF0064B773 /* KSLoginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2888552A80F7BF0064B773 /* KSLoginManager.m */; };
+		BC2888592A80F7BF0064B773 /* TXIMLinsenter.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2888572A80F7BF0064B773 /* TXIMLinsenter.m */; };
+		BC28885C2A80F9880064B773 /* AppDelegate+AppService.m in Sources */ = {isa = PBXBuildFile; fileRef = BC28885B2A80F9880064B773 /* AppDelegate+AppService.m */; };
+		BC2888752A8101C80064B773 /* KSSearchResultListController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2888702A8101C70064B773 /* KSSearchResultListController.m */; };
+		BC2888762A8101C80064B773 /* KSChatSearchBar.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2888722A8101C80064B773 /* KSChatSearchBar.m */; };
+		BC2888772A8101C80064B773 /* KSSearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2888742A8101C80064B773 /* KSSearchViewController.m */; };
+		BC28887C2A8102890064B773 /* KSConversationListController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2888782A8102870064B773 /* KSConversationListController.m */; };
+		BC28887D2A8102890064B773 /* KSGroupConversationController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC28887A2A8102880064B773 /* KSGroupConversationController.m */; };
+		BC2888802A8102A20064B773 /* KSChatConversationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC28887F2A8102A20064B773 /* KSChatConversationViewController.m */; };
 		BC2BE91C28F951DE00CB5F92 /* DialPlateView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2BE91B28F951DE00CB5F92 /* DialPlateView.m */; };
 		BC2DFF4B28BDFE740056105A /* HomeTeacherLiveModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2DFF4A28BDFE730056105A /* HomeTeacherLiveModel.m */; };
 		BC2DFF4E28BE068D0056105A /* TeacherStyleFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2DFF4D28BE068D0056105A /* TeacherStyleFlowLayout.m */; };
@@ -467,7 +470,6 @@
 		BC49BAEC28D98C500031FF06 /* KSMetronomePlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = BC49BAEB28D98C500031FF06 /* KSMetronomePlayer.m */; };
 		BC4CC417288FD689004AD8EC /* LaunchAnimationView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CC416288FD689004AD8EC /* LaunchAnimationView.m */; };
 		BC4CF28E28D072C000961C61 /* WidgetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF28D28D072C000961C61 /* WidgetViewController.m */; };
-		BC50171227FC0D5600F8BCBC /* SubjectChooseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */; };
 		BC50171527FC0D8300F8BCBC /* SubjectChooseBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC50171427FC0D8300F8BCBC /* SubjectChooseBodyView.m */; };
 		BC50171727FC0D8E00F8BCBC /* SubjectChooseBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC50171627FC0D8D00F8BCBC /* SubjectChooseBodyView.xib */; };
 		BC5082B4283345A10031DD0A /* KSChatListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC5082B3283345A10031DD0A /* KSChatListCell.m */; };
@@ -998,10 +1000,8 @@
 		2723B59B27F1577E00E0B90B /* CreateFansGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CreateFansGroupViewController.m; sourceTree = "<group>"; };
 		2723B59C27F1577F00E0B90B /* KSChatListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSChatListViewController.m; sourceTree = "<group>"; };
 		2723B59D27F1577F00E0B90B /* ChatAddressViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatAddressViewController.h; sourceTree = "<group>"; };
-		2723B59E27F1578000E0B90B /* KSChatConversationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSChatConversationViewController.m; sourceTree = "<group>"; };
 		2723B59F27F1578100E0B90B /* KSChatListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSChatListViewController.h; sourceTree = "<group>"; };
 		2723B5A027F1578100E0B90B /* ChatAddressViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatAddressViewController.m; sourceTree = "<group>"; };
-		2723B5A127F1578200E0B90B /* KSChatConversationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSChatConversationViewController.h; sourceTree = "<group>"; };
 		2723B5A627F157A200E0B90B /* ChatAddressHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChatAddressHeaderView.xib; sourceTree = "<group>"; };
 		2723B5A727F157A300E0B90B /* ChatAddressBodyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatAddressBodyView.m; sourceTree = "<group>"; };
 		2723B5A827F157A300E0B90B /* GroupCreateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupCreateView.m; sourceTree = "<group>"; };
@@ -1028,16 +1028,6 @@
 		2723B5CA27F157BB00E0B90B /* KSRCloudMediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSRCloudMediaManager.m; sourceTree = "<group>"; };
 		2723B5CB27F157BD00E0B90B /* GroupMemberModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupMemberModel.h; sourceTree = "<group>"; };
 		2723B5CC27F157BE00E0B90B /* GroupMemberModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupMemberModel.m; sourceTree = "<group>"; };
-		2723B5D227F157D300E0B90B /* KSSearchHistoryMessageController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSearchHistoryMessageController.h; sourceTree = "<group>"; };
-		2723B5D327F157D300E0B90B /* KSSearchHistoryMessageController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSearchHistoryMessageController.m; sourceTree = "<group>"; };
-		2723B5D527F157D300E0B90B /* KSSearchResultModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSearchResultModel.h; sourceTree = "<group>"; };
-		2723B5D627F157D300E0B90B /* KSSearchResultModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSearchResultModel.m; sourceTree = "<group>"; };
-		2723B5D827F157D300E0B90B /* KSSearchResultViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSearchResultViewCell.m; sourceTree = "<group>"; };
-		2723B5D927F157D300E0B90B /* KSRCSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSRCSearchBar.h; sourceTree = "<group>"; };
-		2723B5DA27F157D300E0B90B /* KSSearchRCLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSearchRCLabel.m; sourceTree = "<group>"; };
-		2723B5DB27F157D300E0B90B /* KSRCSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSRCSearchBar.m; sourceTree = "<group>"; };
-		2723B5DC27F157D300E0B90B /* KSSearchResultViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSearchResultViewCell.h; sourceTree = "<group>"; };
-		2723B5DD27F157D300E0B90B /* KSSearchRCLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSearchRCLabel.h; sourceTree = "<group>"; };
 		2723B5E027F157D400E0B90B /* GroupNoticeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupNoticeViewController.m; sourceTree = "<group>"; };
 		2723B5E127F157D400E0B90B /* GroupNoticeEditController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupNoticeEditController.h; sourceTree = "<group>"; };
 		2723B5E227F157D400E0B90B /* GroupNoticeEditController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupNoticeEditController.m; sourceTree = "<group>"; };
@@ -1793,6 +1783,24 @@
 		BC27A078280FFA2200F91E27 /* EvaluateDetailModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EvaluateDetailModel.m; sourceTree = "<group>"; };
 		BC2858292809036C0024697C /* StudentInfoModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StudentInfoModel.h; sourceTree = "<group>"; };
 		BC28582A2809036D0024697C /* StudentInfoModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StudentInfoModel.m; sourceTree = "<group>"; };
+		BC2888542A80F7BF0064B773 /* TXIMLinsenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TXIMLinsenter.h; sourceTree = "<group>"; };
+		BC2888552A80F7BF0064B773 /* KSLoginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSLoginManager.m; sourceTree = "<group>"; };
+		BC2888562A80F7BF0064B773 /* KSLoginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSLoginManager.h; sourceTree = "<group>"; };
+		BC2888572A80F7BF0064B773 /* TXIMLinsenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TXIMLinsenter.m; sourceTree = "<group>"; };
+		BC28885A2A80F9870064B773 /* AppDelegate+AppService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AppDelegate+AppService.h"; sourceTree = "<group>"; };
+		BC28885B2A80F9880064B773 /* AppDelegate+AppService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AppDelegate+AppService.m"; sourceTree = "<group>"; };
+		BC28886F2A8101C60064B773 /* KSSearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSearchViewController.h; sourceTree = "<group>"; };
+		BC2888702A8101C70064B773 /* KSSearchResultListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSearchResultListController.m; sourceTree = "<group>"; };
+		BC2888712A8101C70064B773 /* KSChatSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSChatSearchBar.h; sourceTree = "<group>"; };
+		BC2888722A8101C80064B773 /* KSChatSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSChatSearchBar.m; sourceTree = "<group>"; };
+		BC2888732A8101C80064B773 /* KSSearchResultListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSearchResultListController.h; sourceTree = "<group>"; };
+		BC2888742A8101C80064B773 /* KSSearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSearchViewController.m; sourceTree = "<group>"; };
+		BC2888782A8102870064B773 /* KSConversationListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSConversationListController.m; sourceTree = "<group>"; };
+		BC2888792A8102880064B773 /* KSConversationListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSConversationListController.h; sourceTree = "<group>"; };
+		BC28887A2A8102880064B773 /* KSGroupConversationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSGroupConversationController.m; sourceTree = "<group>"; };
+		BC28887B2A8102890064B773 /* KSGroupConversationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSGroupConversationController.h; sourceTree = "<group>"; };
+		BC28887E2A8102A20064B773 /* KSChatConversationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSChatConversationViewController.h; sourceTree = "<group>"; };
+		BC28887F2A8102A20064B773 /* KSChatConversationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSChatConversationViewController.m; sourceTree = "<group>"; };
 		BC2BE91A28F951DE00CB5F92 /* DialPlateView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DialPlateView.h; sourceTree = "<group>"; };
 		BC2BE91B28F951DE00CB5F92 /* DialPlateView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DialPlateView.m; sourceTree = "<group>"; };
 		BC2DFF4928BDFE730056105A /* HomeTeacherLiveModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeTeacherLiveModel.h; sourceTree = "<group>"; };
@@ -1844,8 +1852,6 @@
 		BC4CC416288FD689004AD8EC /* LaunchAnimationView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LaunchAnimationView.m; sourceTree = "<group>"; };
 		BC4CF28C28D072C000961C61 /* WidgetViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetViewController.h; sourceTree = "<group>"; };
 		BC4CF28D28D072C000961C61 /* WidgetViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetViewController.m; sourceTree = "<group>"; };
-		BC50171027FC0D5600F8BCBC /* SubjectChooseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubjectChooseViewController.h; sourceTree = "<group>"; };
-		BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SubjectChooseViewController.m; sourceTree = "<group>"; };
 		BC50171327FC0D8300F8BCBC /* SubjectChooseBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubjectChooseBodyView.h; sourceTree = "<group>"; };
 		BC50171427FC0D8300F8BCBC /* SubjectChooseBodyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SubjectChooseBodyView.m; sourceTree = "<group>"; };
 		BC50171627FC0D8D00F8BCBC /* SubjectChooseBodyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SubjectChooseBodyView.xib; sourceTree = "<group>"; };
@@ -2699,44 +2705,16 @@
 		2723B5D027F157D300E0B90B /* Search */ = {
 			isa = PBXGroup;
 			children = (
-				2723B5D127F157D300E0B90B /* Controller */,
-				2723B5D427F157D300E0B90B /* Model */,
-				2723B5D727F157D300E0B90B /* View */,
+				BC2888712A8101C70064B773 /* KSChatSearchBar.h */,
+				BC2888722A8101C80064B773 /* KSChatSearchBar.m */,
+				BC2888732A8101C80064B773 /* KSSearchResultListController.h */,
+				BC2888702A8101C70064B773 /* KSSearchResultListController.m */,
+				BC28886F2A8101C60064B773 /* KSSearchViewController.h */,
+				BC2888742A8101C80064B773 /* KSSearchViewController.m */,
 			);
 			path = Search;
 			sourceTree = "<group>";
 		};
-		2723B5D127F157D300E0B90B /* Controller */ = {
-			isa = PBXGroup;
-			children = (
-				2723B5D227F157D300E0B90B /* KSSearchHistoryMessageController.h */,
-				2723B5D327F157D300E0B90B /* KSSearchHistoryMessageController.m */,
-			);
-			path = Controller;
-			sourceTree = "<group>";
-		};
-		2723B5D427F157D300E0B90B /* Model */ = {
-			isa = PBXGroup;
-			children = (
-				2723B5D527F157D300E0B90B /* KSSearchResultModel.h */,
-				2723B5D627F157D300E0B90B /* KSSearchResultModel.m */,
-			);
-			path = Model;
-			sourceTree = "<group>";
-		};
-		2723B5D727F157D300E0B90B /* View */ = {
-			isa = PBXGroup;
-			children = (
-				2723B5D827F157D300E0B90B /* KSSearchResultViewCell.m */,
-				2723B5D927F157D300E0B90B /* KSRCSearchBar.h */,
-				2723B5DA27F157D300E0B90B /* KSSearchRCLabel.m */,
-				2723B5DB27F157D300E0B90B /* KSRCSearchBar.m */,
-				2723B5DC27F157D300E0B90B /* KSSearchResultViewCell.h */,
-				2723B5DD27F157D300E0B90B /* KSSearchRCLabel.h */,
-			);
-			path = View;
-			sourceTree = "<group>";
-		};
 		2723B5DE27F157D400E0B90B /* GroupNotice */ = {
 			isa = PBXGroup;
 			children = (
@@ -2900,6 +2878,8 @@
 				2779336127E3249C0010E277 /* Common */,
 				275E8AA827E18F8800DD3F6E /* AppDelegate.h */,
 				275E8AA927E18F8800DD3F6E /* AppDelegate.m */,
+				BC28885A2A80F9870064B773 /* AppDelegate+AppService.h */,
+				BC28885B2A80F9880064B773 /* AppDelegate+AppService.m */,
 				275E8AAE27E18F8800DD3F6E /* ViewController.h */,
 				275E8AAF27E18F8800DD3F6E /* ViewController.m */,
 				275E8AB127E18F8800DD3F6E /* Main.storyboard */,
@@ -3135,12 +3115,16 @@
 				2723B5A027F1578100E0B90B /* ChatAddressViewController.m */,
 				2723B59A27F1577E00E0B90B /* CreateFansGroupViewController.h */,
 				2723B59B27F1577E00E0B90B /* CreateFansGroupViewController.m */,
-				2723B5A127F1578200E0B90B /* KSChatConversationViewController.h */,
-				2723B59E27F1578000E0B90B /* KSChatConversationViewController.m */,
 				2723B59F27F1578100E0B90B /* KSChatListViewController.h */,
 				2723B59C27F1577F00E0B90B /* KSChatListViewController.m */,
 				BC756CB728FE7D1D00AA9ECB /* KSChatUserDetailViewController.h */,
 				BC756CB828FE7D1D00AA9ECB /* KSChatUserDetailViewController.m */,
+				BC2888792A8102880064B773 /* KSConversationListController.h */,
+				BC2888782A8102870064B773 /* KSConversationListController.m */,
+				BC28887B2A8102890064B773 /* KSGroupConversationController.h */,
+				BC28887A2A8102880064B773 /* KSGroupConversationController.m */,
+				BC28887E2A8102A20064B773 /* KSChatConversationViewController.h */,
+				BC28887F2A8102A20064B773 /* KSChatConversationViewController.m */,
 			);
 			path = Controller;
 			sourceTree = "<group>";
@@ -3314,8 +3298,6 @@
 				275FA21127E7356B00CFEA2E /* PasswordLoginController.m */,
 				275FA21827E7356B00CFEA2E /* VefiCodeLoginController.h */,
 				275FA21427E7356B00CFEA2E /* VefiCodeLoginController.m */,
-				BC50171027FC0D5600F8BCBC /* SubjectChooseViewController.h */,
-				BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */,
 				BC542E4A28409E9E00633781 /* InstrumentChooseViewController.h */,
 				BC542E4928409E9E00633781 /* InstrumentChooseViewController.m */,
 			);
@@ -4060,6 +4042,7 @@
 		2779350B27E324A40010E277 /* Base */ = {
 			isa = PBXGroup;
 			children = (
+				BC2888532A80F7BF0064B773 /* LoginManger */,
 				BCED1595293D941100266AEB /* banzou.mp3 */,
 				BCC5839328A9EC5C00BAB4CF /* CloudLoadingSource */,
 				BC8EC02428926B2C00D51094 /* CustomLoading */,
@@ -4535,6 +4518,17 @@
 			path = RecordManager;
 			sourceTree = "<group>";
 		};
+		BC2888532A80F7BF0064B773 /* LoginManger */ = {
+			isa = PBXGroup;
+			children = (
+				BC2888542A80F7BF0064B773 /* TXIMLinsenter.h */,
+				BC2888552A80F7BF0064B773 /* KSLoginManager.m */,
+				BC2888562A80F7BF0064B773 /* KSLoginManager.h */,
+				BC2888572A80F7BF0064B773 /* TXIMLinsenter.m */,
+			);
+			path = LoginManger;
+			sourceTree = "<group>";
+		};
 		BC2DFF5928C097D00056105A /* AnimationSource */ = {
 			isa = PBXGroup;
 			children = (
@@ -6368,7 +6362,7 @@
 			isa = PBXProject;
 			attributes = {
 				BuildIndependentTargetsInParallel = 1;
-				LastUpgradeCheck = 1420;
+				LastUpgradeCheck = 1430;
 				TargetAttributes = {
 					275E8AA427E18F8800DD3F6E = {
 						CreatedOnToolsVersion = 13.2.1;
@@ -6729,11 +6723,9 @@
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent-KulexiuForStudentUITests/Pods-KulexiuForStudent-KulexiuForStudentUITests-resources-${CONFIGURATION}-input-files.xcfilelist",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent-KulexiuForStudentUITests/Pods-KulexiuForStudent-KulexiuForStudentUITests-resources-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -6768,11 +6760,9 @@
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent/Pods-KulexiuForStudent-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent/Pods-KulexiuForStudent-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -6829,11 +6819,9 @@
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent/Pods-KulexiuForStudent-resources-${CONFIGURATION}-input-files.xcfilelist",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent/Pods-KulexiuForStudent-resources-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -6846,11 +6834,9 @@
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent-KulexiuForStudentUITests/Pods-KulexiuForStudent-KulexiuForStudentUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-KulexiuForStudent-KulexiuForStudentUITests/Pods-KulexiuForStudent-KulexiuForStudentUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -6933,7 +6919,6 @@
 				BCB6353727F6D2A300ACFDCF /* TextMessageCell.m in Sources */,
 				BCB6346A27F6D29600ACFDCF /* LiveVideoRoomViewController.m in Sources */,
 				BCB6357227F6D2A300ACFDCF /* KSIMService.m in Sources */,
-				BC50171227FC0D5600F8BCBC /* SubjectChooseViewController.m in Sources */,
 				2779359727E324A80010E277 /* TZVideoPlayerController.m in Sources */,
 				BC802DBD28BC8E2C0079E350 /* HomeHotLiveCourseView.m in Sources */,
 				BCD886E7290A537600BC4EE6 /* KSGaugeSectorView.m in Sources */,
@@ -6974,6 +6959,7 @@
 				BCB909142852EF0000F5FF69 /* KSDragWindow.m in Sources */,
 				BCB6356727F6D2A300ACFDCF /* MemberChangeMessage.m in Sources */,
 				BC5F765029001C8D00B433E0 /* HomeDragButton.m in Sources */,
+				BC2888802A8102A20064B773 /* KSChatConversationViewController.m in Sources */,
 				2779353B27E324A60010E277 /* UrlDecode.m in Sources */,
 				BC40BA23281255F700DEC0D1 /* HomeCourseTipsView.m in Sources */,
 				BC12636D28FEA20100509E90 /* RecentMusicView.m in Sources */,
@@ -7037,6 +7023,7 @@
 				BCB6353527F6D2A300ACFDCF /* EmojiBoardView.m in Sources */,
 				277935BF27E324A90010E277 /* FSCalendarHeaderView.m in Sources */,
 				275FA1AE27E734C600CFEA2E /* KSImageAlert.m in Sources */,
+				BC2888582A80F7BF0064B773 /* KSLoginManager.m in Sources */,
 				275FA1DE27E7351900CFEA2E /* KSLocalWebViewController.m in Sources */,
 				2779354227E324A60010E277 /* UIImage+ResizeImage.m in Sources */,
 				277935B327E324A90010E277 /* FSCalendarCollectionView.m in Sources */,
@@ -7072,7 +7059,6 @@
 				2723B62927F157D500E0B90B /* KSChatComplainController.m in Sources */,
 				2779351527E324A60010E277 /* NSArray+KSSafe.m in Sources */,
 				BCD886E42908E69900BC4EE6 /* KSGaugeColorView.m in Sources */,
-				2723B61A27F157D500E0B90B /* KSSearchResultViewCell.m in Sources */,
 				BC48C3A92828FC7D00EE65C5 /* KSUploadManager.m in Sources */,
 				BC8A4599283DC33400094BBB /* TBXML.m in Sources */,
 				BC542E4B28409E9F00633781 /* InstrumentChooseViewController.m in Sources */,
@@ -7137,7 +7123,6 @@
 				BCB6346D27F6D29600ACFDCF /* KSEnterLiveroomManager.m in Sources */,
 				2779357327E324A70010E277 /* prodectButton.m in Sources */,
 				2723B5BD27F157B100E0B90B /* KSChatListSearchView.m in Sources */,
-				2723B61827F157D500E0B90B /* KSSearchHistoryMessageController.m in Sources */,
 				BCB6346E27F6D29600ACFDCF /* KSLiveStreamVideo.m in Sources */,
 				2779359327E324A80010E277 /* TZImageCropManager.m in Sources */,
 				2723B66727F15CFC00E0B90B /* ModifyBodyView.m in Sources */,
@@ -7166,6 +7151,7 @@
 				2779353927E324A60010E277 /* UIView+XIBView.m in Sources */,
 				2779355827E324A70010E277 /* UIImage+Addtions.m in Sources */,
 				BCB6355527F6D2A300ACFDCF /* RolePortraitView.m in Sources */,
+				BC2888592A80F7BF0064B773 /* TXIMLinsenter.m in Sources */,
 				277935D427E324A90010E277 /* UIView+ALFrame.m in Sources */,
 				275FA23C27E7356B00CFEA2E /* VefiBodyView.m in Sources */,
 				2779358027E324A80010E277 /* sortButton.m in Sources */,
@@ -7223,6 +7209,7 @@
 				BC8A45B5283DC33400094BBB /* EvaluateResultAlert.m in Sources */,
 				BCB6355B27F6D2A300ACFDCF /* ApplySpeechMessage.m in Sources */,
 				275FA24327E73DF600CFEA2E /* InstrumentDescView.m in Sources */,
+				BC28887C2A8102890064B773 /* KSConversationListController.m in Sources */,
 				2723B68027F15D3D00E0B90B /* FeedbackViewController.m in Sources */,
 				275FA1ED27E7351900CFEA2E /* KSUpdateManager.m in Sources */,
 				BCFEED7C28F810D70078A2B7 /* Tuner.swift in Sources */,
@@ -7302,7 +7289,9 @@
 				275FA1DF27E7351900CFEA2E /* RCConnectionManager.m in Sources */,
 				BCD9295D28F9447B006793E4 /* WMGaugeViewStyleFlatThin.m in Sources */,
 				275FA22B27E7356B00CFEA2E /* HomeViewController.m in Sources */,
+				BC2888762A8101C80064B773 /* KSChatSearchBar.m in Sources */,
 				BCFE53F12812898700AD6786 /* HomeVideoCourseCell.m in Sources */,
+				BC28887D2A8102890064B773 /* KSGroupConversationController.m in Sources */,
 				BCB908F02850B08D00F5FF69 /* KSChatLiveShareCell.m in Sources */,
 				277935C027E324A90010E277 /* FSCalendarTransitionCoordinator.m in Sources */,
 				BC802DA328BC5F8D0079E350 /* HomeHotMusicCellView.m in Sources */,
@@ -7340,12 +7329,12 @@
 				BC119218280ED6A900A716F7 /* MyLessonSearchView.m in Sources */,
 				BC802DB228BC70370079E350 /* HomeHotTalentCell.m in Sources */,
 				BCB6354C27F6D2A300ACFDCF /* VideoMaskView.m in Sources */,
+				BC2888752A8101C80064B773 /* KSSearchResultListController.m in Sources */,
 				2723B66D27F15CFC00E0B90B /* ModifyNameBodyView.m in Sources */,
 				BC8A459D283DC33400094BBB /* KSParseMessageModel.m in Sources */,
 				275FA23327E7356B00CFEA2E /* VefiCodeLoginController.m in Sources */,
 				BCB6359C27F6D2AB00ACFDCF /* ClassVideoListCell.m in Sources */,
 				BCD886E12907E7AE00BC4EE6 /* KSGaugeView.m in Sources */,
-				2723B61B27F157D500E0B90B /* KSSearchRCLabel.m in Sources */,
 				BC7E770F2900F38F00EB37AF /* TuningForkSettingView.m in Sources */,
 				275FA23B27E7356B00CFEA2E /* PasswordBodyView.m in Sources */,
 				BCB9090B2852EE9600F5FF69 /* KSLiveWebViewController.m in Sources */,
@@ -7386,6 +7375,7 @@
 				2779351B27E324A60010E277 /* UIControl+ButtonAction.m in Sources */,
 				BCB6354F27F6D2A300ACFDCF /* KSWhiteboardControl.m in Sources */,
 				27F9032F27E87C2E00C08A19 /* AudioPlayManager.m in Sources */,
+				BC28885C2A80F9880064B773 /* AppDelegate+AppService.m in Sources */,
 				2779357C27E324A70010E277 /* NSString+MD5.m in Sources */,
 				2779355D27E324A70010E277 /* KSHoldButton.m in Sources */,
 				2723B62027F157D500E0B90B /* GroupNoticeCell.m in Sources */,
@@ -7414,6 +7404,7 @@
 				BCFEED6A28F7E4F40078A2B7 /* SmallToolBodyView.m in Sources */,
 				2779352927E324A60010E277 /* zhPopupController.m in Sources */,
 				BC12636728FEA01F00509E90 /* RecentPracticeModel.m in Sources */,
+				BC2888772A8101C80064B773 /* KSSearchViewController.m in Sources */,
 				2779359527E324A80010E277 /* TZVideoEditedPreviewController.m in Sources */,
 				2723B63127F157D500E0B90B /* GroupSettingBodyView.m in Sources */,
 				BC119290280FB46100A716F7 /* KSVideoHelper.m in Sources */,
@@ -7451,12 +7442,10 @@
 				BCB908EE2850B08D00F5FF69 /* ShareLiveCellContentView.m in Sources */,
 				BC802DB828BC8C780079E350 /* HomeHotVideoCourseView.m in Sources */,
 				BCB6354127F6D2A300ACFDCF /* VideoListCell.m in Sources */,
-				2723B5A427F1578300E0B90B /* KSChatConversationViewController.m in Sources */,
 				BC8A45A2283DC33400094BBB /* SettingPageView.m in Sources */,
 				2723B62627F157D500E0B90B /* GroupApplyViewController.m in Sources */,
 				277935C427E324A90010E277 /* SDCycleScrollView.m in Sources */,
 				BC119293280FBC1100A716F7 /* HomeworkAddView.m in Sources */,
-				2723B61C27F157D500E0B90B /* KSRCSearchBar.m in Sources */,
 				BC4CC417288FD689004AD8EC /* LaunchAnimationView.m in Sources */,
 				277935C627E324A90010E277 /* SDQWMaskCustomModel.m in Sources */,
 				BCB6353C27F6D2A300ACFDCF /* MessageHelper.m in Sources */,
@@ -7470,7 +7459,6 @@
 				2723B62227F157D500E0B90B /* LFPopupMenu.m in Sources */,
 				BCB6348027F6D29600ACFDCF /* LiveSeatApplyView.m in Sources */,
 				2779357F27E324A80010E277 /* KeyChainTools.m in Sources */,
-				2723B61927F157D500E0B90B /* KSSearchResultModel.m in Sources */,
 				BCBFDF4B28115C6F0052AFE5 /* HomeHotCourseView.m in Sources */,
 				BC27A074280FF60B00F91E27 /* AccompanyDetailBottomView.m in Sources */,
 				275FA1E327E7351900CFEA2E /* WeakWebViewScriptMessageDelegate.m in Sources */,
@@ -7696,6 +7684,7 @@
 				CURRENT_PROJECT_VERSION = 1.4.7.1;
 				DEVELOPMENT_TEAM = B2AP53HHTU;
 				ENABLE_BITCODE = NO;
+				ENABLE_MODULE_VERIFIER = YES;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/KulexiuForStudent/Common/ThirdPart/UMSocialSDK/umcommonlog/umcommonlog_ios_2.0.0",
@@ -7748,6 +7737,8 @@
 					"$(PROJECT_DIR)/KulexiuForStudent/Common/ThirdPart/UMSocialSDK/share/share_ios_6.10.5/UMSocialSDKPlugin",
 				);
 				MARKETING_VERSION = 1.4.7;
+				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
 				PRODUCT_BUNDLE_IDENTIFIER = com.Colexiu.KulexiuForStudent;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_EMIT_LOC_STRINGS = YES;
@@ -7771,6 +7762,7 @@
 				CURRENT_PROJECT_VERSION = 1.4.7.1;
 				DEVELOPMENT_TEAM = B2AP53HHTU;
 				ENABLE_BITCODE = NO;
+				ENABLE_MODULE_VERIFIER = YES;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/KulexiuForStudent/Common/ThirdPart/UMSocialSDK/umcommonlog/umcommonlog_ios_2.0.0",
@@ -7823,6 +7815,8 @@
 					"$(PROJECT_DIR)/KulexiuForStudent/Common/ThirdPart/UMSocialSDK/share/share_ios_6.10.5/UMSocialSDKPlugin",
 				);
 				MARKETING_VERSION = 1.4.7;
+				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
 				PRODUCT_BUNDLE_IDENTIFIER = com.Colexiu.KulexiuForStudent;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_EMIT_LOC_STRINGS = YES;
@@ -7842,9 +7836,12 @@
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = B2AP53HHTU;
+				ENABLE_MODULE_VERIFIER = YES;
 				GENERATE_INFOPLIST_FILE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 15.2;
 				MARKETING_VERSION = 1.0;
+				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
 				PRODUCT_BUNDLE_IDENTIFIER = com.JingMing.KulexiuForStudentTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_EMIT_LOC_STRINGS = NO;
@@ -7862,9 +7859,12 @@
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = P664H7S5LL;
+				ENABLE_MODULE_VERIFIER = YES;
 				GENERATE_INFOPLIST_FILE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 15.2;
 				MARKETING_VERSION = 1.0;
+				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
 				PRODUCT_BUNDLE_IDENTIFIER = com.JingMing.KulexiuForStudentTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_EMIT_LOC_STRINGS = NO;
@@ -7881,8 +7881,11 @@
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = P664H7S5LL;
+				ENABLE_MODULE_VERIFIER = YES;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
+				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
 				PRODUCT_BUNDLE_IDENTIFIER = com.JingMing.KulexiuForStudentUITests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_EMIT_LOC_STRINGS = NO;
@@ -7899,8 +7902,11 @@
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = P664H7S5LL;
+				ENABLE_MODULE_VERIFIER = YES;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
+				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
 				PRODUCT_BUNDLE_IDENTIFIER = com.JingMing.KulexiuForStudentUITests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_EMIT_LOC_STRINGS = NO;

+ 1 - 1
KulexiuForStudent/KulexiuForStudent.xcodeproj/xcshareddata/xcschemes/KulexiuForStudent.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1430"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 19 - 0
KulexiuForStudent/KulexiuForStudent/AppDelegate+AppService.h

@@ -0,0 +1,19 @@
+//
+//  AppDelegate+AppService.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2023/8/7.
+//
+
+#import "AppDelegate.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface AppDelegate (AppService)
+
+//单例
++ (AppDelegate *)shareAppDelegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 16 - 0
KulexiuForStudent/KulexiuForStudent/AppDelegate+AppService.m

@@ -0,0 +1,16 @@
+//
+//  AppDelegate+AppService.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2023/8/7.
+//
+
+#import "AppDelegate+AppService.h"
+
+@implementation AppDelegate (AppService)
+
++ (AppDelegate *)shareAppDelegate{
+    return (AppDelegate *)[[UIApplication sharedApplication] delegate];
+}
+
+@end

+ 2 - 0
KulexiuForStudent/KulexiuForStudent/AppDelegate.h

@@ -12,6 +12,8 @@
 
 @interface AppDelegate : UIResponder <UIApplicationDelegate>
 
+@property (nonatomic, strong) NSData *deviceToken;
+
 @property (strong, nonatomic) UIWindow *window;
 @property (nonatomic, strong) KSTabBarViewController *tabBarController;
 

+ 27 - 3
KulexiuForStudent/KulexiuForStudent/AppDelegate.m

@@ -39,6 +39,10 @@
 #import "LaunchAnimationViewController.h"
 #import "KSEnterLiveroomManager.h"
 
+#import "TXIMLinsenter.h"
+#import <TUICore/TUIConfig.h>
+#import <TUIChat/TUIChat.h>
+
 @interface RCNaviDataInfo : NSObject
 
 @property (nonatomic, assign) NSTimeInterval uploadVideoDurationLimit;
@@ -402,6 +406,26 @@ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
     
     // 融云
     [[RCIMClient sharedRCIMClient] setDeviceTokenData:deviceToken];
+    
+    if ([TXIM_LINSENTER isCurrentUserLoginIM]) {
+        [self registerTXIMDeviceToken:deviceToken];
+    }
+    else {
+        self.deviceToken = deviceToken;
+    }
+}
+
+- (void)registerTXIMDeviceToken:(NSData *)deviceToken {
+    if (deviceToken) {
+        V2TIMAPNSConfig *config = [[V2TIMAPNSConfig alloc] init];
+        config.businessID = TXOfflinePushCertificateIDForAPNS;
+        config.token = deviceToken;
+        [[V2TIMManager sharedInstance] setAPNS:config succ:^{
+            NSLog(@"%s, succ", __func__);
+        } fail:^(int code, NSString *desc) {
+            NSLog(@"%s, fail, %d, %@", __func__, code, desc);
+        }];
+    }
 }
 
 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
@@ -481,7 +505,7 @@ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
     if (status == ConnectionStatus_Unconnected) {  // 连接失败或未连接 需要重新连接
         NSString *token = UserDefault(TokenKey);
         if (![NSString isEmptyString:token]) {
-            [USER_MANAGER checkTokenEnableConnectRongCloud];
+            [USER_MANAGER checkTokenEnableConnectIM];
         }
     }
     // 退到后台发送消息
@@ -771,9 +795,9 @@ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
             NSString *newToken = [dic ks_stringValueForKey:@"data"];
             if (![NSString isEmptyString:newToken]) {
-                UserDefaultSet(newToken, RongTokenKey);
+                UserDefaultSet(newToken, IM_TOKEN);
                 [[NSUserDefaults standardUserDefaults] synchronize];
-                [USER_MANAGER checkTokenEnableConnectRongCloud];
+                [USER_MANAGER checkTokenEnableConnectIM];
             }
         }
         else {

+ 11 - 24
KulexiuForStudent/KulexiuForStudent/Common/Base/KSBaseWKWebViewController.m

@@ -18,6 +18,7 @@
 #import "RCConnectionManager.h"
 #import "KSAccompanyWebViewController.h"
 #import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
 #import "KSOrderManager.h"
 #import "AddressListViewController.h"
 #import "KSEnterLiveroomManager.h"
@@ -486,9 +487,10 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
         NSString *targetId = [valueDic ks_stringValueForKey:@"id"];
         if ([[valueDic ks_stringValueForKey:@"type"] isEqualToString:@"single"]) { // 单聊
             
+            TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+            model.userID = targetId;
             KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
-            ctrl.targetId = targetId;
-            ctrl.conversationType = ConversationType_PRIVATE;
+            ctrl.conversation = model;
             [self.navigationController pushViewController:ctrl animated:YES];
             
         }
@@ -497,11 +499,11 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
                 [self MBPShow:@"报名未结束,暂无群组"];
                 return;
             }
-            KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
-            ctrl.targetId = targetId;
-            ctrl.conversationType = ConversationType_GROUP;
-            [self.navigationController pushViewController:ctrl animated:YES];
-        }
+            TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+            model.groupID = targetId;
+            KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+            ctrl.conversation = model;
+            [self.navigationController pushViewController:ctrl animated:YES];        }
     }
     else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"chooseFile"]) {
         NSDictionary *valueDic = [parm ks_dictionaryValueForKey:@"content"];
@@ -761,11 +763,6 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
 
 // 返回登录页面
 - (void)backLoginView {
-    USER_MANAGER.hasShowFlash = NO;
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
     
     NSString *webUrl = [self.url copy];
     if ([webUrl containsString:@"Authorization="]) {
@@ -799,18 +796,8 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
     // 当前失败的H5地址
     UserDefaultSetObjectForKey(webUrl, FAIL_WEB_URL);
     
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
-    [KSNetworkingManager clearRequestHeader];
-    LoginViewController *loginVC = [[LoginViewController alloc] init];
-    CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    appDelegate.window.rootViewController = navCtrl;
-    
+    // 退出登录
+    [APPLOGIN_MANAGER logoutAction];
 }
  
 #pragma mark ----- WKWebView delegate

+ 2 - 32
KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m

@@ -52,6 +52,7 @@
 // 设置json提交方式
 + (void)configRequestMethodJSON {
     [VoNetworking sharedManager].httpSessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
+    [[VoNetworking sharedManager] configHttpHeader:@{@"Content-Type":@"application/json"}];
     [self configRequestHeader];
 }
 
@@ -163,38 +164,7 @@
 }
 
 + (void)logoutAction {
-    USER_MANAGER.hasShowFlash = NO;
-    [self clearRequestHeader];
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    // 清除数据信息
-    UserDefaultRemoveObjectForKey(TokenKey);
-    UserDefaultRemoveObjectForKey(RongTokenKey);
-
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
-
-    // 回到登录界面
-    UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
-    if ([vc.presentedViewController isKindOfClass:NSClassFromString(@"NewClassroomViewController")]) {
-        [[NSNotificationCenter defaultCenter] postNotificationName:@"classroomLogout" object:nil];
-    }
-    else if ([vc isKindOfClass:[UITabBarController class]]) {
-        if ([vc.presentedViewController isKindOfClass:NSClassFromString(@"CustomNavViewController")]) {
-            CustomNavViewController *nav = (CustomNavViewController *)vc.presentedViewController;
-            if ([nav.visibleViewController isKindOfClass:NSClassFromString(@"LiveVideoRoomViewController")] || [nav.visibleViewController isKindOfClass:NSClassFromString(@"KSLiveWebViewController")]) {
-                [[NSNotificationCenter defaultCenter] postNotificationName:@"liveroomLogout" object:nil];
-                return;
-            }
-            else if ([nav.visibleViewController isKindOfClass:NSClassFromString(@"InstrumentChooseViewController")]) {
-                [[NSNotificationCenter defaultCenter] postNotificationName:@"LogoutAction" object:nil];
-                return;
-            }
-        }
-        [self backLoginView];
-    }
+    [APPLOGIN_MANAGER logoutAction];
 }
 
 // 返回到登录页面

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Common/Base/KSRCIMDataSource.m

@@ -98,7 +98,7 @@
         }];
     }
     else {
-        RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:UserDefault(RongCloudID) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
+        RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:UserDefault(IM_USERID) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
         return completion(user);
     }
 }

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/KSTabBarViewController.h

@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 
 #define CHATVIEW_REFRESH (@"chatViewRefresh")
+#define CHATVIEW_REFRESHSTATUS (@"chatViewRefreshStatus")
 
 NS_ASSUME_NONNULL_BEGIN
 

+ 27 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/KSLoginManager.h

@@ -0,0 +1,27 @@
+//
+//  KSLoginManager.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2023/8/7.
+//
+
+#import <Foundation/Foundation.h>
+
+#define APPLOGIN_MANAGER ([KSLoginManager shareInstance])
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// 登录管理实例
+@interface KSLoginManager : NSObject
+
++ (instancetype)shareInstance;
+
+- (void)loginAction;
+
+- (void)logoutAction;
+
+- (NSString *)getVisableControllerName;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 106 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/KSLoginManager.m

@@ -0,0 +1,106 @@
+//
+//  KSLoginManager.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2023/8/7.
+//
+
+#import "KSLoginManager.h"
+#import "LoginViewController.h"
+#import "JPUSHService.h"
+#import "CustomNavViewController.h"
+#import "UserInfoManager.h"
+#import "TXIMLinsenter.h"
+#import "UIDevice+TFDevice.h"
+#import "AppDelegate+AppService.h"
+
+
+@implementation KSLoginManager
+
++ (instancetype)shareInstance {
+    static KSLoginManager *manager = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        manager = [[KSLoginManager alloc] init];
+    });
+    return manager;
+}
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherLogin) name:@"otherLogin" object:nil];
+    }
+    return self;
+}
+
+- (void)otherLogin {
+    dispatch_main_async_safe(^{
+        
+    });
+}
+
+- (void)loginAction {
+    
+}
+
+
+- (void)clearUMCount {
+    [USER_MANAGER sendUMEvent:@"klx_logout"];
+    [USER_MANAGER stopCountUMEvent];
+}
+- (void)logoutAction {
+    [self clearUMCount];
+    [KSNetworkingManager clearRequestHeader];
+    
+    // 取消推送别名
+    [JPUSHService deleteAlias:nil seq:0];
+    // 退出IM连接
+    [TXIM_LINSENTER logoutTXIM];
+    USER_MANAGER.hasShowFlash = NO;
+
+    // 清除数据
+    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
+    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
+    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
+    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
+    [[NSUserDefaults standardUserDefaults] removeObjectForKey:IM_TOKEN];
+    // 返回登录页面
+    UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
+    if ([vc isKindOfClass:[UITabBarController class]]) {
+        UITabBarController *tab = (UITabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
+        CustomNavViewController *ctrl = (CustomNavViewController *)tab.selectedViewController;
+        [ctrl popToRootViewControllerAnimated:NO];
+
+        LoginViewController *logonVC = [[LoginViewController alloc] init];
+        CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:logonVC];
+        navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
+        [tab.selectedViewController presentViewController:navCtrl animated:YES completion:nil];
+        
+        // 切换到横屏
+        AppDelegate* delegate = [AppDelegate shareAppDelegate];
+        if (delegate.allowAutoRotate) {
+            delegate.allowAutoRotate = NO;
+            [UIDevice switchNewOrientation:UIInterfaceOrientationPortrait inController:logonVC];
+        }
+    }
+    
+}
+
+- (NSString *)getVisableControllerName {
+    UIViewController *vc = [AppDelegate shareAppDelegate].window.rootViewController;
+    if ([vc isKindOfClass:[UITabBarController class]]) {
+        UITabBarController *tab = (UITabBarController *)vc;
+        CustomNavViewController *ctrl = (CustomNavViewController *)tab.selectedViewController;
+        return NSStringFromClass(ctrl.visibleViewController.class);
+    }
+    else if ([vc isKindOfClass:[CustomNavViewController class]]) {
+        CustomNavViewController *ctrl = (CustomNavViewController *)vc;
+        return NSStringFromClass(ctrl.visibleViewController.class);
+    }
+    else {
+        return NSStringFromClass(vc.class);
+    }
+}
+
+@end

+ 38 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/TXIMLinsenter.h

@@ -0,0 +1,38 @@
+//
+//  TXIMLinsenter.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2023/8/7.
+//
+
+#import <Foundation/Foundation.h>
+#import "TUILogin.h"
+
+typedef void(^TXIMLoginCallback)(BOOL isSuccess, NSString * _Nullable msg);
+
+typedef void(^UnreadCountCallback)(NSInteger count);
+
+#define TXIM_LINSENTER ([TXIMLinsenter shareInstance])
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface TXIMLinsenter : NSObject
+
+// 是否成功登录IM
+@property (nonatomic, assign) BOOL loginIMSuccess;
+
+@property (nonatomic, assign) BOOL isIMConnected;
+
++ (instancetype)shareInstance;
+
+- (void)TXIMLoginWithUserId:(NSString *)userId sig:(NSString *)userSig callback:(TXIMLoginCallback)callback;
+
+- (void)logoutTXIM;
+
+- (BOOL)isCurrentUserLoginIM;
+
+- (void)getUnReadCountCallback:(UnreadCountCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 171 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/LoginManger/TXIMLinsenter.m

@@ -0,0 +1,171 @@
+//
+//  TXIMLinsenter.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2023/8/7.
+//
+
+#import "TXIMLinsenter.h"
+#import <ImSDK_Plus/ImSDK_Plus.h>
+#import "KSTabBarViewController.h"
+#import "AppDelegate+AppService.h"
+#import "ClassroomService.h"
+
+@interface TXIMLinsenter ()<TUILoginListener,V2TIMConversationListener,V2TIMSimpleMsgListener,V2TIMSignalingListener,V2TIMGroupListener>
+
+
+
+@end
+
+@implementation TXIMLinsenter
+
++ (instancetype)shareInstance {
+    static TXIMLinsenter *manager = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        manager = [[TXIMLinsenter alloc] init];
+    });
+    return manager;
+}
+
+
+- (void)TXIMLoginWithUserId:(NSString *)userId sig:(NSString *)userSig callback:(TXIMLoginCallback)callback {
+    [TUILogin addLoginListener:self];
+    [[V2TIMManager sharedInstance] addConversationListener:self];
+    [TUILogin login:CONFIG_TXSDKAPPID userID:userId userSig:userSig succ:^{
+        self.loginIMSuccess = YES;
+        if (callback) {
+            callback(YES, nil);
+        }
+        [self registerAPNSDevice];
+    } fail:^(int code, NSString *msg) {
+        self.loginIMSuccess = NO;
+        NSLog(@"IM login  failure, code:%d, desc:%@", code, msg);
+        callback(NO, msg);
+    }];
+}
+
+- (void)registerAPNSDevice {
+    NSData *deviceToken = [AppDelegate shareAppDelegate].deviceToken;
+    if (deviceToken) {
+        V2TIMAPNSConfig *config = [[V2TIMAPNSConfig alloc] init];
+        config.businessID = TXOfflinePushCertificateIDForAPNS;
+        config.token = deviceToken;
+        [[V2TIMManager sharedInstance] setAPNS:config succ:^{
+            NSLog(@"%s, succ", __func__);
+        } fail:^(int code, NSString *desc) {
+            NSLog(@"%s, fail, %d, %@", __func__, code, desc);
+        }];
+    }
+}
+
+- (void)getUnReadCountCallback:(UnreadCountCallback)callback {
+    [[V2TIMManager sharedInstance] getTotalUnreadMessageCount:^(UInt64 totalUnreadCount) {
+        callback(totalUnreadCount);
+    } fail:^(int code, NSString *desc) {
+        callback(0);
+    }];
+}
+
+- (void)logoutTXIM {
+    if (self.loginIMSuccess) {
+        [TUILogin logout:^{
+            self.loginIMSuccess = NO;
+            
+        } fail:^(int code, NSString *msg) {
+            NSLog(@" logout failer ----- failure, code:%d, desc:%@", code, msg);
+        }];
+    }
+}
+
+- (BOOL)isCurrentUserLoginIM {
+    return [TUILogin isUserLogined];
+}
+
+#pragma mark ----- TUILoginListener
+- (void)onConnecting {
+    NSLog(@"----tx IM SDK 连接中");
+}
+
+- (void)onConnectSuccess {
+    NSLog(@"----- tx IM SDK 连接成功");
+    self.isIMConnected = YES;
+}
+
+- (void)onConnectFailed:(int)code err:(NSString *)err {
+    NSLog(@"----- tx IM SDK 连接失败 %d 错误信息 %@", code, err);
+    self.isIMConnected = NO;
+}
+
+- (void)onKickedOffline {
+    // 被踢下线
+    NSLog(@"----- 被踢下线");
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"otherLogin" object:nil];
+}
+
+- (void)onUserSigExpired {
+    // 在线时票据过期
+    NSLog(@"----- 票据过期");
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"otherLogin" object:nil];
+}
+
+#pragma mark ----
+- (void)onTotalUnreadMessageCountChanged:(UInt64)totalUnreadCount {
+    
+    NSDictionary *receiveMsg = @{@"unreadCount":@(totalUnreadCount)};
+    
+    [UIApplication sharedApplication].applicationIconBadgeNumber = totalUnreadCount;
+    if (totalUnreadCount >= 1) {
+        [[AppDelegate shareAppDelegate].tabBarController noteNewsWithIndex:3 count:totalUnreadCount];
+    } else {
+        [[AppDelegate shareAppDelegate].tabBarController clearNewsWithIndex:3];
+    }
+    [[NSNotificationCenter defaultCenter] postNotificationName:CHATVIEW_REFRESHSTATUS object:receiveMsg];
+}
+
+
+#pragma mark ------ V2TIMSimpleMsgListener
+
+- (void)onRecvGroupTextMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info text:(NSString *)text {
+    // 收到群组文本消息
+    if ([groupID containsString:@"LIVE"]) { // 判断是否是直播群消息
+//        TXLiveTextMessage *message = [[TXLiveTextMessage alloc] init];
+//        message.messageId = msgID;
+//        message.groupId = groupID;
+//        [[NSNotificationCenter defaultCenter] postNotificationName:OnReceiveTXLiveMessageNotification object:@{@"message":message}];
+    }
+}
+
+- (void)onRecvGroupCustomMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info customData:(NSData *)data {
+    // 收到自定义群组消息
+    if ([groupID containsString:@"LIVE"]) { // 判断是否是直播群消息
+//        [[NSNotificationCenter defaultCenter] postNotificationName:OnReceiveTXLiveMessageNotification object:@{@"message":[data mj_JSONObject],@"msgID" : msgID, @"groupID" : groupID}];
+    }
+    else {
+        NSDictionary *receiveMsg = @{@"message":[data mj_JSONObject],@"msgID" : msgID, @"groupID" : groupID};
+//        [[NSNotificationCenter defaultCenter] postNotificationName:OnReceiveTXMessageNotification object:receiveMsg];
+//        if ([[ClassroomService sharedService] isHoldTXClassroomMessage:receiveMsg]) {
+//
+//        }
+    }
+}
+
+#pragma mark ----- group listener
+- (void)onGroupAttributeChanged:(NSString *)groupID attributes:(NSMutableDictionary<NSString *,NSString *> *)attributes {
+    // 收到自定义群组消息
+    if ([groupID containsString:@"LIVE"]) { // 判断是否是直播群消息
+//        [[NSNotificationCenter defaultCenter] postNotificationName:OnReceiveTXLiveGroupNotification object:@{@"message":attributes, @"groupID" : groupID}];
+    }
+    else {
+//        [[NSNotificationCenter defaultCenter] postNotificationName:OnReceiveTXClassroomGroupNotification object:@{@"message":attributes, @"groupID" : groupID}];
+    }
+}
+
+- (void)onGroupCounterChanged:(NSString *)groupID key:(NSString *)key newValue:(NSInteger)newValue {
+    // 收到自定义群组消息
+    if ([groupID containsString:@"LIVE"]) { // 判断是否是直播群消息
+//        [[NSNotificationCenter defaultCenter] postNotificationName:OnReceiveTXLiveGroupCountNotification object:@{@"message":@{key:@(newValue)}, @"groupID" : groupID}];
+    }
+}
+
+@end

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Common/Base/RCConnectionManager.m

@@ -36,7 +36,7 @@
     }
     else if (isNeedJoin && !self.isConnected) {
         dispatch_main_async_safe(^{
-            NSString *tipsMessage = [NSString isEmptyString:UserDefault(RongTokenKey)] ? @"无IM token,请重新登录获取" : @"IM未能连接上,请检查您的网络";
+            NSString *tipsMessage = [NSString isEmptyString:UserDefault(IM_TOKEN)] ? @"无IM token,请重新登录获取" : @"IM未能连接上,请检查您的网络";
             [MBProgressHUD ksShowMessage:tipsMessage];
             // 失败回调
             [[ClassroomService sharedService] joinRoomFailerNotify];

+ 20 - 14
KulexiuForStudent/KulexiuForStudent/Common/Define/KSDomain.h

@@ -10,13 +10,15 @@
 
 //#ifdef DEBUG
 
-//#define hostURL (@"https://dev.colexiu.com")
-//#define SEALCLASSHOST (@"https://dev.colexiu.com/api-classroom")
-//#define WEBHOST (@"https://dev.colexiu.com/student")
-//#define SOCKET_URL (@"wss://dev.colexiu.com/audioAnalysis")
-//#define JSPUSH_ENVIRONMENT (NO)
-//#define RCIM_KEY (@"0vnjpoad0jbdz")
-//#define SUBMIT_UUID (NO)
+#define hostURL (@"https://dev.colexiu.com")
+#define SEALCLASSHOST (@"https://dev.colexiu.com/api-classroom")
+#define WEBHOST (@"https://dev.colexiu.com/student")
+#define SOCKET_URL (@"wss://dev.colexiu.com/audioAnalysis")
+#define JSPUSH_ENVIRONMENT (NO)
+#define RCIM_KEY (@"0vnjpoad0jbdz")
+#define SUBMIT_UUID (NO)
+#define CONFIG_TXSDKAPPID (1400805079)
+#define TXOfflinePushCertificateIDForAPNS (39341)
 
 // 预生产环境
 
@@ -27,16 +29,20 @@
 //#define JSPUSH_ENVIRONMENT (NO)
 //#define RCIM_KEY (@"0vnjpoad0jbdz")
 //#define SUBMIT_UUID (NO)
+//#define CONFIG_TXSDKAPPID (1400805079)
+//#define TXOfflinePushCertificateIDForAPNS (39341)
 
 //#else
 
-#define hostURL (@"https://online.colexiu.com")
-#define SEALCLASSHOST (@"https://online.colexiu.com/api-classroom")
-#define WEBHOST (@"https://online.colexiu.com/student")
-#define SOCKET_URL (@"wss://online.colexiu.com/audioAnalysis")
-#define JSPUSH_ENVIRONMENT (YES)
-#define RCIM_KEY (@"e5t4ouvpe42pa")
-#define SUBMIT_UUID (YES)
+//#define hostURL (@"https://online.colexiu.com")
+//#define SEALCLASSHOST (@"https://online.colexiu.com/api-classroom")
+//#define WEBHOST (@"https://online.colexiu.com/student")
+//#define SOCKET_URL (@"wss://online.colexiu.com/audioAnalysis")
+//#define JSPUSH_ENVIRONMENT (YES)
+//#define RCIM_KEY (@"e5t4ouvpe42pa")
+//#define SUBMIT_UUID (YES)
+//#define CONFIG_TXSDKAPPID (1400805079)
+//#define TXOfflinePushCertificateIDForAPNS (39341)
 
 //#endif
 

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Common/Define/PrefixHeader.pch

@@ -35,6 +35,7 @@
 
 #import "UIView+SubViewExtension.h"
 #import "NSObject+KSDateFormatter.h"
+#import "KSLoginManager.h"
 
 #define FIRST_LOGIN_KEY (@"FirstLoginKey")
 

+ 5 - 4
KulexiuForStudent/KulexiuForStudent/Common/Define/UserKeyHeader.h

@@ -71,8 +71,6 @@
 // userId 用户id
 #define UIDKey (@"UID")
 
-// 融云ID
-#define RongCloudID (@"RongCloudID")
 
 //用户token
 #define TokenKey  (@"access_token")
@@ -81,8 +79,11 @@
 
 #define Token_type (@"token_type")
 
-// 融云TOKEN
-#define RongTokenKey (@"RongToken")
+// IM——ID
+#define IM_USERID (@"imUserId")
+//  IM sig
+#define IM_TOKEN (@"IM_SIG")
+
 //用户昵称
 #define NicknameKey (@"NickName")
 // 头像

+ 6 - 0
KulexiuForStudent/KulexiuForStudent/Info.plist

@@ -2,6 +2,8 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+	<key>CFBundleAllowMixedLocalizations</key>
+	<true/>
 	<key>CFBundleDocumentTypes</key>
 	<array>
 		<dict>
@@ -24,6 +26,10 @@
 			</array>
 		</dict>
 	</array>
+	<key>CFBundleLocalizations</key>
+	<array>
+		<string>zh_CN</string>
+	</array>
 	<key>CFBundleURLTypes</key>
 	<array>
 		<dict>

+ 11 - 7
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.h

@@ -1,19 +1,23 @@
 //
 //  KSChatConversationViewController.h
-//  KulexiuForTeacher
+//  GuanYueTeamManager
 //
-//  Created by Kyle on 2022/3/23.
+//  Created by 王智 on 2023/8/2.
 //
 
-#import <RongIMKit/RongIMKit.h>
+#import "TUIC2CChatViewController.h"
+#import "KSBaseViewController.h"
 
 NS_ASSUME_NONNULL_BEGIN
-/**
- 会话页面
- */
-@interface KSChatConversationViewController : RCConversationViewController
 
+@interface KSChatConversationViewController : KSBaseViewController
 
+@property (nonatomic, strong) TUIChatConversationModel *conversation;
+
+// 搜索用
+@property(nonatomic, copy) NSString *highlightKeyword;
+// 搜索用
+@property(nonatomic, strong) V2TIMMessage *locateMessage;
 
 @end
 

+ 33 - 792
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.m

@@ -1,72 +1,15 @@
 //
 //  KSChatConversationViewController.m
-//  KulexiuForTeacher
+//  GuanYueTeamManager
 //
-//  Created by Kyle on 2022/3/23.
+//  Created by 王智 on 2023/8/2.
 //
 
 #import "KSChatConversationViewController.h"
-#import "GroupSettingViewController.h"
-#import "KSTabBarViewController.h"
-#import "UIButton+EnlargeEdge.h"
-#import "CustomNavViewController.h"
-#import <AVFoundation/AVFoundation.h>
-#import "KSBaseWKWebViewController.h"
-#import "WMPlayer.h"
-#import "KSRCloudMediaManager.h"
-#import "KSSelectConversationViewController.h"
-#import "GroupMemberModel.h"
 
-#import "KSChatLiveMessage.h"
-#import "KSChatLiveShareCell.h"
-#import "KSChatMusicShareCell.h"
-#import "KSChatMusicMessage.h"
+@interface KSChatConversationViewController ()
 
-#import "KSEnterLiveroomManager.h"
-#import "KSAccompanyWebViewController.h"
-
-#import "KSPublicAlertView.h"
-#import "KSGroupTagImageView.h"
-#import "KSChatUserDetailViewController.h"
-
-#define SHARE_MUSIC_TAG (2001)
-
-@interface RCNaviDataInfo : NSObject
-
-@property (nonatomic, assign) NSTimeInterval uploadVideoDurationLimit;
-
-@end
-
-@interface RCNaviDataManager : NSObject
-
-@property (nonatomic, strong) RCNaviDataInfo *naviData;
-
-+ (instancetype)sharedInstance;
-
-@end
-
-@interface RCSightMessage ()
-
-@property (nonatomic, readonly) AVAsset *asset;
-
-@property (nonatomic, assign) long long size;
-
-+ (instancetype)messageWithAsset:(AVAsset *)asset thumbnail:(UIImage *)image duration:(NSUInteger)duration;
-@end
-
-
-@interface KSChatConversationViewController ()<RCMessageCellDelegate,UIAlertViewDelegate,UIActionSheetDelegate,WMPlayerDelegate>
-{
-    WMPlayer *_wmPlayer;
-    CGRect _playerFrame;
-}
-
-@property (nonatomic, strong) UIView *bgView;
-@property (nonatomic, assign) BOOL isRatation;
-
-@property (nonatomic, assign) BOOL isFirstLoad;
-
-@property (nonatomic, strong) KSPublicAlertView *alertView;
+@property (nonatomic, strong) TUIC2CChatViewController *vc;
 
 @end
 
@@ -75,759 +18,57 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
-    if (self.conversationType == ConversationType_PRIVATE) {
-        self.displayUserNameInCell = NO;
-    }
-    else if (self.conversationType == ConversationType_SYSTEM) {
-        self.displayUserNameInCell = NO;
-        self.chatSessionInputBarControl.hidden = YES;
-        self.conversationMessageCollectionView.frame = CGRectMake(0, kNaviBarHeight, kScreenWidth, kScreenHeight - iPhoneXSafeBottomMargin - kNaviBarHeight);
-    }
-    
-    if (self.conversationType != ConversationType_APPSERVICE &&
-        self.conversationType != ConversationType_PUBLICSERVICE) {
-        //加号区域增加发送文件功能,Kit中已经默认实现了该功能,但是为了SDK向后兼容性,目前SDK默认不开启该入口,可以参考以下代码在加号区域中增加发送文件功能。
-        UIImage *imageFile = [UIImage imageNamed:@"actionbar_file_icon"];
-        RCPluginBoardView *pluginBoardView = self.chatSessionInputBarControl.pluginBoardView;
-        [pluginBoardView insertItem:imageFile
-                   highlightedImage:imageFile
-                              title:@"文件"
-                            atIndex:3
-                                tag:PLUGIN_BOARD_ITEM_FILE_TAG];
-    }
-    
-    // 注册自定义消息
-    [self registerClass:[KSChatLiveShareCell class] forMessageClass:[KSChatLiveMessage class]];
-    [self registerClass:[KSChatMusicShareCell class] forMessageClass:[KSChatMusicMessage class]];
-    
-    [self leftRightButton];
-    [self refreshUserInfoOrGroupInfo];
-    self.isFirstLoad = YES;
-    [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]}];
+    [self configUI];
+    [self clearConversation];
+    [self requestData];
 }
 
-- (void)allocTitle:(NSString *)Ntitle withColor:(UIColor *)color {
-    UILabel *natext= [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 40)];
-    natext.textAlignment = NSTextAlignmentCenter;
-    natext.font = [UIFont systemFontOfSize:18.0f weight:UIFontWeightMedium];
-    natext.textColor = color;
-    natext.text = Ntitle;
-    self.navigationItem.titleView  = natext;
+- (void)configUI {
+    self.vc = [[TUIC2CChatViewController alloc] init];
+    if (![NSString isEmptyString:self.highlightKeyword]) {
+        self.vc.highlightKeyword = self.highlightKeyword;
+        self.vc.locateMessage = self.locateMessage;
+    }
+    self.vc.conversationData = self.conversation;
+    [self addChildViewController:self.vc];
+    [self.view addSubview:self.vc.view];
 }
 
 - (void)viewWillAppear:(BOOL)animated {
     [super viewWillAppear:animated];
-    if (self.isFirstLoad == NO) {
-        [self refreshUserInfoOrGroupInfo];
-    }
-    [self refreshTitle];
-}
 
-- (void)viewDidAppear:(BOOL)animated {
-    [super viewDidAppear:animated];
-    self.isFirstLoad = NO;
-    [IQKeyboardManager sharedManager].enableAutoToolbar = NO;
+    //TODO: 页面appear 禁用
+   [[IQKeyboardManager sharedManager] setEnable:NO];
 }
 
 - (void)viewWillDisappear:(BOOL)animated {
     [super viewWillDisappear:animated];
-    int unreadMsgCount = [[RCIMClient sharedRCIMClient] getUnreadCount:@[
-        @(ConversationType_PRIVATE), @(ConversationType_APPSERVICE), @(ConversationType_GROUP),@(ConversationType_SYSTEM)
-    ]];
-    if (unreadMsgCount >= 1) {
-        [(KSTabBarViewController *)self.tabBarController noteNewsWithIndex:2 count:unreadMsgCount];
-    } else {
-        [(KSTabBarViewController *)self.tabBarController clearNewsWithIndex:2];
-    }
-
-    [IQKeyboardManager sharedManager].enableAutoToolbar = YES;
-}
-
-- (void)notifyUpdateUnreadMessageCount {
-    if (self.allowsMessageCellSelection) {
-        [super notifyUpdateUnreadMessageCount];
-        return;
-    }
-    [self leftRightButton];
-}
-
-- (void)leftRightButton {
-    dispatch_main_async_safe(^{
-        UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_black"] style:UIBarButtonItemStylePlain target:self action:@selector(backAction)];
-        leftButton.imageInsets = UIEdgeInsetsMake(0, -5, 0, 0);
-        leftButton.tintColor = [UIColor blackColor];
-        self.navigationItem.leftBarButtonItem = leftButton;
-        if (self.conversationType == ConversationType_GROUP) {
-            [self rightButtonWithImage:@"group_setting"];
-        }
-        else if (self.conversationType == ConversationType_SYSTEM || self.conversationType == ConversationType_PRIVATE) {
-            self.navigationItem.rightBarButtonItem = nil;
-        }
-    });
-}
-
-- (void)rightButtonWithImage:(NSString *)imageName {
-    UIButton *rightBt = [UIButton buttonWithType:UIButtonTypeCustom];
-    rightBt.frame =CGRectMake(0, 0, 80, 40);
-    rightBt.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -40);
-    [rightBt setEnlargeEdgeWithTop:10 right:10 bottom:10 left:10];
-    rightBt.titleLabel.font = [UIFont systemFontOfSize:16];
-    [rightBt setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
-    [rightBt setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
-    [rightBt addTarget:self action:@selector(rightBtnClick) forControlEvents:UIControlEventTouchUpInside];
-    UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]initWithCustomView:rightBt];
-    self.navigationItem.rightBarButtonItem = rightItem;
-}
 
-- (void)backAction {
-    [self.navigationController popViewControllerAnimated:YES];
-}
-- (void)rightBtnClick {
-    GroupSettingViewController *groupVC = [[GroupSettingViewController alloc] init];
-    groupVC.groupId = self.targetId;
-    [self.navigationController pushViewController:groupVC animated:YES];
-}
-
-- (NSArray<UIMenuItem *> *)getLongTouchMessageCellMenuList:(RCMessageModel *)model {
-    if (self.conversationType == ConversationType_SYSTEM) {
-        return [NSArray array];
-    }
-    return [super getLongTouchMessageCellMenuList:model];
-}
-
-// 转发
-- (void)forwardMessage:(NSInteger)index
-             completed:(void (^)(NSArray<RCConversation *> *conversationList))completedBlock {
-    KSSelectConversationViewController *forwardSelectedVC = [[KSSelectConversationViewController alloc]
-        initSelectConversationViewControllerCompleted:^(NSArray<RCConversation *> *conversationList) {
-            completedBlock(conversationList);
-        }];
-    [self.navigationController pushViewController:forwardSelectedVC animated:NO];
-}
-
-#pragma mark override
-// 点击消息的处理
-- (void)didTapMessageCell:(RCMessageModel *)model {
-    if ([model.objectName isEqualToString:@"RC:CHATSHARE:LIVE"]) { // 直播消息
-        KSChatLiveMessage *liveShareMsg = (KSChatLiveMessage *)model.content;
-        [KSEnterLiveroomManager joinLiveWithRoomId:liveShareMsg.roomUID inController:(CustomNavViewController *)self.navigationController callback:^{
-            
-        }];
-    }
-    else if ([model.objectName isEqualToString:@"RC:CHATSHARE:MUSIC"]) { // 曲谱消息
-        KSChatMusicMessage *musicShareMsg = (KSChatMusicMessage *)model.content;
-        KSAccompanyWebViewController *detailCtrl = [[KSAccompanyWebViewController alloc] init];
-        detailCtrl.url = [NSString stringWithFormat:@"%@/accompany?id=%@",hostURL, musicShareMsg.songId];
-        detailCtrl.hiddenNavBar = YES;
-        detailCtrl.parmDic = @{@"isOpenLight" : @(YES), @"orientation" : @(0),@"isHideTitle" : @(YES)};
-        [self.navigationController pushViewController:detailCtrl animated:YES];
-    }
-    else {
-        [super didTapMessageCell:model];
-    }
+    //TODO: 页面Disappear 启用
+   [[IQKeyboardManager sharedManager] setEnable:YES];
 }
 
-
-- (void)playVideoWithUrl:(NSString *)fileUrl {
-    fileUrl = [fileUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
-    _playerFrame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
-    _wmPlayer = [[WMPlayer alloc] initWithFrame:_playerFrame];
-    WMPlayerModel *playModel = [[WMPlayerModel alloc] init];
-    playModel.videoURL = [NSURL URLWithString:fileUrl];
-    _wmPlayer.playerModel = playModel;
-    _wmPlayer.delegate = self;
-    _bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
-    _bgView.backgroundColor = [UIColor blackColor];
-    [[UIApplication sharedApplication].keyWindow addSubview:_bgView];
-    [[UIApplication sharedApplication].keyWindow addSubview:_wmPlayer];
-    [[UIApplication sharedApplication].keyWindow bringSubviewToFront:_wmPlayer];
+- (void)clearConversation {
     
-    [_wmPlayer play];
-}
-
-
-
-- (void)wmplayer:(WMPlayer *)wmplayer clickedCloseButton:(UIButton *)backBtn {
-    [wmplayer removePlayer];
-    [_bgView removeFromSuperview];
-    [self setNeedsStatusBarAppearanceUpdate];
-}
-
-- (void)wmplayer:(WMPlayer *)wmplayer clickedFullScreenButton:(UIButton *)fullScreenBtn {
-    self.isRatation = !self.isRatation;
-    
-    if (self.isRatation) {
-        [wmplayer removeFromSuperview];
-        [UIView animateWithDuration:1.0f animations:^{
-            wmplayer.transform = CGAffineTransformMakeRotation(M_PI_2);
-            
-        } completion:^(BOOL finished) {
-            wmplayer.frame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
-            [[UIApplication sharedApplication].keyWindow addSubview:wmplayer];
-            [[UIApplication sharedApplication].keyWindow bringSubviewToFront:wmplayer];
-        }];
-    }
-    else {
-        [wmplayer removeFromSuperview];
+    NSString *conversationID = [NSString stringWithFormat:@"c2c_%@",self.conversation.userID];
+    [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:^{
         
-        [UIView animateWithDuration:1.0f animations:^{
-            //        复原
-            wmplayer.transform = CGAffineTransformIdentity;
-            
-        } completion:^(BOOL finished) {
-            wmplayer.frame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
-            [[UIApplication sharedApplication].keyWindow addSubview:wmplayer];
-            [[UIApplication sharedApplication].keyWindow bringSubviewToFront:wmplayer];
-        }];
-    }
-}
-
-
-- (void)didTapUrlInMessageCell:(NSString *)url model:(RCMessageModel *)model {
-    if ([url containsString:@"dayaedu"]) {
+    } fail:^(int code, NSString *desc) {
         
-        KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
-        ctrl.url = url;
-        [self.navigationController pushViewController:ctrl animated:YES];
-    }
-    else if ([url containsString:@"daya"] && [url hasSuffix:@".mp4"]) {
-        [self playVideoWithUrl:url];
-    }
-    else {
-        [super didTapUrlInMessageCell:url model:model];
-    }
+    }];
 }
 
-
-
-- (RCMessageContent *)willSendMessage:(RCMessageContent *)messageContent {
-    //可以在这里修改将要发送的消息
-    if ([messageContent isMemberOfClass:[RCTextMessage class]]) {
-        // RCTextMessage *textMsg = (RCTextMessage *)messageContent;
-        // textMsg.extra = @"";
-    }
-    return messageContent;
-}
-
-- (void)resendMessage:(RCMessageContent *)messageContent {
-    if ([messageContent isKindOfClass:[RCSightMessage class]]) {
-        RCSightMessage *sightMsg = (RCSightMessage *)messageContent;
-        [self sendMediaMessage:sightMsg pushContent:nil appUpload:YES];
-    }
-    else {
-        [super resendMessage:messageContent];
-    }
-}
-
-#pragma mark  --- refresh
-- (void)refreshUserInfoOrGroupInfo {
-    
-    if (self.conversationType == ConversationType_PRIVATE) {
-        if (![self.targetId isEqualToString:[RCIM sharedRCIM].currentUserInfo.userId]) {
-            [KSNetworkingManager imUserFriendQueryDetail:KS_POST userId:self.targetId success:^(NSDictionary * _Nonnull dic) {
-                if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
-                    NSDictionary *userDic = [dic ks_dictionaryValueForKey:@"data"];
-                    RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:self.targetId name:[userDic ks_stringValueForKey:@"friendNickname"] portrait:[userDic ks_stringValueForKey:@"friendAvatar"]];
-                    // 附加字段
-                    NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
-                    [extraDic setValue:[userDic ks_stringValueForKey:@"roleType"] forKey:@"role"];
-                    user.extra = [extraDic mj_JSONString];
-                    
-                    [[RCIM sharedRCIM] refreshUserInfoCache:user withUserId:self.targetId];
-                    [self refreshTitle];
-                }
-                else {
-                    
-                }
-            } faliure:^(NSError * _Nonnull error) {
-                
-            }];
+- (void)requestData {
+    [KSNetworkingManager imUserFriendQueryDetail:KS_POST userId:self.conversation.userID success:^(NSDictionary * _Nonnull dic) {
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSDictionary *userDic = [dic ks_dictionaryValueForKey:@"data"];
+            NSString *userName = [userDic ks_stringValueForKey:@"friendNickname"];
+            [self allocTitle:userName];
         }
-    }
-    else if (self.conversationType == ConversationType_GROUP) {
-        // 获取群成员
-        [KSNetworkingManager imGroupMemberAllRequest:KS_POST groupId:self.targetId success:^(NSDictionary * _Nonnull dic) {
-            
-            if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
-                NSArray *sourceArray = [dic ks_arrayValueForKey:@"data"];
-                for (NSDictionary *parm in sourceArray) {
-                    if ([parm isKindOfClass:[NSNull class]]) {
-                        continue;
-                    }
-                    GroupMemberModel *model = [[GroupMemberModel alloc] initWithDictionary:parm];
-                    // 刷新缓存
-                    RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.imUserId name:model.nickname portrait:model.avatar];
-                    // 附加字段
-                    NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
-                    if (model.isAdmin) {
-                        [extraDic setValue:@"owner" forKey:@"groupOwner"];
-                    }
-                    [extraDic setValue:model.roleType forKey:@"role"];
-                    user.extra = [extraDic mj_JSONString];
-                    
-                    [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.imUserId withGroupId:self.targetId];
-                }
-            }
-            else {
-                
-            }
-            
-        } faliure:^(NSError * _Nonnull error) {
-            
-        }];
+    } faliure:^(NSError * _Nonnull error) {
         
-        // 获取群组信息
-        [KSNetworkingManager queryGroupDetail:KS_POST groupId:self.targetId success:^(NSDictionary * _Nonnull dic) {
-            if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
-                NSDictionary *result = [dic ks_dictionaryValueForKey:@"data"];
-                RCGroup *groupInfo = [[RCGroup alloc] initWithGroupId:self.targetId groupName:[result ks_stringValueForKey:@"name"] portraitUri:[result ks_stringValueForKey:@"img"]];
-                [[RCIM sharedRCIM] refreshGroupInfoCache:groupInfo withGroupId:self.targetId];
-                [self refreshTitle];
-            }
-            else if ([dic ks_integerValueForKey:@"code"] == 204) {
-                // 弹窗提示是否删除群组
-                MJWeakSelf;
-                self.alertView = [KSPublicAlertView shareInstanceWithTitle:@"提示" descMessage:@"当前群组已被解散,是否删除聊天记录?" leftTitle:@"取消" rightTitle:@"确定" cancelAction:^{
-                    
-                } sureAction:^{
-                    [weakSelf removeNoExistGroup];
-                }];
-            }
-        } faliure:^(NSError * _Nonnull error) {
-            
-        }];
-    }
-}
-
-- (void)removeNoExistGroup {
-    [[RCIMClient sharedRCIMClient] removeConversation:ConversationType_GROUP targetId:self.targetId];
-    [self.navigationController popToRootViewControllerAnimated:YES];
-}
-
-
-- (void)refreshTitle {
-    if (self.conversationType == ConversationType_GROUP) {
-        RCGroup *group = [[RCIM sharedRCIM] getGroupInfoCache:self.targetId];
-        if (![NSString isEmptyString:group.groupName]) {
-            [self allocTitle:group.groupName withColor:[UIColor blackColor]];
-        }
-    }
-    else {
-        RCUserInfo *userInfo = [[RCIM sharedRCIM] getUserInfoCache:self.targetId];
-        if (![NSString isEmptyString:userInfo.name]) {
-            [self allocTitle:userInfo.name withColor:[UIColor blackColor]];
-        }
-    }
-}
-
-
-
-- (void)pluginBoardView:(RCPluginBoardView *)pluginBoardView clickedItemWithTag:(NSInteger)tag {
-    switch (tag) {
-        case SHARE_MUSIC_TAG: // 曲谱分享
-        {
-            
-        }
-            break;
-            
-        default:
-        {
-            [RCNaviDataManager sharedInstance].naviData.uploadVideoDurationLimit = 480.0f;
-            [super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
-        }
-            
-            break;
-    }
-}
-
-- (void)willDisplayMessageCell:(RCMessageBaseCell *)cell atIndexPath:(NSIndexPath *)indexPath {
-    if ([cell isKindOfClass:[RCMessageCell class]]) {
-        UIImageView *imageView = (UIImageView *)((RCMessageCell *)cell).portraitImageView;
-        imageView.contentMode = UIViewContentModeScaleAspectFill;
-        imageView.layer.masksToBounds = YES;
-        
-        if (self.conversationType == ConversationType_GROUP) {
-            UIView *contentView = (UIView *)((RCMessageCell *)cell).messageContentView;
-            RCMessageModel *model = self.conversationDataRepository[indexPath.row];
-            for (UIView *subView in contentView.subviews) {
-                if ([subView isKindOfClass:[KSGroupTagImageView class]]) {
-                    [subView removeFromSuperview];
-                }
-            }
-            RCUserInfo *user = [[RCIM sharedRCIM] getGroupUserInfoCache:model.senderUserId withGroupId:self.targetId];
-            NSDictionary *extraDic = [user.extra mj_JSONObject];
-            
-            if ([[extraDic ks_stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
-                KSGroupTagImageView *avatarImage = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"chat_collegeTag"]];
-                [contentView addSubview:avatarImage];
-                [avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
-                    make.width.mas_equalTo(40);
-                    make.height.mas_equalTo(13);
-                    make.centerX.mas_equalTo(imageView.mas_centerX);
-                    make.bottom.mas_equalTo(imageView.mas_bottom);
-                }];
-            }
-            // owner
-            if ([[extraDic ks_stringValueForKey:@"groupOwner"] isEqualToString:@"owner"]) {
-                
-                RCMessageCell *baseCell = (RCMessageCell *)cell;
-                
-                KSGroupTagImageView *ownerTagView = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"group_ownerTag"]];
-                [contentView addSubview:ownerTagView];
-                [ownerTagView mas_makeConstraints:^(MASConstraintMaker *make) {
-                    make.width.mas_equalTo(24);
-                    make.height.mas_equalTo(14);
-                    make.centerY.mas_equalTo(baseCell.nicknameLabel.mas_centerY);
-                    make.left.mas_equalTo(baseCell.bubbleBackgroundView.mas_left);
-                }];
-                [baseCell.nicknameLabel mas_updateConstraints:^(MASConstraintMaker *make) {
-                    make.left.mas_equalTo(ownerTagView.mas_right).offset(4);
-                }];
-            }
-            
-        }
-        else if (self.conversationType == ConversationType_PRIVATE) {
-            UIView *contentView = (UIView *)((RCMessageCell *)cell).messageContentView;
-            for (UIView *subView in contentView.subviews) {
-                if ([subView isKindOfClass:[KSGroupTagImageView class]]) {
-                    [subView removeFromSuperview];
-                    break;
-                }
-            }
-            RCMessageModel *model = self.conversationDataRepository[indexPath.row];
-            RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:model.senderUserId];
-            NSDictionary *extraDic = [user.extra mj_JSONObject];
-            if ([[extraDic ks_stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
-                KSGroupTagImageView *avatarImage = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"chat_collegeTag"]];
-                [contentView addSubview:avatarImage];
-                [avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
-                    make.width.mas_equalTo(40);
-                    make.height.mas_equalTo(13);
-                    make.centerX.mas_equalTo(imageView.mas_centerX);
-                    make.bottom.mas_equalTo(imageView.mas_bottom);
-                }];
-            }
-        }
-    }
-}
-
-
-#pragma mark ----- chatSessionInputBarControl delegate
-- (void)sightDidFinishRecord:(NSString *)url thumbnail:(UIImage *)image duration:(NSUInteger)duration {
-    RCSightMessage *sightMessage = [RCSightMessage messageWithLocalPath:url thumbnail:image duration:duration];
+    }];
     
-    [self sendMediaMessage:sightMessage pushContent:nil appUpload:YES];
-}
-
-- (void)imageDataDidSelect:(NSArray *)selectedImages fullImageRequired:(BOOL)full {
-    
-    [self becomeFirstResponder];
-    __weak KSChatConversationViewController *weakSelf = self;
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        for (int i = 0; i < selectedImages.count; i++) {
-            @autoreleasepool {
-                id item = [selectedImages objectAtIndex:i];
-                if ([item isKindOfClass:NSData.class]) {
-                    NSData *imageData = (NSData *)item;
-                    UIImage *image = [UIImage imageWithData:imageData];
-                    image = [RCKitUtility fixOrientation:image];
-                    // 保留原有逻辑并添加大图缩小的功能
-                    [[KSRCloudMediaManager sharedManager] downsizeImage:image completionBlock:^(UIImage * _Nullable outimage, BOOL doNothing) {
-                        RCImageMessage *imagemsg;
-                        if (doNothing || !outimage) {
-                            imagemsg = [RCImageMessage messageWithImage:image];
-                            imagemsg.full = full;
-                        } else if (outimage) {
-                            NSData *newImageData = UIImageJPEGRepresentation(outimage, 1);
-                            imagemsg = [RCImageMessage messageWithImageData:newImageData];
-                            imagemsg.full = full;
-                        }
-                        [weakSelf sendMessage:imagemsg pushContent:nil];
-                    } progressBlock:^(UIImage * _Nullable outimage, BOOL doNothing) {
-                        
-                    }];
-                    
-                }
-                else if ([item isKindOfClass:NSDictionary.class]) {
-                    NSDictionary *assertInfo = item;
-                    if ([assertInfo objectForKey:@"avAsset"]) {
-                        AVAsset *model = assertInfo[@"avAsset"];
-                        UIImage *image = assertInfo[@"thumbnail"];
-                        NSString *localPath = assertInfo[@"localPath"];
-                        if (![localPath isKindOfClass:[NSString class]]) {
-                            localPath = @"";
-                        }
-                        dispatch_sync(dispatch_get_main_queue(), ^{
-                            NSUInteger duration = round(CMTimeGetSeconds(model.duration));
-                            RCSightMessage *sightMsg =
-                            [RCSightMessage messageWithAsset:model thumbnail:image duration:duration];
-                            sightMsg.localPath = localPath;
-                            [weakSelf sendMediaMessage:sightMsg pushContent:nil appUpload:YES];
-                        });
-                    }
-                }
-                [NSThread sleepForTimeInterval:0.5];
-            }
-        }
-    });
-}
-
-- (void)uploadMedia:(RCMessage *)message uploadListener:(RCUploadMediaStatusListener *)uploadListener {
-    // 获取 asset
-    if ([message.content isKindOfClass:[RCSightMessage class]]) {
-        RCSightMessage *sightMessage = (RCSightMessage *)message.content;
-        NSString *fileName = [NSString stringWithFormat:@"sight_%@", [[sightMessage.name componentsSeparatedByString:@"_"] lastObject]];
-        NSString *savePath =  [[self getSightSavePath] stringByAppendingPathComponent:fileName];
-        // 判断文件是否存在于该文件夹
-        if ([[NSFileManager defaultManager] fileExistsAtPath:savePath]) {
-            sightMessage.localPath = savePath;
-            [self submitFileWithMessage:sightMessage uploadListener:uploadListener];
-        }
-        else {
-            if (([sightMessage.localPath containsString:@"var/mobile/Media/"])) {
-                NSURL *fileUrl = [NSURL fileURLWithPath:sightMessage.localPath];
-                AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:fileUrl options:nil];
-                [self startExportVideoWithVideoAsset:avAsset presetName:AVAssetExportPreset960x540 savePath:savePath success:^(NSString *outputPath) {
-                    sightMessage.localPath = savePath;
-                    
-                    [self submitFileWithMessage:sightMessage uploadListener:uploadListener];
-                } failure:^(NSString *errorMessage, NSError *error) {
-                    // 导出失败 直接拷贝上传
-                    [self copyFileToPath:savePath uploadListener:uploadListener];
-                }];
-                
-            }
-            else {
-                // 复制文件到指定文件夹
-                [self copyFileToPath:savePath uploadListener:uploadListener];
-            }
-        }
-    }
-    else {
-        uploadListener.errorBlock(INVALID_PARAMETER);
-    }
-}
-
-- (void)copyFileToPath:(NSString *)savePath uploadListener:(RCUploadMediaStatusListener *)uploadListener {
-    RCMessage *message = uploadListener.currentMessage;
-    if ([message.content isKindOfClass:[RCSightMessage class]]) {
-        RCSightMessage *sightMessage = (RCSightMessage *)message.content;
-        // 复制文件到指定文件夹
-        BOOL isSuccess = [self copyMediaFile:sightMessage.localPath toPath:savePath];
-        if (isSuccess) {
-            sightMessage.localPath = savePath;
-            [self submitFileWithMessage:sightMessage uploadListener:uploadListener];
-        }
-        else {
-            uploadListener.errorBlock(INVALID_PARAMETER);
-        }
-    }
-}
-
-- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName savePath:(NSString *)savePath success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
-    NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset];
-    if ([presets containsObject:presetName]) {
-        
-        NSError *error = nil;
-        AVAssetTrack *assetVideoTrack = nil;
-        AVAssetTrack *assetAudioTrack = nil;
-        CMTime start = CMTimeMakeWithSeconds(0, videoAsset.duration.timescale);
-        
-        CMTimeRange range = CMTimeRangeMake(start, videoAsset.duration);
-        // Check if the asset contains video and audio tracks
-        if ([[videoAsset tracksWithMediaType:AVMediaTypeVideo] count] != 0) {
-            assetVideoTrack = [videoAsset tracksWithMediaType:AVMediaTypeVideo][0];
-        }
-        
-        if ([[videoAsset tracksWithMediaType:AVMediaTypeAudio] count] != 0) {
-            assetAudioTrack = [videoAsset tracksWithMediaType:AVMediaTypeAudio][0];
-        }
-        
-        CMTime insertionPoint = kCMTimeZero;
-        
-        AVMutableComposition *composition = [[AVMutableComposition alloc] init];
-        
-        // Insert the video and audio tracks from AVAsset
-        if (assetVideoTrack != nil) {
-            // 视频通道  工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材
-            AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
-            // 视频方向
-            [compositionVideoTrack setPreferredTransform:assetVideoTrack.preferredTransform];
-            // 把视频轨道数据加入到可变轨道中 这部分可以做视频裁剪TimeRange
-            [compositionVideoTrack insertTimeRange:range ofTrack:assetVideoTrack atTime:insertionPoint error:&error];
-        }
-        
-        
-        if (assetAudioTrack != nil) {
-            AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
-            compositionAudioTrack.preferredTransform = assetAudioTrack.preferredTransform;
-            [compositionAudioTrack insertTimeRange:range ofTrack:assetAudioTrack atTime:insertionPoint error:&error];
-        }
-        
-        AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:composition presetName:presetName];
-        // Optimize for network use.
-        session.shouldOptimizeForNetworkUse = YES;
-        NSArray *supportedTypeArray = session.supportedFileTypes;
-        if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
-            session.outputFileType = AVFileTypeMPEG4;
-        } else if (supportedTypeArray.count == 0) {
-            if (failure) {
-                failure(@"该视频类型暂不支持导出", nil);
-            }
-            NSLog(@"No supported file types 视频类型暂不支持导出");
-            return;
-        } else {
-            session.outputFileType = [supportedTypeArray objectAtIndex:0];
-            if (videoAsset.URL && videoAsset.URL.lastPathComponent) {
-                savePath = [savePath stringByReplacingOccurrencesOfString:@".mp4" withString:[NSString stringWithFormat:@"-%@", videoAsset.URL.lastPathComponent]];
-            }
-        }
-        session.outputURL = [NSURL fileURLWithPath:savePath];
-        [session exportAsynchronouslyWithCompletionHandler:^{
-            dispatch_async(dispatch_get_main_queue(), ^{
-                switch (session.status) {
-                    case AVAssetExportSessionStatusUnknown: {
-                        NSLog(@"AVAssetExportSessionStatusUnknown");
-                    }  break;
-                    case AVAssetExportSessionStatusWaiting: {
-                        NSLog(@"AVAssetExportSessionStatusWaiting");
-                    }  break;
-                    case AVAssetExportSessionStatusExporting: {
-                        NSLog(@"AVAssetExportSessionStatusExporting");
-                    }  break;
-                    case AVAssetExportSessionStatusCompleted: {
-                        NSLog(@"AVAssetExportSessionStatusCompleted");
-                        if (success) {
-                            success(savePath);
-                        }
-                    }  break;
-                    case AVAssetExportSessionStatusFailed: {
-                        NSLog(@"AVAssetExportSessionStatusFailed");
-                        if (failure) {
-                            failure(@"视频导出失败", session.error);
-                        }
-                    }  break;
-                    case AVAssetExportSessionStatusCancelled: {
-                        NSLog(@"AVAssetExportSessionStatusCancelled");
-                        if (failure) {
-                            failure(@"导出任务已被取消", nil);
-                        }
-                    }  break;
-                    default: break;
-                }
-            });
-        }];
-        
-    }
-    else {
-        if (failure) {
-            NSString *errorMessage = [NSString stringWithFormat:@"当前设备不支持该预设:%@", presetName];
-            failure(errorMessage, nil);
-        }
-    }
-}
-
-
-- (void)submitFileWithMessage:(RCSightMessage *)sightMessage uploadListener:(RCUploadMediaStatusListener *)uploadListener {
-    NSURL *fileUrl = [NSURL fileURLWithPath:sightMessage.localPath];
-    NSData *fileData = [NSData dataWithContentsOfURL:fileUrl];
-    
-    if (fileData.length) {
-        NSString *suffix = [NSString stringWithFormat:@".%@",[fileUrl pathExtension]];
-        [[KSUploadManager shareInstance] configBucketName:@"i-m"];
-        [[KSUploadManager shareInstance] videoUpload:fileData fileName:@"sightVideo" fileSuffix:suffix progress:^(int64_t bytesWritten, int64_t totalBytes) {
-            int progress = (int)(bytesWritten / totalBytes * 100);
-            uploadListener.updateBlock(progress);
-        } successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
-            NSString *videoUrl = [fileUrlArray lastObject];
-            sightMessage.remoteUrl = videoUrl;
-            sightMessage.size = fileData.length;
-            uploadListener.successBlock(sightMessage);
-        } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
-            uploadListener.errorBlock(ERRORCODE_TIMEOUT);
-        }];
-    }
-    else {
-        uploadListener.errorBlock(INVALID_PARAMETER);
-    }
-}
-
-
-- (BOOL)copyMediaFile:(NSString *)sourcePath toPath:(NSString *)toPath
-{
-    BOOL retVal = YES;
-    if ([[NSFileManager defaultManager] fileExistsAtPath:sourcePath]) { // 如果原文件存在
-
-        if (![[NSFileManager defaultManager] fileExistsAtPath:toPath])
-        {
-            retVal = [[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:toPath error:NULL];
-        }
-    }
-    else {
-        retVal = NO;
-    }
-    
-    return retVal;
-}
-
-- (NSString *)getSightSavePath {
-    NSString *componentString = [NSString stringWithFormat:@"RongCloud/%@/RCSightCache", self.targetId];
-    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:componentString];
-    NSFileManager *fileManager = [NSFileManager defaultManager];
-    BOOL isDir = FALSE;
-    BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
-    if(!(isDirExist && isDir)) {
-        BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-        if(!bCreateDir){
-            NSLog(@"创建文件夹失败!");
-        }
-        NSLog(@"创建文件夹成功,文件路径%@",path);
-    }
-    NSLog(@"文件路径%@",path);
-    return path;
-}
-
-- (void)didTapCellPortrait:(NSString *)userId {
-    if ([userId isEqualToString:UserDefault(RongCloudID)]) {
-        [self displayStudent:userId];
-    }
-    else {
-//        RCUserInfo *user = nil;
-        if (self.conversationType == ConversationType_PRIVATE) {
-            RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:userId];
-            
-            NSDictionary *extraDic = [user.extra mj_JSONObject];
-            if ([[extraDic ks_stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
-                [self displayTeacher:userId];
-            }
-            else {
-                [self displayStudent:userId];
-            }
-        }
-        else {
-            RCUserInfo *user = [[RCIM sharedRCIM] getGroupUserInfoCache:userId withGroupId:self.targetId];
-            NSDictionary *extraDic = [user.extra mj_JSONObject];
-            if ([[extraDic ks_stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
-                [self displayTeacher:userId];
-            }
-            else {
-                [self displayStudent:userId];
-            }
-        }
-        
-    }
-}
-
-- (void)displayStudent:(NSString *)stuentId {
-    KSChatUserDetailViewController *ctrl = [[KSChatUserDetailViewController alloc] init];
-    ctrl.rongCloudId = stuentId;
-    [self.navigationController pushViewController:ctrl animated:YES];
-}
-
-- (void)displayTeacher:(NSString *)teacherId {
-    KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
-    ctrl.url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/teacherHome?teacherId=",teacherId];
-    [self.navigationController pushViewController:ctrl animated:YES];
 }
 
 /*

+ 2 - 6
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatListViewController.h

@@ -5,17 +5,13 @@
 //  Created by Kyle on 2022/3/23.
 //
 
-#import <RongIMKit/RongIMKit.h>
+#import "KSBaseViewController.h"
 #import "JXCategoryView.h"
 #import "JXPagerView.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
-@interface KSChatListViewController : RCConversationListViewController <JXCategoryListContentViewDelegate>
-
-@property (nonatomic, assign) BOOL isSubList;
-
-@property (nonatomic, strong) NSString *topTitle;
+@interface KSChatListViewController : KSBaseViewController <JXCategoryListContentViewDelegate>
 
 @property (nonatomic, strong) JXPagerView *pagerView;
 @property (nonatomic, strong, readonly) JXCategoryTitleView *categoryView;

+ 64 - 233
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatListViewController.m

@@ -8,278 +8,109 @@
 #import "KSChatListViewController.h"
 #import "KSChatListSearchView.h"
 #import "UIButton+EnlargeEdge.h"
-#import "KSSearchHistoryMessageController.h"
+#import "KSSearchViewController.h"
+#import "KSGroupConversationController.h"
 #import "KSChatConversationViewController.h"
 #import "KSTabBarViewController.h"
 #import "KSChatTagView.h"
+#import <TUICore/TUICore.h>
+#import "AppDelegate+AppService.h"
+#import "KSConversationListController.h"
 
-@interface KSChatListViewController ()
+@interface KSChatListViewController ()<TUIConversationListControllerListener>
 
 @property (nonatomic, strong) KSChatListSearchView *searchBar;
 
-@property (nonatomic, strong) UIView *stateView;
+@property(nonatomic, strong) KSConversationListController *listVC;
 
 @end
 
 @implementation KSChatListViewController
 
 - (void)refreshChatListMessage {
-    NSArray *visiableIndexArray = self.conversationListTableView.indexPathsForVisibleRows;
-    if (visiableIndexArray.count) {
-        NSIndexPath *firstIndexPath = [visiableIndexArray firstObject];
-
-        NSInteger firstIndex = firstIndexPath.row;
-        if ([self isAtTheBottomOfTableView]) {
-            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
-            [self.conversationListTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
-        }
-        else {
-            for (NSInteger index = firstIndex+1; index < self.conversationListDataSource.count; index++) {
-                RCConversationModel *model = self.conversationListDataSource[index];
-                if (model.unreadMessageCount > 0) {
-                    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
-                    [self.conversationListTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
-                    break;
-                }
-                
-                if (index == self.conversationListDataSource.count - 1) {
-                    
-                }
-            }
-        }
-    }
-}
-
-/**
- *  判断消息是否在collectionView的底部
- *
- *  @return 是否在底部
- */
-- (BOOL)isAtTheBottomOfTableView {
-    if (self.conversationListTableView.contentSize.height <= self.conversationListTableView.frame.size.height) {
-        return YES;
-    }
-    CGFloat height = self.conversationListTableView.frame.size.height;
-    CGFloat contentOffsetY = self.conversationListTableView.contentOffset.y;
-    CGFloat bottomOffset = self.conversationListTableView.contentSize.height - contentOffsetY;
-    if (bottomOffset <= height) {
-        return YES;
-    }else{
-        return NO;
-    }
+    
 }
 
 
-- (instancetype)init {
-    self = [super init];
-    if (self) {
-        [self setDisplayConversationTypes:@[@(ConversationType_PRIVATE),@(ConversationType_GROUP),@(ConversationType_SYSTEM)]];
-        //聚合会话类型
-        self.topTitle = @"聊天消息";
-        [self setCollectionConversationType:@[@(ConversationType_SYSTEM)]];
-    }
-    return self;
-}
-
 - (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
-    [self allocTitle:self.topTitle];
-    self.stateView.center = CGPointMake(self.view.centerX, self.view.centerY - 30);
-    
-    [self configUI];
-}
-
-- (void)viewWillAppear:(BOOL)animated {
-    [super viewWillAppear:animated];
-    if (self.isSubList) {
-        [self allocLeftButton];
-        self.conversationListTableView.tableHeaderView = [UIView new];
-    }
-}
-
-- (void)allocLeftButton {
-    dispatch_main_async_safe(^{
-        UIButton * backButton = [[UIButton alloc]initWithFrame:CGRectMake(0,8,44,34)];
-        [backButton setImage:[UIImage imageNamed:@"back_black"] forState:UIControlStateNormal];
-        [backButton setImageEdgeInsets:UIEdgeInsetsMake(0, -40, 0, 0)];
-        [backButton addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside];
-        [backButton setEnlargeEdgeWithTop:8 right:50 bottom:0 left:20];
-        UIBarButtonItem *leftItem = [[UIBarButtonItem alloc]initWithCustomView:backButton];
-        self.navigationItem.leftBarButtonItem = leftItem;
-    });
-}
-
-- (void)backAction {
-    [self.navigationController popViewControllerAnimated:YES];
-}
-
-- (void)configUI {
+    self.listVC = [[KSConversationListController alloc] init];
+    // 把 TUIConversationListController 添加到自己的 ViewController
+    [self addChildViewController:self.listVC];
+    self.listVC.delegate = self;
+    [self.view addSubview:self.listVC.view];
+    self.listVC.tableViewForAll.tipsMsgWhenNoConversation = @"暂无内容~";
+    [self.listVC.tableViewForAll.tipsView setImage:[UIImage imageNamed:@"wd_img_zwsj"]];
+    [self updateTipsFrame];
     _searchBar = [KSChatListSearchView shareInstance];
-    _searchBar.frame = CGRectMake(0, 0, kScreenWidth, 60);
+    _searchBar.isClickSearch = YES;
+    [_searchBar configText:@"查找聊天记录"];
+    _searchBar.frame = CGRectMake(0, 0, KPortraitWidth, 60);
     MJWeakSelf;
     [_searchBar topSearchCallback:^{
         [weakSelf searchAction];
     }];
-    self.conversationListTableView.tableHeaderView = self.searchBar;
-    self.conversationListTableView.separatorColor = HexRGBAlpha(0x414141, 0.05f);
-    self.conversationListTableView.tableFooterView = [UIView new];
-    self.isShowNetworkIndicatorView = YES;
-    self.emptyConversationView = self.stateView;
+    [self.view addSubview:self.searchBar];
+    
+    [self.searchBar mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.mas_equalTo(self.view);
+        make.height.mas_equalTo(60);
+    }];
 }
 
-- (void)allocTitle:(NSString *)titleStr {
-    UILabel *navText = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 40)];
-    navText.backgroundColor = [UIColor clearColor];
-    navText.textAlignment = NSTextAlignmentCenter;
-    navText.font = [UIFont systemFontOfSize:18.0f weight:UIFontWeightMedium];
-    navText.textColor = HexRGB(0x000000);
-    navText.text = titleStr;
-    self.navigationItem.titleView  = navText;
+- (void)updateTipsFrame {
+    [self.listVC.tableViewForAll.tipsView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.centerX.mas_equalTo(self.listVC.tableViewForAll);
+        make.top.mas_equalTo(self.listVC.tableViewForAll.mas_top).offset(40);
+        make.width.mas_equalTo(240);
+        make.height.mas_equalTo(240);
+    }];
+    
+    [self.listVC.tableViewForAll.tipsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.centerX.mas_equalTo(self.listVC.tableViewForAll);
+        make.top.mas_equalTo(self.listVC.tableViewForAll.tipsView.mas_bottom).offset(18);
+        make.width.mas_equalTo(300);
+        make.height.mas_equalTo(18);
+    }];
 }
 
-#pragma mark -- searchAction
-- (void)searchAction {
-    // 搜索逻辑
-    KSSearchHistoryMessageController *searchViewController = [[KSSearchHistoryMessageController alloc] init];
-    [self.navigationController pushViewController:searchViewController animated:YES];
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
 }
 
-//重写RCConversationListViewController的onSelectedTableRow事件
-- (void)onSelectedTableRow:(RCConversationModelType)conversationModelType
-         conversationModel:(RCConversationModel *)model
-               atIndexPath:(NSIndexPath *)indexPath {
-    //聚合会话类型,此处自定设置。
-    if (conversationModelType == RC_CONVERSATION_MODEL_TYPE_COLLECTION) {
-        KSChatListViewController *tempCtrl = [[KSChatListViewController alloc] init];
-        tempCtrl.isSubList = YES;
-        tempCtrl.topTitle = @"系统消息助手";
-        NSArray *array = [NSArray arrayWithObject:[NSNumber numberWithInteger:model.conversationType]];
-        [tempCtrl setDisplayConversationTypes:array];
-        [tempCtrl setCollectionConversationType:nil];
-        tempCtrl.isEnteredToCollectionViewController = YES;
-        [self.navigationController pushViewController:tempCtrl animated:YES];
-    }
-    else if (model.conversationModelType == RC_CONVERSATION_MODEL_TYPE_PUBLIC_SERVICE ||
-             conversationModelType == RC_CONVERSATION_MODEL_TYPE_NORMAL){
-        KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] initWithConversationType:model.conversationType targetId:model.targetId];
-        if (model.conversationType == ConversationType_SYSTEM) {
-            conversationVC.title = @"系统消息";
-        }
-        else {
-            conversationVC.title = model.conversationTitle;
-        }
-        [self.navigationController pushViewController:conversationVC animated:YES];
-        return;
-    }
-}
 
-- (NSMutableArray *)willReloadTableData:(NSMutableArray *)dataSource {
-    NSMutableArray *array = [NSMutableArray array];
-    for (RCConversationModel *model in dataSource) {
-        if (model.conversationType == ConversationType_GROUP && ![model.targetId containsString:@"FAN"] && ![model.targetId containsString:@"COURSE"]) {
-            [[RCIMClient sharedRCIMClient] clearMessagesUnreadStatus:ConversationType_GROUP targetId:model.targetId];
-        }
-        else {
-            [array addObject:model];
-        }
+#pragma mark -- searchAction
+- (void)searchAction {
+    KSSearchViewController *vc = [[KSSearchViewController alloc] init];
+    CustomNavViewController *nav = [[CustomNavViewController alloc] initWithRootViewController:(UIViewController *)vc];
+    nav.modalPresentationStyle = UIModalPresentationFullScreen;
+    
+    UIViewController *parentVC = self.navigationController;
+    if (parentVC) {
+        [parentVC presentViewController:nav animated:NO completion:nil];
     }
-    dispatch_async(dispatch_get_main_queue(), ^{
-        int unreadMsgCount = [[RCIMClient sharedRCIMClient] getUnreadCount:@[
-            @(ConversationType_PRIVATE), @(ConversationType_APPSERVICE), @(ConversationType_GROUP),@(ConversationType_SYSTEM)
-        ]];
-        if (unreadMsgCount >= 1) {
-            [(KSTabBarViewController *)self.tabBarController noteNewsWithIndex:2 count:unreadMsgCount];
-        } else {
-            [(KSTabBarViewController *)self.tabBarController clearNewsWithIndex:2];
-        }
-    });
-    return array;
 }
 
-- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
-    RCConversationModel *model = self.conversationListDataSource[indexPath.row];
-    BOOL isTop = model.isTop;
-    NSString *msgTitle = isTop ? @"取消置顶" : @"置顶会话";
-    // 删除会话
-    UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
-        
-        [[RCIMClient sharedRCIMClient] removeConversation:model.conversationType targetId:model.targetId];
-        [self refreshConversationTableViewIfNeeded];
-    }];
-    deleteRowAction.backgroundColor = HexRGB(0xf97215);
-    
-    // 置顶
-    UITableViewRowAction *upperRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:msgTitle handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
-        
-        [[RCIMClient sharedRCIMClient] setConversationToTop:model.conversationType targetId:model.targetId isTop:!isTop];
-        [self refreshConversationTableViewIfNeeded];
-    }];
-    upperRowAction.backgroundColor = THEMECOLOR;
-    return @[deleteRowAction,upperRowAction];
-}
+- (void)conversationListController:(UIViewController *)conversationController didSelectConversation:(TUIConversationCellData *)conversation {
 
-- (void)willDisplayConversationTableCell:(RCConversationBaseCell *)cell atIndexPath:(NSIndexPath *)indexPath {
-    UIImageView *imageView = (UIImageView *)((RCConversationCell *)cell).headerImageView;
-    UIView *tagView = (UIView *)((RCConversationCell *)cell).conversationTagView;
-    imageView.contentMode = UIViewContentModeScaleAspectFill;
-    imageView.layer.masksToBounds = YES;
-    for (UIView *view in cell.contentView.subviews) {
-        if ([view isKindOfClass:[KSChatTagView class]]) {
-            [view removeFromSuperview];
-        }
-    }
-    RCConversationModel *model = self.conversationListDataSource[indexPath.row];
-    if (model.conversationType == ConversationType_GROUP) {
-        if ([model.targetId containsString:@"FAN"]) { // 粉丝群
-            [imageView setImage:[UIImage imageNamed:GROUP_FAN_LOGO]];
-            UIImageView *tagImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"group_fans"]];
-            [tagView removeAllSubViews];
-            [tagView addSubview:tagImage];
-            tagImage.frame = CGRectMake(0, 2, 45, 17);
-        }
-        else if ([model.targetId containsString:@"COURSE"]) { // 课程群
-            [imageView setImage:[UIImage imageNamed:GROUP_COURSE_LOGO]];
-            UIImageView *tagImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"group_course"]];
-            [tagView removeAllSubViews];
-            [tagView addSubview:tagImage];
-            tagImage.frame = CGRectMake(0, 2, 45, 17);
-        }
+
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.groupID = conversation.groupID;
+    model.userID = conversation.userID;
+    model.title = conversation.title;
+    if (![NSString isEmptyString:model.userID]) { // 单聊
+        KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+        ctrl.conversation = model;
+        [self.navigationController pushViewController:ctrl animated:YES];
     }
-    else if (model.conversationType == ConversationType_PRIVATE) {
-        UIView *contentView = (UIView *)((RCConversationCell *)cell).contentView;
-        RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:model.targetId];
-        NSDictionary *extraDic = [user.extra mj_JSONObject];
-        if ([[extraDic ks_stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
-            KSChatTagView *avatarImage = [[KSChatTagView alloc] initWithImage:[UIImage imageNamed:@"chat_talentList"]];
-            [contentView addSubview:avatarImage];
-            [avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
-                make.width.mas_equalTo(44);
-                make.height.mas_equalTo(13);
-                make.centerX.mas_equalTo(imageView.mas_centerX);
-                make.bottom.mas_equalTo(imageView.mas_bottom);
-            }];
-        }
-        
+    else { // 群聊
+        KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+        ctrl.conversation = model;
+        [self.navigationController pushViewController:ctrl animated:YES];
     }
 }
 
-- (UIView *)stateView {
-    if (!_stateView) {
-        _stateView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 240)];
-        UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 260, 230)];
-        [imgView setImage:[UIImage imageNamed:@"wd_img_zwsj"]];
-        
-        UILabel *descLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 260, 280, 20)];
-        descLabel.text = @"暂无消息";
-        descLabel.textColor = HexRGB(0xb7b7b7);
-        descLabel.font = [UIFont systemFontOfSize:16];
-        descLabel.textAlignment = NSTextAlignmentCenter;
-        [_stateView addSubview:descLabel];
-        [_stateView addSubview:imgView];
-     }
-    return _stateView;
-}
 #pragma mark - JXCategoryListContentViewDelegate
 
 - (UIView *)listView {

+ 17 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSConversationListController.h

@@ -0,0 +1,17 @@
+//
+//  KSConversationListController.h
+//  GuanYueTeamManager
+//
+//  Created by 王智 on 2023/8/2.
+//
+
+#import "TUIConversationListController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSConversationListController : TUIConversationListController
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 715 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSConversationListController.m

@@ -0,0 +1,715 @@
+//
+//  KSConversationListController.m
+//  GuanYueTeamManager
+//
+//  Created by 王智 on 2023/8/2.
+//
+
+#import "KSConversationListController.h"
+#import <TIMCommon/TIMDefine.h>
+#import <TUICore/TUICore.h>
+#import <TUICore/TUIThemeManager.h>
+#import "TUIConversationCell.h"
+#import "TUIConversationListDataProvider.h"
+#import "TUIFoldListViewController.h"
+
+#define GroupBtnSpace 24
+#define GroupScrollViewHeight 30
+
+@interface KSConversationListController ()<UIGestureRecognizerDelegate,
+UIPopoverPresentationControllerDelegate,
+TUIConversationTableViewDelegate,
+TUIPopViewDelegate,
+TUINotificationProtocol>
+@property(nonatomic, strong) TUINaviBarIndicatorView *titleView;
+@property(nonatomic, strong) TUIConversationListBaseDataProvider *settingDataProvider;
+@property(nonatomic, strong) UIView *tableViewContainer;
+@property(nonatomic, strong) UIView *bannerView;
+@property(nonatomic, assign) CGFloat viewHeight;
+
+@property(nonatomic, assign) BOOL actualShowConversationGroup;
+@property(nonatomic, strong) UIView *groupView;
+@property(nonatomic, strong) UIScrollView *groupScrollView;
+@property(nonatomic, strong) UIView *groupAnimationView;
+@property(nonatomic, strong) UIView *groupBtnContainer;
+@property(nonatomic, strong) NSMutableArray *groupItemList;
+
+@end
+
+@implementation KSConversationListController
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        self.isShowBanner = YES;
+        self.isShowConversationGroup = YES;
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onThemeChanged) name:TUIDidApplyingThemeChangedNotfication object:nil];
+    }
+    return self;
+}
+
+#pragma mark - NSNotification
+- (void)onThemeChanged {
+    self.groupAnimationView.layer.borderColor = [TUIConversationDynamicColor(@"conversation_group_bg_color", @"#EBECF0") CGColor];
+}
+
+#pragma mark - SettingDataProvider
+- (void)setDataProvider:(TUIConversationListBaseDataProvider *)dataProvider {
+    self.settingDataProvider = dataProvider;
+}
+
+- (TUIConversationListBaseDataProvider *)dataProvider {
+    return self.settingDataProvider;
+}
+
+#pragma mark - Life Cycle
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    [self setupNavigation];
+    [self setupViews];
+    [TUICore registerEvent:TUICore_TUIConversationGroupNotify subKey:@"" object:self];
+    [TUICore registerEvent:TUICore_TUIConversationMarkNotify subKey:@"" object:self];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [self.currentTableView reloadData];
+}
+
+- (void)dealloc {
+    [NSNotificationCenter.defaultCenter removeObserver:self];
+    [TUICore unRegisterEventByObject:self];
+}
+
+- (void)setupNavigation {
+    UIButton *moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    [moreButton setImage:TIMCommonDynamicImage(@"nav_more_img", [UIImage imageNamed:TIMCommonImagePath(@"more")]) forState:UIControlStateNormal];
+    [moreButton addTarget:self action:@selector(rightBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
+    moreButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
+    [moreButton.widthAnchor constraintEqualToConstant:24].active = YES;
+    [moreButton.heightAnchor constraintEqualToConstant:24].active = YES;
+    UIBarButtonItem *moreItem = [[UIBarButtonItem alloc] initWithCustomView:moreButton];
+    self.navigationController.navigationItem.rightBarButtonItem = moreItem;
+
+    self.navigationController.interactivePopGestureRecognizer.enabled = YES;
+    self.navigationController.interactivePopGestureRecognizer.delegate = self;
+}
+
+- (void)rightBarButtonClick:(UIButton *)rightBarButton {
+    NSMutableArray *menus = [NSMutableArray array];
+    TUIPopCellData *friend = [[TUIPopCellData alloc] init];
+
+    friend.image = TUIConversationDynamicImage(@"pop_icon_new_chat_img", [UIImage imageNamed:TUIConversationImagePath(@"new_chat")]);
+    friend.title = TIMCommonLocalizableString(ChatsNewChatText);
+    [menus addObject:friend];
+
+    TUIPopCellData *group = [[TUIPopCellData alloc] init];
+    group.image = TUIConversationDynamicImage(@"pop_icon_new_group_img", [UIImage imageNamed:TUIConversationImagePath(@"new_groupchat")]);
+    group.title = TIMCommonLocalizableString(ChatsNewGroupText);
+    [menus addObject:group];
+
+    CGFloat height = [TUIPopCell getHeight] * menus.count + TUIPopView_Arrow_Size.height;
+    CGFloat orginY = 0;
+    TUIPopView *popView = [[TUIPopView alloc] initWithFrame:CGRectMake(Screen_Width - 155, orginY, 145, height)];
+    CGRect frameInNaviView = [self.navigationController.view convertRect:rightBarButton.frame fromView:rightBarButton.superview];
+    popView.arrowPoint = CGPointMake(frameInNaviView.origin.x + frameInNaviView.size.width * 0.5, orginY);
+    popView.delegate = self;
+    [popView setData:menus];
+    [popView showInWindow:self.view.window];
+}
+
+- (void)setupViews {
+    self.view.backgroundColor = TUIConversationDynamicColor(@"conversation_bg_color", @"#FFFFFF");
+    self.viewHeight = self.view.mm_h;
+    if (self.isShowBanner) {
+        CGSize size = CGSizeMake(self.view.bounds.size.width, 60);
+        self.bannerView.mm_width(size.width).mm_height(60);
+        NSMutableDictionary *param = [NSMutableDictionary dictionary];
+        param[TUICore_TUIConversationExtension_ConversationListBanner_BannerSize] = NSStringFromCGSize(size);
+        param[TUICore_TUIConversationExtension_ConversationListBanner_ModalVC] = self;
+        BOOL result = [TUICore raiseExtension:TUICore_TUIConversationExtension_ConversationListBanner_ClassicExtensionID
+                                   parentView:self.bannerView
+                                        param:param];
+        if (!result) {
+            self.bannerView.mm_height(0);
+        }
+    }
+
+    [self.view addSubview:self.tableViewContainer];
+    [self.tableViewContainer addSubview:self.tableViewForAll];
+
+    if (self.isShowConversationGroup) {
+        // 延迟点时间加载,等待插件能力位异步加载完毕
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+          NSArray *extensionList = [TUICore getExtensionList:TUICore_TUIConversationExtension_ConversationGroupListBanner_ClassicExtensionID param:nil];
+          @weakify(self);
+          [[[RACObserve(self, actualShowConversationGroup) distinctUntilChanged] skip:0] subscribeNext:^(NSNumber *showConversationGroup) {
+            @strongify(self);
+            if ([showConversationGroup boolValue]) {
+                [self.tableViewContainer setFrame:CGRectMake(0, self.groupView.mm_maxY, self.view.mm_w, self.viewHeight - self.groupView.mm_maxY)];
+
+                self.groupItemList = [NSMutableArray array];
+                TUIConversationGroupItem *allGroupItem = [[TUIConversationGroupItem alloc] init];
+                allGroupItem.groupName = TIMCommonLocalizableString(TUIConversationGroupAll);
+                [self addGroup:allGroupItem];
+
+                for (TUIExtensionInfo *info in extensionList) {
+                    TUIConversationGroupItem *groupItem = info.data[TUICore_TUIConversationExtension_ConversationGroupListBanner_GroupItemKey];
+                    if (groupItem) {
+                        [self addGroup:groupItem];
+                    }
+                }
+                [self onSelectGroup:allGroupItem];
+            } else {
+                self.tableViewContainer.frame = CGRectMake(0, self.bannerView.mm_maxY, self.view.mm_w, self.viewHeight - self.bannerView.mm_maxY);
+                self.tableViewForAll.frame = self.tableViewContainer.bounds;
+            }
+          }];
+          self.actualShowConversationGroup = (extensionList.count > 0);
+        });
+    } else {
+        self.tableViewContainer.frame = CGRectMake(0, self.bannerView.mm_maxY, self.view.mm_w, self.viewHeight - self.bannerView.mm_maxY);
+        self.tableViewForAll.frame = self.tableViewContainer.bounds;
+    }
+}
+
+- (UIView *)bannerView {
+    if (!_bannerView) {
+        _bannerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
+        [self.view addSubview:_bannerView];
+    }
+    return _bannerView;
+}
+
+- (TUIConversationTableView *)currentTableView {
+    for (UIView *view in self.tableViewContainer.subviews) {
+        if ([view isKindOfClass:[TUIConversationTableView class]]) {
+            return (TUIConversationTableView *)view;
+        }
+    }
+    return nil;
+}
+
+- (UIView *)tableViewContainer {
+    if (!_tableViewContainer) {
+        _tableViewContainer = [[UIView alloc] init];
+        _tableViewContainer.autoresizesSubviews = YES;
+    }
+    return _tableViewContainer;
+}
+
+
+
+- (UIView *)groupView {
+    if (!_groupView) {
+        _groupView = [[UIView alloc] initWithFrame:CGRectMake(0, self.bannerView.mm_maxY, self.view.mm_w, 60)];
+        [self.view addSubview:_groupView];
+
+        CGFloat groupExtensionBtnLeft = _groupView.mm_w - GroupScrollViewHeight - kScale375(16);
+        self.groupBtnContainer = [[UIView alloc] initWithFrame:CGRectMake(groupExtensionBtnLeft, 18, GroupScrollViewHeight, GroupScrollViewHeight)];
+        [_groupView addSubview:self.groupBtnContainer];
+        [TUICore raiseExtension:TUICore_TUIConversationExtension_ConversationGroupManagerContainer_ClassicExtensionID
+                     parentView:self.groupBtnContainer
+                          param:@{TUICore_TUIConversationExtension_ConversationGroupManagerContainer_ParentVCKey : self}];
+
+        CGFloat groupScrollViewWidth = self.groupBtnContainer.mm_x - kScale375(16) - kScale375(10);
+        self.groupScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(kScale375(16), 18, groupScrollViewWidth, GroupScrollViewHeight)];
+        self.groupScrollView.backgroundColor = TUIConversationDynamicColor(@"conversation_group_bg_color", @"#EBECF0");
+        self.groupScrollView.showsHorizontalScrollIndicator = NO;
+        self.groupScrollView.showsVerticalScrollIndicator = NO;
+        self.groupScrollView.bounces = NO;
+        self.groupScrollView.scrollEnabled = YES;
+        self.groupScrollView.layer.cornerRadius = GroupScrollViewHeight / 2.0;
+        self.groupScrollView.layer.masksToBounds = YES;
+        [_groupView addSubview:self.groupScrollView];
+        @weakify(self);
+        [[[RACObserve(self.groupScrollView, contentSize) distinctUntilChanged] skip:1] subscribeNext:^(NSValue *contentSizeValue) {
+          @strongify(self);
+          self.groupScrollView.mm_w = MIN(groupScrollViewWidth, [contentSizeValue CGSizeValue].width);
+        }];
+
+        self.groupAnimationView = [[UIView alloc] init];
+        self.groupAnimationView.backgroundColor = TUIConversationDynamicColor(@"conversation_group_animate_view_color", @"#FFFFFF");
+        self.groupAnimationView.layer.cornerRadius = GroupScrollViewHeight / 2.0;
+        self.groupAnimationView.layer.masksToBounds = YES;
+        self.groupAnimationView.layer.borderWidth = 1;
+        self.groupAnimationView.layer.borderColor = [TUIConversationDynamicColor(@"conversation_group_bg_color", @"#EBECF0") CGColor];
+        [self.groupScrollView addSubview:self.groupAnimationView];
+    }
+    return _groupView;
+}
+
+#pragma mark Conversation Group Manager
+- (void)createGroupBtn:(TUIConversationGroupItem *)groupItem positionX:(CGFloat)positionX {
+    UIButton *groupBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+    [groupBtn setBackgroundColor:[UIColor clearColor]];
+    [groupBtn setAttributedTitle:[self getGroupBtnAttributedString:groupItem] forState:UIControlStateNormal];
+    [groupBtn setTitleColor:TUIConversationDynamicColor(@"conversation_group_btn_unselect_color", @"#666666") forState:UIControlStateNormal];
+    [groupBtn.titleLabel setFont:[UIFont systemFontOfSize:16]];
+    [groupBtn addTarget:self action:@selector(onGroupBtnClick:) forControlEvents:UIControlEventTouchUpInside];
+    [groupBtn sizeToFit];
+    groupBtn.mm_x = positionX;
+    groupBtn.mm_w = groupBtn.mm_w + GroupBtnSpace;
+    groupBtn.mm_h = GroupScrollViewHeight;
+    groupItem.groupBtn = groupBtn;
+}
+
+- (void)updateGroupBtn:(TUIConversationGroupItem *)groupItem {
+    [groupItem.groupBtn setAttributedTitle:[self getGroupBtnAttributedString:groupItem] forState:UIControlStateNormal];
+    [groupItem.groupBtn sizeToFit];
+    groupItem.groupBtn.mm_w = groupItem.groupBtn.mm_w + GroupBtnSpace;
+    groupItem.groupBtn.mm_h = GroupScrollViewHeight;
+}
+
+- (void)onGroupBtnClick:(UIButton *)btn {
+    for (TUIConversationGroupItem *groupItem in self.groupItemList) {
+        if ([groupItem.groupBtn isEqual:btn]) {
+            [self onSelectGroup:groupItem];
+            return;
+        }
+    }
+}
+
+- (void)loadGroupList:(NSArray<TUIConversationGroupItem *> *)groupItemList {
+    NSString *selectGroup = @"";
+    for (TUIConversationGroupItem *groupItem in self.groupItemList) {
+        if (groupItem.groupBtn.isSelected) {
+            selectGroup = groupItem.groupName;
+        }
+        [groupItem.groupBtn removeFromSuperview];
+    }
+    [self.groupItemList removeAllObjects];
+    [self.groupScrollView setContentSize:CGSizeZero];
+
+    for (TUIConversationGroupItem *groupItem in groupItemList) {
+        [self addGroup:groupItem];
+        if ([groupItem.groupName isEqualToString:selectGroup]) {
+            groupItem.groupBtn.selected = YES;
+            self.groupAnimationView.frame = groupItem.groupBtn.frame;
+        }
+    }
+}
+
+- (void)addGroup:(TUIConversationGroupItem *)addGroup {
+    [self createGroupBtn:addGroup positionX:self.groupScrollView.contentSize.width];
+    [self.groupItemList addObject:addGroup];
+    [self.groupScrollView addSubview:addGroup.groupBtn];
+    [self.groupScrollView setContentSize:CGSizeMake(addGroup.groupBtn.mm_maxX, GroupScrollViewHeight)];
+}
+
+- (void)insertGroup:(TUIConversationGroupItem *)insertGroup atIndex:(NSInteger)index {
+    if (index < self.groupItemList.count) {
+        for (int i = 0; i < self.groupItemList.count; ++i) {
+            TUIConversationGroupItem *groupItem = self.groupItemList[i];
+            if (i == index) {
+                [self createGroupBtn:insertGroup positionX:groupItem.groupBtn.mm_x];
+                [self.groupScrollView addSubview:insertGroup.groupBtn];
+            }
+            if (i >= index) {
+                groupItem.groupBtn.mm_x += insertGroup.groupBtn.mm_w;
+                if (groupItem.groupBtn.isSelected) {
+                    self.groupAnimationView.frame = groupItem.groupBtn.frame;
+                }
+            }
+        }
+        [self.groupItemList insertObject:insertGroup atIndex:index];
+        [self.groupScrollView setContentSize:CGSizeMake(self.groupScrollView.contentSize.width + insertGroup.groupBtn.mm_w, GroupScrollViewHeight)];
+    } else {
+        [self addGroup:insertGroup];
+    }
+}
+
+- (void)updateGroup:(TUIConversationGroupItem *)updateGroup {
+    CGFloat offsetX = 0;
+    for (int i = 0; i < self.groupItemList.count; ++i) {
+        TUIConversationGroupItem *groupItem = self.groupItemList[i];
+        if (offsetX != 0) {
+            groupItem.groupBtn.mm_x += offsetX;
+        }
+        if ([groupItem.groupName isEqualToString:updateGroup.groupName]) {
+            groupItem.unreadCount = updateGroup.unreadCount;
+            CGFloat oldBtnWidth = groupItem.groupBtn.mm_w;
+            [self updateGroupBtn:groupItem];
+            CGFloat newBtnWidth = groupItem.groupBtn.mm_w;
+            offsetX = newBtnWidth - oldBtnWidth;
+        }
+        if (groupItem.groupBtn.isSelected) {
+            self.groupAnimationView.frame = groupItem.groupBtn.frame;
+        }
+    }
+    [self.groupScrollView setContentSize:CGSizeMake(self.groupScrollView.contentSize.width + offsetX, GroupScrollViewHeight)];
+}
+
+- (void)renameGroup:(NSString *)oldName newName:(NSString *)newName {
+    CGFloat offsetX = 0;
+    for (int i = 0; i < self.groupItemList.count; ++i) {
+        TUIConversationGroupItem *groupItem = self.groupItemList[i];
+        if (offsetX != 0) {
+            groupItem.groupBtn.mm_x += offsetX;
+        }
+        if ([groupItem.groupName isEqualToString:oldName]) {
+            groupItem.groupName = newName;
+            CGFloat oldBtnWidth = groupItem.groupBtn.mm_w;
+            [self updateGroupBtn:groupItem];
+            CGFloat newBtnWidth = groupItem.groupBtn.mm_w;
+            offsetX = newBtnWidth - oldBtnWidth;
+        }
+        if (groupItem.groupBtn.isSelected) {
+            self.groupAnimationView.frame = groupItem.groupBtn.frame;
+        }
+    }
+    [self.groupScrollView setContentSize:CGSizeMake(self.groupScrollView.contentSize.width + offsetX, GroupScrollViewHeight)];
+}
+
+- (void)deleteGroup:(TUIConversationGroupItem *)deleteGroup {
+    CGFloat offsetX = 0;
+    NSUInteger removeIndex = 0;
+    BOOL isSelectedGroup = NO;
+    for (int i = 0; i < self.groupItemList.count; ++i) {
+        TUIConversationGroupItem *groupItem = self.groupItemList[i];
+        if (offsetX != 0) {
+            groupItem.groupBtn.mm_x += offsetX;
+        }
+        if ([groupItem.groupName isEqualToString:deleteGroup.groupName]) {
+            [groupItem.groupBtn removeFromSuperview];
+            offsetX = -groupItem.groupBtn.mm_w;
+            removeIndex = i;
+            isSelectedGroup = groupItem.groupBtn.isSelected;
+        }
+        if (groupItem.groupBtn.isSelected) {
+            self.groupAnimationView.frame = groupItem.groupBtn.frame;
+        }
+    }
+    [self.groupItemList removeObjectAtIndex:removeIndex];
+    [self.groupScrollView setContentSize:CGSizeMake(self.groupScrollView.contentSize.width + offsetX, GroupScrollViewHeight)];
+    if (isSelectedGroup) {
+        [self onSelectGroup:self.groupItemList.firstObject];
+    }
+}
+
+- (void)onSelectGroup:(TUIConversationGroupItem *)selectGroupItem {
+    for (int i = 0; i < self.groupItemList.count; ++i) {
+        TUIConversationGroupItem *groupItem = self.groupItemList[i];
+        if ([groupItem.groupName isEqualToString:selectGroupItem.groupName]) {
+            groupItem.groupBtn.selected = YES;
+
+            [UIView animateWithDuration:0.1
+                             animations:^{
+                               self.groupAnimationView.frame = groupItem.groupBtn.frame;
+                             }];
+            for (UIView *view in self.tableViewContainer.subviews) {
+                [view removeFromSuperview];
+            }
+            if ([groupItem.groupName isEqualToString:TIMCommonLocalizableString(TUIConversationGroupAll)]) {
+                self.tableViewForAll.frame = self.tableViewContainer.bounds;
+                [self.tableViewContainer addSubview:self.tableViewForAll];
+            } else {
+                [TUICore raiseExtension:TUICore_TUIConversationExtension_ConversationListContainer_ClassicExtensionID
+                             parentView:self.tableViewContainer
+                                  param:@{TUICore_TUIConversationExtension_ConversationListContainer_GroupNameKey : groupItem.groupName}];
+                self.currentTableView.convDelegate = self;
+            }
+        } else {
+            groupItem.groupBtn.selected = NO;
+        }
+        [self updateGroupBtn:groupItem];
+    }
+}
+
+- (NSMutableAttributedString *)getGroupBtnAttributedString:(TUIConversationGroupItem *)groupItem {
+    NSMutableString *content = [NSMutableString stringWithString:groupItem.groupName];
+    NSInteger unreadCount = groupItem.unreadCount;
+    if (unreadCount > 0) {
+        [content appendString:@" "];
+        [content appendString:(unreadCount > 99 ? @"99+" : [@(unreadCount) stringValue])];
+    }
+    NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:content];
+    if (groupItem.groupBtn.isSelected) {
+        [attributeString setAttributes:@{
+            NSFontAttributeName : [UIFont systemFontOfSize:16],
+            NSForegroundColorAttributeName : TUIConversationDynamicColor(@"conversation_group_btn_select_color", @"#147AFF")
+        }
+                                 range:NSMakeRange(0, groupItem.groupName.length)];
+    } else {
+        [attributeString setAttributes:@{
+            NSFontAttributeName : [UIFont systemFontOfSize:16],
+            NSForegroundColorAttributeName : TUIConversationDynamicColor(@"conversation_group_btn_unselect_color", @"#666666")
+        }
+                                 range:NSMakeRange(0, groupItem.groupName.length)];
+    }
+    [attributeString setAttributes:@{
+        NSForegroundColorAttributeName : TUIConversationDynamicColor(@"conversation_group_btn_select_color", @"#147AFF"),
+        NSFontAttributeName : [UIFont systemFontOfSize:12],
+        NSBaselineOffsetAttributeName : @(1)
+    }
+                             range:NSMakeRange(groupItem.groupName.length, content.length - groupItem.groupName.length)];
+    return attributeString;
+}
+
+#pragma mark TUINotificationProtocol
+- (void)onNotifyEvent:(NSString *)key subKey:(NSString *)subKey object:(nullable id)anObject param:(nullable NSDictionary *)param {
+    if ([key isEqualToString:TUICore_TUIConversationGroupNotify] || [key isEqualToString:TUICore_TUIConversationMarkNotify]) {
+        if (!self.actualShowConversationGroup) {
+            self.actualShowConversationGroup = YES;
+        }
+    }
+    if ([key isEqualToString:TUICore_TUIConversationGroupNotify]) {
+        if ([param objectForKey:TUICore_TUIConversationGroupNotify_GroupListLoadKey]) {
+            NSArray *groupItemList = [param objectForKey:TUICore_TUIConversationGroupNotify_GroupListLoadKey];
+            if (groupItemList && groupItemList.count > 0) {
+                [self loadGroupList:groupItemList];
+            }
+        } else if ([param objectForKey:TUICore_TUIConversationGroupNotify_GroupAddKey]) {
+            TUIConversationGroupItem *groupItem = [param objectForKey:TUICore_TUIConversationGroupNotify_GroupAddKey];
+            if (groupItem) {
+                [self addGroup:groupItem];
+            }
+        } else if ([param objectForKey:TUICore_TUIConversationGroupNotify_GroupUpdateKey]) {
+            TUIConversationGroupItem *groupItem = [param objectForKey:TUICore_TUIConversationGroupNotify_GroupUpdateKey];
+            if (groupItem) {
+                [self updateGroup:groupItem];
+            }
+        } else if ([param objectForKey:TUICore_TUIConversationGroupNotify_GroupRenameKey]) {
+            NSDictionary *renameItem = [param objectForKey:TUICore_TUIConversationGroupNotify_GroupRenameKey];
+            if (renameItem) {
+                [self renameGroup:renameItem.allKeys.firstObject newName:renameItem.allValues.firstObject];
+            }
+        } else if ([param objectForKey:TUICore_TUIConversationGroupNotify_GroupDeleteKey]) {
+            TUIConversationGroupItem *groupItem = [param objectForKey:TUICore_TUIConversationGroupNotify_GroupDeleteKey];
+            if (groupItem) {
+                [self deleteGroup:groupItem];
+            }
+        }
+    } else if ([key isEqualToString:TUICore_TUIConversationMarkNotify]) {
+        if ([param objectForKey:TUICore_TUIConversationGroupNotify_MarkAddKey]) {
+            TUIConversationGroupItem *groupItem = [param objectForKey:TUICore_TUIConversationGroupNotify_MarkAddKey];
+            if (groupItem) {
+                [self insertGroup:groupItem atIndex:groupItem.groupIndex];
+            }
+        } else if ([param objectForKey:TUICore_TUIConversationGroupNotify_MarkUpdateKey]) {
+            TUIConversationGroupItem *groupItem = [param objectForKey:TUICore_TUIConversationGroupNotify_MarkUpdateKey];
+            if (groupItem) {
+                [self updateGroup:groupItem];
+            }
+        }
+    }
+}
+
+#pragma TUIConversationTableViewDelegate
+- (void)tableViewDidScroll:(CGFloat)offsetY {
+    if (!self.bannerView || self.bannerView.hidden) {
+        return;
+    }
+    UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
+    if (@available(iOS 11.0, *)) {
+        safeAreaInsets = self.currentTableView.adjustedContentInset;
+    }
+    CGFloat contentSizeHeight = self.currentTableView.contentSize.height + safeAreaInsets.top + safeAreaInsets.bottom;
+    if (contentSizeHeight > self.currentTableView.mm_h && self.currentTableView.contentOffset.y + self.currentTableView.mm_h > contentSizeHeight) {
+        return;
+    }
+    if (offsetY > self.bannerView.mm_h) {
+        offsetY = self.bannerView.mm_h;
+    }
+    if (offsetY < 0) {
+        offsetY = 0;
+    }
+    self.bannerView.mm_top(offsetY);
+    if (self.actualShowConversationGroup) {
+        self.groupView.mm_top(self.bannerView.mm_maxY);
+        self.tableViewContainer.mm_top(self.groupView.mm_maxY).mm_height(self.viewHeight - self.groupView.mm_maxY);
+    } else {
+        self.tableViewContainer.mm_top(self.bannerView.mm_maxY).mm_height(self.viewHeight - self.bannerView.mm_maxY);
+    }
+}
+
+- (void)tableViewDidSelectCell:(TUIConversationCellData *)data {
+    if (data.isLocalConversationFoldList) {
+        [TUIConversationListDataProvider cacheConversationFoldListSettings_FoldItemIsUnread:NO];
+
+        TUIFoldListViewController *foldVC = [[TUIFoldListViewController alloc] init];
+        [self.navigationController pushViewController:foldVC animated:YES];
+
+        @weakify(self);
+        foldVC.dismissCallback = ^(NSMutableAttributedString *_Nonnull foldStr, NSArray *_Nonnull sortArr, NSArray *_Nonnull needRemoveFromCacheMapArray) {
+          @strongify(self);
+          data.foldSubTitle = foldStr;
+          data.subTitle = data.foldSubTitle;
+          data.isMarkAsUnread = NO;
+
+          if (sortArr.count <= 0) {
+              data.orderKey = 0;
+              if ([self.dataProvider.conversationList containsObject:data]) {
+                  [self.dataProvider hideConversation:data];
+              }
+          }
+
+          for (NSString *removeId in needRemoveFromCacheMapArray) {
+              if ([self.dataProvider.markFoldMap objectForKey:removeId]) {
+                  [self.dataProvider.markFoldMap removeObjectForKey:removeId];
+              }
+          }
+
+          [TUIConversationListDataProvider cacheConversationFoldListSettings_FoldItemIsUnread:NO];
+          [self.currentTableView reloadData];
+        };
+        return;
+    }
+    if (self.delegate && [self.delegate respondsToSelector:@selector(conversationListController:didSelectConversation:)]) {
+        [self.delegate conversationListController:self didSelectConversation:data];
+    } else {
+        NSDictionary *param = @{
+            TUICore_TUIChatObjectFactory_ChatViewController_Title : data.title ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_UserID : data.userID ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_GroupID : data.groupID ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_AvatarImage : data.avatarImage ?: [UIImage new],
+            TUICore_TUIChatObjectFactory_ChatViewController_AvatarUrl : data.faceUrl ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_ConversationID : data.conversationID ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_AtMsgSeqs : data.atMsgSeqs ?: @[],
+            TUICore_TUIChatObjectFactory_ChatViewController_Draft : data.draftText ?: @""
+        };
+        [self.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Classic param:param forResult:nil];
+    }
+}
+
+- (void)tableViewDidShowAlert:(UIAlertController *)ac {
+    [self presentViewController:ac animated:YES completion:nil];
+}
+
+#pragma TUIPopViewDelegate
+- (void)popView:(TUIPopView *)popView didSelectRowAtIndex:(NSInteger)index {
+    if (0 == index) {
+        [self startConversation:V2TIM_C2C];
+    } else {
+        [self startConversation:V2TIM_GROUP];
+    }
+}
+
+- (void)startConversation:(V2TIMConversationType)type {
+    __weak typeof(self) weakSelf = self;
+    void (^selectContactCompletion)(NSArray<TUICommonContactSelectCellData *> *) = ^(NSArray<TUICommonContactSelectCellData *> *array) {
+      if (V2TIM_C2C == type) {
+          NSDictionary *param = @{
+              TUICore_TUIChatObjectFactory_ChatViewController_Title : array.firstObject.title ?: @"",
+              TUICore_TUIChatObjectFactory_ChatViewController_UserID : array.firstObject.identifier ?: @"",
+              TUICore_TUIChatObjectFactory_ChatViewController_AvatarImage : array.firstObject.avatarImage ?: [UIImage new],
+              TUICore_TUIChatObjectFactory_ChatViewController_AvatarUrl : array.firstObject.avatarUrl.absoluteString ?: @""
+          };
+          [weakSelf.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Classic param:param forResult:nil];
+
+          NSMutableArray *tempArray = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
+          [tempArray removeObjectAtIndex:tempArray.count - 2];
+          weakSelf.navigationController.viewControllers = tempArray;
+      } else {
+          NSString *loginUser = [[V2TIMManager sharedInstance] getLoginUser];
+          [[V2TIMManager sharedInstance]
+              getUsersInfo:@[ loginUser ]
+                      succ:^(NSArray<V2TIMUserFullInfo *> *infoList) {
+                        NSString *showName = loginUser;
+                        if (infoList.firstObject.nickName.length > 0) {
+                            showName = infoList.firstObject.nickName;
+                        }
+                        NSMutableString *groupName = [NSMutableString stringWithString:showName];
+                        for (TUICommonContactSelectCellData *item in array) {
+                            [groupName appendFormat:@"、%@", item.title];
+                        }
+
+                        if ([groupName length] > 10) {
+                            groupName = [groupName substringToIndex:10].mutableCopy;
+                        }
+                        void (^createGroupCompletion)(BOOL, V2TIMGroupInfo *) = ^(BOOL isSuccess, V2TIMGroupInfo *_Nonnull info) {
+                          NSDictionary *param = @{
+                              TUICore_TUIChatObjectFactory_ChatViewController_Title : info.groupName ?: @"",
+                              TUICore_TUIChatObjectFactory_ChatViewController_GroupID : info.groupID ?: @"",
+                              TUICore_TUIChatObjectFactory_ChatViewController_AvatarUrl : info.faceURL ?: @""
+                          };
+                          [self.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Classic param:param forResult:nil];
+
+                          NSMutableArray *tempArray = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
+                          for (UIViewController *vc in self.navigationController.viewControllers) {
+                              if ([vc isKindOfClass:NSClassFromString(@"TUIGroupCreateController")] ||
+                                  [vc isKindOfClass:NSClassFromString(@"TUIContactSelectController")]) {
+                                  [tempArray removeObject:vc];
+                              }
+                          }
+
+                          weakSelf.navigationController.viewControllers = tempArray;
+                        };
+
+                        NSDictionary *param = @{
+                            TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod_TitleKey : array.firstObject.title ?: @"",
+                            TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod_GroupNameKey : groupName ?: @"",
+                            TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod_GroupTypeKey : GroupType_Work,
+                            TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod_CompletionKey : createGroupCompletion,
+                            TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod_ContactListKey : array ?: @[]
+                        };
+
+                        UIViewController *groupVC = (UIViewController *)[TUICore createObject:TUICore_TUIContactObjectFactory
+                                                                                          key:TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod
+                                                                                        param:param];
+                        [weakSelf.navigationController pushViewController:(UIViewController *)groupVC animated:YES];
+                      }
+                      fail:nil];
+      }
+    };
+    NSDictionary *param = @{
+        TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod_TitleKey : TIMCommonLocalizableString(ChatsSelectContact),
+        TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod_MaxSelectCount : @(type == V2TIM_C2C ? 1 : INT_MAX),
+        TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod_CompletionKey : selectContactCompletion
+    };
+    UIViewController *vc = [TUICore createObject:TUICore_TUIContactObjectFactory
+                                             key:TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod
+                                           param:param];
+    [self.navigationController pushViewController:vc animated:YES];
+}
+
+#pragma mark TUIConversationListDataProviderDelegate
+- (NSString *)getConversationDisplayString:(V2TIMConversation *)conversation {
+    if (self.delegate && [self.delegate respondsToSelector:@selector(getConversationDisplayString:)]) {
+        return [self.delegate getConversationDisplayString:conversation];
+    }
+    V2TIMMessage *msg = conversation.lastMessage;
+    if (msg.customElem == nil || msg.customElem.data == nil) {
+        return nil;
+    }
+    NSDictionary *param = [TUITool jsonData2Dictionary:msg.customElem.data];
+    if (param != nil && [param isKindOfClass:[NSDictionary class]]) {
+        NSString *businessID = param[@"businessID"];
+        if (![businessID isKindOfClass:[NSString class]]) {
+            return nil;
+        }
+
+        // whether custom jump message
+        if ([businessID isEqualToString:BussinessID_TextLink] || ([(NSString *)param[@"text"] length] > 0 && [(NSString *)param[@"link"] length] > 0)) {
+            NSString *desc = param[@"text"];
+            if (msg.status == V2TIM_MSG_STATUS_LOCAL_REVOKED) {
+                if (msg.isSelf) {
+                    desc = TIMCommonLocalizableString(TUIKitMessageTipsYouRecallMessage);
+                } else if (msg.userID.length > 0) {
+                    desc = TIMCommonLocalizableString(TUIKitMessageTipsOthersRecallMessage);
+                } else if (msg.groupID.length > 0) {
+                    /**
+                     * 对于群组消息的名称显示,优先显示群名片,昵称优先级其次,用户ID优先级最低。
+                     * For the name display of group messages, the group business card is displayed first, the nickname has the second priority, and the user ID
+                     * has the lowest priority.
+                     */
+                    NSString *userName = msg.nameCard;
+                    if (userName.length == 0) {
+                        userName = msg.nickName ?: msg.sender;
+                    }
+                    desc = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
+                }
+            }
+            return desc;
+        }
+    }
+    return nil;
+}
+
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
+    return UIModalPresentationNone;
+}
+
+@end
+
+

+ 24 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSGroupConversationController.h

@@ -0,0 +1,24 @@
+//
+//  KSGroupConversationController.h
+//  GuanYueTeamManager
+//
+//  Created by 王智 on 2023/8/2.
+//
+
+#import "KSBaseViewController.h"
+#import "TUIGroupChatViewController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSGroupConversationController : KSBaseViewController
+
+@property (nonatomic, strong) TUIChatConversationModel *conversation;
+
+// 搜索用
+@property(nonatomic, copy) NSString *highlightKeyword;
+// 搜索用
+@property(nonatomic, strong) V2TIMMessage *locateMessage;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 93 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSGroupConversationController.m

@@ -0,0 +1,93 @@
+//
+//  KSGroupConversationController.m
+//  GuanYueTeamManager
+//
+//  Created by 王智 on 2023/8/2.
+//
+
+#import "KSGroupConversationController.h"
+#import "GroupSettingViewController.h"
+
+@interface KSGroupConversationController ()
+
+@property (nonatomic, strong) TUIGroupChatViewController *vc;
+
+@end
+
+@implementation KSGroupConversationController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self configUI];
+    [self clearConversation];
+    [self requestData];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+
+    //TODO: 页面appear 禁用
+   [[IQKeyboardManager sharedManager] setEnable:NO];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+
+    //TODO: 页面Disappear 启用
+   [[IQKeyboardManager sharedManager] setEnable:YES];
+}
+
+- (void)clearConversation {
+    
+    NSString *conversationID = [NSString stringWithFormat:@"group_%@",self.conversation.groupID];
+    [[V2TIMManager sharedInstance] cleanConversationUnreadMessageCount:conversationID cleanTimestamp:0 cleanSequence:0 succ:^{
+        
+    } fail:^(int code, NSString *desc) {
+        
+    }];
+}
+
+- (void)configUI {
+    [self rightButton:[UIImage imageNamed:@"mine_setting"]];
+    self.vc = [[TUIGroupChatViewController alloc] init];
+    if (![NSString isEmptyString:self.highlightKeyword]) {
+        self.vc.highlightKeyword = self.highlightKeyword;
+        self.vc.locateMessage = self.locateMessage;
+    }
+    self.vc.conversationData = self.conversation;
+    [self addChildViewController:self.vc];
+    [self.view addSubview:self.vc.view];
+}
+
+- (void)rightBtnClick {
+    GroupSettingViewController *ctrl = [[GroupSettingViewController alloc] init];
+    ctrl.groupId = self.conversation.groupID;
+    [self.navigationController pushViewController:ctrl animated:YES];
+}
+
+- (void)requestData {
+    [KSNetworkingManager queryGroupDetail:KS_POST groupId:self.conversation.groupID success:^(NSDictionary * _Nonnull dic) {
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSDictionary *result = [dic ks_dictionaryValueForKey:@"data"];
+            NSString *groupName = [result ks_stringValueForKey:@"name"];
+            [self allocTitle:groupName];
+        }
+        else if ([dic ks_integerValueForKey:@"code"] == 204) {
+            
+        }
+    } faliure:^(NSError * _Nonnull error) {
+        
+    }];
+}
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 5 - 5
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupMemberViewController.m

@@ -151,11 +151,11 @@
     GroupMemberModel *model = filterArray[indexPath.row];
     MJWeakSelf;
     [cell configWithSource:model callback:^(NSString * _Nonnull targetId, NSString * _Nonnull name) {
-        KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-        conversationVC.conversationType = ConversationType_PRIVATE;
-        conversationVC.targetId = targetId;
-        conversationVC.title = [NSString returnNoNullStringWithString:name];
-        [weakSelf.navigationController pushViewController:conversationVC animated:YES];
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.userID = targetId;
+        KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+        ctrl.conversation = model;
+        [weakSelf.navigationController pushViewController:ctrl animated:YES];
     }];
     return cell;
 }

+ 24 - 46
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupSettingViewController.m

@@ -7,8 +7,7 @@
 
 #import "GroupSettingViewController.h"
 #import "GroupSettingBodyView.h"
-#import <RongIMKit/RongIMKit.h>
-#import "KSSearchHistoryMessageController.h"
+#import "KSSearchViewController.h"
 #import "KSChatComplainController.h"
 #import "GroupListModel.h"
 #import "GroupMemberModel.h"
@@ -16,7 +15,8 @@
 #import "GroupNoticeViewController.h"
 #import "GroupApplyViewController.h"
 #import "KSPublicAlertView.h"
-
+#import <ImSDK_Plus/V2TIMManager+Group.h>
+#import "CustomNavViewController.h"
 
 @interface GroupSettingViewController ()
 
@@ -96,18 +96,6 @@
             for (NSDictionary *parm in sourceArray) {
                 GroupMemberModel *model = [[GroupMemberModel alloc] initWithDictionary:parm];
                 [self.sourceArray addObject:model];
-                
-                // 刷新缓存
-                RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.imUserId name:model.nickname portrait:model.avatar];
-                // 附加字段
-                NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
-                if (model.isAdmin) {
-                    [extraDic setValue:@"owner" forKey:@"groupOwner"];
-                }
-                [extraDic setValue:model.roleType forKey:@"role"];
-                user.extra = [extraDic mj_JSONString];
-                
-                [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.imUserId withGroupId:self.groupId];
             }
             [self evaluateMessge];
         }
@@ -120,32 +108,23 @@
 }
 
 - (void)getGroupMessageNotiferStatus {
-    [[RCIMClient sharedRCIMClient] getConversationNotificationStatus:ConversationType_GROUP targetId:self.groupId success:^(RCConversationNotificationStatus nStatus) {
-        dispatch_main_async_safe(^{
-            if (nStatus == NOTIFY) {
+    [[V2TIMManager sharedInstance] getGroupsInfo:@[self.groupId] succ:^(NSArray<V2TIMGroupInfoResult *> * groupResultList) {
+        for (V2TIMGroupInfoResult *result in groupResultList){
+            V2TIMGroupInfo *info = result.info;
+            NSLog(@"recvOpt, %d", (int)info.recvOpt);
+            if (info.recvOpt == V2TIM_RECEIVE_MESSAGE) {
                 self.bodyView.isOn = NO;
             }
             else {
                 self.bodyView.isOn = YES;
             }
-        });
-        
-    } error:^(RCErrorCode status) {
-        
+        }
+    } fail:^(int code, NSString *desc) {
+        NSLog(@"failure, code:%d, desc:%@", code, desc);
     }];
 }
 
 - (void)refreshUI {
-    // 刷新群缓存信息
-    if (![NSString isEmptyString:self.sourceModel.name]) {
-        RCGroup *group = [[RCGroup alloc] initWithGroupId:self.groupId groupName:self.sourceModel.name portraitUri:self.sourceModel.img];
-        [[RCIM sharedRCIM] refreshGroupInfoCache:group withGroupId:self.groupId];
-    }
-    else {
-        RCGroup *group = [[RCGroup alloc] initWithGroupId:self.groupId groupName:self.sourceModel.memo portraitUri:self.sourceModel.img];
-        [[RCIM sharedRCIM] refreshGroupInfoCache:group withGroupId:self.groupId];
-    }
-    
     MJWeakSelf;
     [self.bodyView configWithSource:self.sourceModel callback:^(GROUPSETTING type) {
         [weakSelf operationWithType:type];
@@ -174,10 +153,15 @@
             break;
         case GROUPSETTING_MESSAGESEARCH:
         {
-            KSSearchHistoryMessageController *searchViewController = [[KSSearchHistoryMessageController alloc] init];
-            searchViewController.conversationType = ConversationType_GROUP;
-            searchViewController.targetId = self.groupId;
-            [self.navigationController pushViewController:searchViewController animated:YES];
+            KSSearchViewController *vc = [[KSSearchViewController alloc] init];
+            vc.groupId = self.groupId;
+            CustomNavViewController *nav = [[CustomNavViewController alloc] initWithRootViewController:(UIViewController *)vc];
+            nav.modalPresentationStyle = UIModalPresentationFullScreen;
+            
+            UIViewController *parentVC = self.navigationController;
+            if (parentVC) {
+                [parentVC presentViewController:nav animated:NO completion:nil];
+            }
         }
             break;
         case GROUPSETTING_SETTING: // 消息提醒
@@ -226,7 +210,6 @@
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
             MJWeakSelf;
             [self KSShowMsg:@"退出成功" promptCompletion:^{
-                [[RCIMClient sharedRCIMClient] removeConversation:ConversationType_GROUP targetId:self.groupId];
                 [weakSelf.navigationController popToRootViewControllerAnimated:YES];
             }];
         }
@@ -241,15 +224,10 @@
 
 - (void)messageSetting {
     
-    RCPushNotificationLevel level = self.bodyView.isOn ? RCPushNotificationLevelBlocked : RCPushNotificationLevelDefault;
-    [[RCChannelClient sharedChannelManager] setConversationNotificationLevel:ConversationType_GROUP targetId:self.groupId level:level success:^{
-        dispatch_main_async_safe(^{
-            MJWeakSelf;
-            [self KSShowMsg:@"设置成功" promptCompletion:^{
-                [weakSelf.navigationController popViewControllerAnimated:YES];
-            }];
-        });
-    } error:^(RCErrorCode status) {
+    V2TIMReceiveMessageOpt type = self.bodyView.isOn ? V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE : V2TIM_RECEIVE_MESSAGE;
+    [[V2TIMManager sharedInstance] setGroupReceiveMessageOpt:self.groupId opt:type succ:^{
+        NSLog(@"success");
+    } fail:^(int code, NSString *desc) {
         dispatch_main_async_safe(^{
             MJWeakSelf;
             [self KSShowMsg:@"设置失败" promptCompletion:^{

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupMemberListCell.m

@@ -53,7 +53,7 @@
             self.memberName.text = model.nickname;
         }
         NSString *userId = model.imUserId;
-        if ([userId isEqualToString:UserDefault(RongCloudID)]) {
+        if ([userId isEqualToString:UserDefault(UIDKey)]) {
             self.chatButton.hidden = YES;
             self.chatButton.userInteractionEnabled = NO;
         }

+ 0 - 27
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Controller/KSSearchHistoryMessageController.h

@@ -1,27 +0,0 @@
-//
-//  KSSearchHistoryMessageController.h
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import "KSBaseTableViewController.h"
-#import <RongIMKit/RongIMKit.h>
-NS_ASSUME_NONNULL_BEGIN
-
-@interface KSSearchHistoryMessageController : KSBaseTableViewController
-
-/*!
- 当前会话的会话类型
- */
-@property (nonatomic, assign) RCConversationType conversationType;
-
-/*!
- 目标会话ID
- */
-@property (nonatomic, strong) NSString *targetId;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 318
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Controller/KSSearchHistoryMessageController.m

@@ -1,318 +0,0 @@
-//
-//  KSSearchHistoryMessageController.m
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import "KSSearchHistoryMessageController.h"
-#import "KSChatConversationViewController.h"
-#import "KSSearchRCLabel.h"
-#import "KSSearchResultModel.h"
-#import "KSRCSearchBar.h"
-#import "KSSearchResultViewCell.h"
-
-@interface KSSearchHistoryMessageController ()<UISearchBarDelegate, UIScrollViewDelegate>
-
-@property (nonatomic, strong) NSArray *resultArray;
-@property (nonatomic, strong) KSRCSearchBar *searchBar;
-@property (nonatomic, strong) UIButton *cancelButton;
-@property (nonatomic, strong) UIView *searchView;
-@property (nonatomic, strong) KSSearchRCLabel *emptyLabel;
-@property (nonatomic, assign) BOOL isLoading;
-
-@end
-
-@implementation KSSearchHistoryMessageController
-
-- (void)viewDidLoad {
-    [super viewDidLoad];
-    // Do any additional setup after loading the view.
-    self.isLoading = NO;
-    self.resultArray = [NSArray array];
-    [self loadSearchView];
-    self.navigationItem.titleView = self.searchView;
-    self.tableView.tableFooterView = [UIView new];
-    self.navigationItem.hidesBackButton = YES;
-    if (@available(iOS 11.0, *)) {
-        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
-    } else {
-        // Fallback on earlier versions
-        self.automaticallyAdjustsScrollViewInsets = NO;
-    }
-}
-
-- (void)viewWillLayoutSubviews {
-    [super viewWillLayoutSubviews];
-    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
-        [self.tableView setSeparatorInset:UIEdgeInsetsMake(0, 10, 0, 0)];
-    }
-    if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
-        [self.tableView setLayoutMargins:UIEdgeInsetsMake(0, 10, 0, 0)];
-    }
-}
-
-
-- (void)loadSearchView {
-    self.searchView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, 44)];
-    self.searchView.backgroundColor = [UIColor clearColor];
-    [self.searchView addSubview:self.searchBar];
-    [self.searchView addSubview:self.cancelButton];
-}
-
-- (void)cancelButtonClicked {
-    [self.searchBar resignFirstResponder];
-    [self.navigationController popViewControllerAnimated:YES];
-}
-
-#pragma mark - UITableViewDelegate
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
-    return self.resultArray.count;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-
-    KSSearchResultViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
-    if (!cell) {
-        cell = [[KSSearchResultViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
-    }
-    cell.searchString = self.searchBar.text;
-    [cell setDataModel:self.resultArray[indexPath.row]];
-    return cell;
-}
-
-- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
-    return 65;
-}
-
-- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
-    KSSearchResultModel *model = self.resultArray[indexPath.row];
-    KSChatConversationViewController *_conversationVC = [[KSChatConversationViewController alloc] init];
-    _conversationVC.conversationType = model.conversationType;
-    _conversationVC.targetId = model.targetId;
-    if (model.conversationType == ConversationType_GROUP) {
-        RCGroup *groupInfo = [[RCIM sharedRCIM] getGroupInfoCache:model.targetId];
-        _conversationVC.title = groupInfo.groupName;
-    } else {
-        _conversationVC.title = model.name;
-    }
-    int unreadCount = [[RCIMClient sharedRCIMClient] getUnreadCount:model.conversationType targetId:model.targetId];
-    _conversationVC.unReadMessage = unreadCount;
-    _conversationVC.enableNewComingMessageIcon = YES; //开启消息提醒
-    _conversationVC.enableUnreadMessageIcon = YES;
-    _conversationVC.locatedMessageSentTime = model.time;
-    //如果是单聊,不显示发送方昵称
-    if (model.conversationType == ConversationType_PRIVATE) {
-        _conversationVC.displayUserNameInCell = NO;
-    }
-    [self.navigationController pushViewController:_conversationVC animated:YES];
-}
-
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
-    self.resultArray = nil;
-    NSArray *result = nil;
-    if (self.conversationType) {
-        result = [[RCIMClient sharedRCIMClient] searchMessages:self.conversationType
-                                                              targetId:self.targetId
-                                                               keyword:searchText
-                                                                 count:50
-                                                             startTime:0];
-        NSMutableArray *resultArray = [NSMutableArray array];
-        for (RCMessage *message in result) {
-            KSSearchResultModel *messegeModel = [KSSearchResultModel modelForMessage:message];
-            [resultArray addObject:messegeModel];
-        }
-        self.resultArray = resultArray;
-        [self refreshSearchView:searchText];
-        if (self.resultArray.count < 50) {
-            self.isLoading = NO;
-        } else {
-            self.isLoading = YES;
-        }
-    }
-    else {
-        result = [[RCIMClient sharedRCIMClient] searchConversations:@[ @(ConversationType_GROUP), @(ConversationType_PRIVATE) ] messageType:@[
-            [RCTextMessage getObjectName],
-            [RCRichContentMessage getObjectName],
-            [RCFileMessage getObjectName]
-        ] keyword:searchText];
-        NSMutableArray *resultArray = [NSMutableArray array];
-        for (RCSearchConversationResult *searchResult in result) {
-            KSSearchResultModel *messegeModel = [[KSSearchResultModel alloc] init];
-            messegeModel.conversationType = searchResult.conversation.conversationType;
-            messegeModel.targetId = searchResult.conversation.targetId;
-            if (searchResult.matchCount > 1) {
-                messegeModel.otherInformation = [NSString stringWithFormat:@"共%d条相关的聊天记录", searchResult.matchCount];
-            } else {
-                NSString *string = nil;
-                messegeModel.objectName = searchResult.conversation.objectName;
-                if ([searchResult.conversation.lastestMessage isKindOfClass:[RCRichContentMessage class]]) {
-                    RCRichContentMessage *rich = (RCRichContentMessage *)searchResult.conversation.lastestMessage;
-                    string = rich.title;
-                } else if ([searchResult.conversation.lastestMessage isKindOfClass:[RCFileMessage class]]) {
-                    RCFileMessage *file = (RCFileMessage *)searchResult.conversation.lastestMessage;
-                    string = file.name;
-                } else {
-                    string = [self formatMessage:searchResult.conversation.lastestMessage
-                                   withMessageId:searchResult.conversation.lastestMessageId];
-                }
-                messegeModel.otherInformation = [self relaceEnterBySpace:string];
-            }
-            if (searchResult.conversation.conversationType == ConversationType_PRIVATE) {
-                RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:searchResult.conversation.targetId];
-                messegeModel.name = user.name;
-                messegeModel.portraitUri = user.portraitUri;
-            } else if (searchResult.conversation.conversationType == ConversationType_GROUP) {
-                RCGroup *group = [[RCIM sharedRCIM] getGroupInfoCache:searchResult.conversation.targetId];
-                messegeModel.name = group.groupName;
-                messegeModel.portraitUri = group.portraitUri;
-            }
-            messegeModel.count = searchResult.matchCount;
-            if (messegeModel.conversationType == ConversationType_GROUP && ![messegeModel.targetId containsString:@"FAN"] && ![messegeModel.targetId containsString:@"COURSE"]) { // 视频课聊天群不添加
-            }
-            else {
-                [resultArray addObject:messegeModel];
-            }
-        }
-        self.resultArray = resultArray;
-        [self refreshSearchView:searchText];
-        self.isLoading = NO;
-    }
-    
-}
-
-- (NSString *)relaceEnterBySpace:(NSString *)originalString {
-    NSString *string = [originalString stringByReplacingOccurrencesOfString:@"\r\n" withString:@" "];
-    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
-    string = [string stringByReplacingOccurrencesOfString:@"\r" withString:@" "];
-    return string;
-}
-
-- (NSString *)formatMessage:(RCMessageContent *)messageContent withMessageId:(long)messageId {
-    
-    if (RCKitConfigCenter.message.showUnkownMessage && messageId > 0 && !messageContent) {
-        return NSLocalizedStringFromTable(@"unknown_message_cell_tip", @"RongCloudKit", nil);
-    } else {
-        return [RCKitUtility formatMessage:messageContent];
-    }
-}
-
-
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
-    [self.searchBar resignFirstResponder];
-}
-
-- (void)refreshSearchView:(NSString *)searchText {
-    [self.tableView reloadData];
-    NSString *searchStr = [searchText stringByReplacingOccurrencesOfString:@" " withString:@""];
-    if (!self.resultArray.count && searchText.length > 0 && searchStr.length > 0) {
-        NSString *str = [NSString stringWithFormat:@"没有搜索到“%@”相关的内容", searchText];
-        self.emptyLabel.textColor = HexRGB(0x999999);
-        NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:str];
-        int index = 6;
-        [attributedString addAttribute:NSForegroundColorAttributeName
-                                 value:HexRGB(0x2dc7aa)
-                                 range:NSMakeRange(index, searchText.length)];
-        self.emptyLabel.attributedText = attributedString;
-        CGFloat height = [self labelAdaptive:str];
-        CGRect rect = self.emptyLabel.frame;
-        rect.size.height = height;
-        self.emptyLabel.frame = rect;
-        self.emptyLabel.hidden = NO;
-    } else {
-        self.emptyLabel.hidden = YES;
-    }
-}
-
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
-    if (scrollView.contentOffset.y < self.tableView.contentSize.height && self.isLoading) {
-        [self searchMoreMessage];
-    }
-}
-
-- (void)searchMoreMessage {
-    NSArray *result = nil;
-    if (self.conversationType) {
-        KSSearchResultModel *model = self.resultArray[self.resultArray.count - 1];
-        result = [[RCIMClient sharedRCIMClient] searchMessages:self.conversationType
-                                                              targetId:self.targetId
-                                                               keyword:self.searchBar.text
-                                                                 count:50
-                                                             startTime:model.time];
-        if (result.count < 50) {
-            self.isLoading = NO;
-        } else {
-            self.isLoading = YES;
-        }
-        NSMutableArray *resultArray = self.resultArray.mutableCopy;
-        for (RCMessage *message in result) {
-            KSSearchResultModel *messegeModel = [KSSearchResultModel modelForMessage:message];
-            [resultArray addObject:messegeModel];
-        }
-        self.resultArray = resultArray;
-        [self refreshSearchView:nil];
-    }
-}
-
-- (CGFloat)labelAdaptive:(NSString *)string {
-    float maxWidth = self.view.frame.size.width - 20;
-    CGRect textRect =
-        [string boundingRectWithSize:CGSizeMake(maxWidth, 8000)
-                             options:(NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin |
-                                      NSStringDrawingUsesFontLeading)
-                          attributes:@{
-                              NSFontAttributeName : [UIFont systemFontOfSize:14.0]
-                          }
-                             context:nil];
-    textRect.size.height = ceilf(textRect.size.height);
-    return textRect.size.height + 5;
-}
-
-#pragma mark - getter
-- (KSRCSearchBar *)searchBar {
-    if (!_searchBar) {
-        _searchBar = [[KSRCSearchBar alloc] initWithFrame:CGRectZero];
-        _searchBar.delegate = self;
-        _searchBar.tintColor = HexRGB(0x444444);
-        _searchBar.layer.cornerRadius = 22.0f;
-        [_searchBar becomeFirstResponder];
-        _searchBar.frame = CGRectMake(0, 0, self.searchView.frame.size.width - 75, 44);
-    }
-    return _searchBar;
-}
-- (UIButton *)cancelButton {
-    if (!_cancelButton) {
-        _cancelButton = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.searchBar.frame) - 3,
-                                                                   CGRectGetMinY(self.searchBar.frame), 60, 44)];
-        [_cancelButton setTitle:@"取消" forState:UIControlStateNormal];
-        [_cancelButton setTitleColor:HexRGB(0x1a1a1a) forState:UIControlStateNormal];
-        _cancelButton.titleLabel.font = [UIFont systemFontOfSize:18.];
-        [_cancelButton addTarget:self
-                          action:@selector(cancelButtonClicked)
-                forControlEvents:UIControlEventTouchUpInside];
-    }
-    return _cancelButton;
-}
-- (UILabel *)emptyLabel {
-    if (!_emptyLabel) {
-        self.emptyLabel = [[KSSearchRCLabel alloc] initWithFrame:CGRectMake(10, 45, self.view.frame.size.width - 20, 16)];
-        self.emptyLabel.font = [UIFont systemFontOfSize:14.f];
-        self.emptyLabel.textAlignment = NSTextAlignmentCenter;
-        self.emptyLabel.numberOfLines = 0;
-        [self.tableView addSubview:self.emptyLabel];
-    }
-    return _emptyLabel;
-}
-
-/*
-#pragma mark - Navigation
-
-// In a storyboard-based application, you will often want to do a little preparation before navigation
-- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
-    // Get the new view controller using [segue destinationViewController].
-    // Pass the selected object to the new view controller.
-}
-*/
-
-@end

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSChatSearchBar.h

@@ -0,0 +1,18 @@
+//
+//  KSChatSearchBar.h
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2023/8/3.
+//
+
+#import <TUISearch/TUISearch.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSChatSearchBar : TUISearchBar
+
+@property (nonatomic, strong, readonly) UISearchBar *mySearchBar;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 167 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSChatSearchBar.m

@@ -0,0 +1,167 @@
+//
+//  KSChatSearchBar.m
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2023/8/3.
+//
+
+#import "KSChatSearchBar.h"
+#import <TIMCommon/TIMDefine.h>
+#import <TUICore/TUICore.h>
+#import <TUICore/TUIDarkModel.h>
+#import <TUICore/TUIGlobalization.h>
+#import <TUICore/TUIThemeManager.h>
+#import <TUICore/UIView+TUILayout.h>
+#import "TUISearchViewController.h"
+
+@interface KSChatSearchBar () <UISearchBarDelegate>
+
+@property (nonatomic, strong) UISearchBar *mySearchBar;
+
+@property(nonatomic, assign) BOOL isEntrance;
+
+
+@property (nonatomic, strong) UIButton *cancelButton;
+@end
+
+
+@implementation KSChatSearchBar
+
+- (void)setEntrance:(BOOL)isEntrance {
+    self.isEntrance = isEntrance;
+    [self setupViews];
+}
+
+- (UIColor *)bgColorOfSearchBar {
+    return TIMCommonDynamicColor(@"head_bg_gradient_start_color", @"#EBF0F6");
+}
+
+- (void)setupViews {
+    self.backgroundColor = self.bgColorOfSearchBar;
+    UISearchBar *searchBar = [[UISearchBar alloc] init];
+    searchBar.placeholder = TIMCommonLocalizableString(Search);
+    searchBar.backgroundImage = [UIImage new];
+    searchBar.barTintColor = UIColor.redColor;
+    searchBar.showsCancelButton = NO;
+    searchBar.delegate = self;
+    searchBar.layer.cornerRadius = 22.0f;
+
+    if (@available(iOS 13.0, *)) {
+        searchBar.searchTextField.backgroundColor = HexRGBAlpha(0xf5f5f5, 0.6f);
+    }
+    self.mySearchBar = searchBar;
+    [self addSubview:self.mySearchBar];
+    [self addSubview:self.cancelButton];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    self.mySearchBar.frame = CGRectMake(0, 0, self.mm_w - 50, self.mm_h);
+    self.cancelButton.frame = CGRectMake(self.mm_w - 50 + 3, 0, 50, self.mm_h);
+    [self updateSearchIcon];
+}
+
+- (void)updateSearchIcon {
+    if ([self.mySearchBar isFirstResponder] || self.mySearchBar.text.length || !self.isEntrance) {
+        [self.mySearchBar setPositionAdjustment:UIOffsetZero forSearchBarIcon:UISearchBarIconSearch];
+        self.backgroundColor = self.superview.backgroundColor;
+    } else {
+        [self.mySearchBar setPositionAdjustment:UIOffsetMake(0.5 * (self.mm_w - 10 - 10) - 40, 0) forSearchBarIcon:UISearchBarIconSearch];
+        self.backgroundColor = self.bgColorOfSearchBar;
+    }
+}
+
+- (void)showSearchVC {
+    TUISearchViewController *vc = [[TUISearchViewController alloc] init];
+    TUINavigationController *nav = [[TUINavigationController alloc] initWithRootViewController:(UIViewController *)vc];
+    nav.modalPresentationStyle = UIModalPresentationFullScreen;
+
+    UIViewController *parentVC = self.parentVC;
+    if (parentVC) {
+        [parentVC presentViewController:nav animated:NO completion:nil];
+    }
+}
+
+#pragma mark - UISearchBarDelegate
+- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
+    [self showSearchVC];
+
+    if (self.isEntrance && [self.delegate respondsToSelector:@selector(searchBarDidEnterSearch:)]) {
+        [self.delegate searchBarDidEnterSearch:self];
+    }
+
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(dispatch_get_main_queue(), ^{
+      [weakSelf updateSearchIcon];
+    });
+    return !self.isEntrance;
+}
+
+- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
+    if ([self.delegate respondsToSelector:@selector(searchBarDidCancelClicked:)]) {
+        [self.delegate searchBarDidCancelClicked:self];
+    }
+}
+
+- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
+    if ([self.delegate respondsToSelector:@selector(searchBar:searchText:)]) {
+        [self.delegate searchBar:self searchText:searchBar.text];
+    }
+}
+
+- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
+    if ([self.delegate respondsToSelector:@selector(searchBar:searchText:)]) {
+        [self.delegate searchBar:self searchText:searchBar.text];
+    }
+}
+
+- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
+//    [self enableCancelButton];
+}
+
+- (void)enableCancelButton {
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(dispatch_get_main_queue(), ^{
+      UIButton *cancelBtn = [weakSelf.searchBar valueForKeyPath:@"cancelButton"];
+      for (UIButton *view in cancelBtn.subviews) {
+          if ([view isKindOfClass:UIButton.class]) {
+              view.userInteractionEnabled = YES;
+              view.enabled = YES;
+          }
+      }
+      cancelBtn.enabled = YES;
+      cancelBtn.userInteractionEnabled = YES;
+
+      [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[ [UISearchBar class] ]].title = TIMCommonLocalizableString(TUIKitSearchItemCancel);
+        [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTintColor:HexRGB(0x1CACF1)];
+
+    });
+}
+
+- (UIButton *)cancelButton {
+    if (!_cancelButton) {
+        _cancelButton = [[UIButton alloc] initWithFrame:CGRectZero];
+        [_cancelButton setTitle:@"取消" forState:UIControlStateNormal];
+        [_cancelButton setTitleColor:THEMECOLOR forState:UIControlStateNormal];
+        _cancelButton.titleLabel.font = [UIFont systemFontOfSize:18.];
+        [_cancelButton addTarget:self
+                          action:@selector(cancelButtonClicked)
+                forControlEvents:UIControlEventTouchUpInside];
+    }
+    return _cancelButton;
+}
+
+- (void)cancelButtonClicked {
+    if ([self.delegate respondsToSelector:@selector(searchBarDidCancelClicked:)]) {
+        [self.delegate searchBarDidCancelClicked:self];
+    }
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 16 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchResultListController.h

@@ -0,0 +1,16 @@
+//
+//  KSSearchResultListController.h
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2023/8/1.
+//
+
+#import <TUISearch/TUISearch.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSSearchResultListController : TUISearchResultListController
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 367 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchResultListController.m

@@ -0,0 +1,367 @@
+//
+//  KSSearchResultListController.m
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2023/8/1.
+//
+
+#import "KSSearchResultListController.h"
+#import <TIMCommon/TIMDefine.h>
+#import <TUICore/TUICore.h>
+#import "KSChatSearchBar.h"
+#import "TUISearchResultCell.h"
+#import "TUISearchResultCellModel.h"
+#import "TUISearchResultHeaderFooterView.h"
+#import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
+
+@interface KSSearchResultListController () <UITableViewDelegate, UITableViewDataSource, TUISearchBarDelegate, TUISearchResultDelegate>
+
+@property(nonatomic, strong) NSMutableArray<TUISearchResultCellModel *> *results;
+@property(nonatomic, copy) NSString *keyword;
+@property(nonatomic, assign) TUISearchResultModule module;
+@property(nonatomic, strong) NSDictionary<TUISearchParamKey, id> *param;
+@property(nonatomic, strong) TUISearchDataProvider *dataProvider;
+
+@property(nonatomic, strong) KSChatSearchBar *searchBar;
+@property(nonatomic, strong) UITableView *tableView;
+
+@property(nonatomic, assign) BOOL allowPageRequest;
+@property(nonatomic, assign) NSUInteger pageIndex;
+
+@end
+
+@implementation KSSearchResultListController
+
+static NSString *const Id = @"cell";
+static NSString *const HFId = @"HFId";
+
+- (instancetype)initWithResults:(NSArray<TUISearchResultCellModel *> *__nullable)results
+                        keyword:(NSString *__nullable)keyword
+                         module:(TUISearchResultModule)module
+                          param:(NSDictionary<TUISearchParamKey, id> *__nullable)param;
+{
+    if (self = [super init]) {
+        _results = (module == TUISearchResultModuleChatHistory) ? [NSMutableArray arrayWithArray:@[]] : [NSMutableArray arrayWithArray:results];
+        _keyword = keyword;
+        _module = module;
+        _dataProvider = [[TUISearchDataProvider alloc] init];
+        _dataProvider.delegate = self;
+        _param = param;
+        _allowPageRequest = (module == TUISearchResultModuleChatHistory);
+        _pageIndex = 0;
+    }
+    return self;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    self.navigationController.navigationBar.backgroundColor = [UIColor groupTableViewBackgroundColor];
+    [self.navigationController.navigationBar setBackgroundImage:[self imageWithColor:[UIColor groupTableViewBackgroundColor]]
+                                                  forBarMetrics:UIBarMetricsDefault];
+    self.navigationController.navigationBar.shadowImage = [UIImage new];
+    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
+
+    UIImage *image = [UIImage imageNamed:@"ic_back_white"];
+    image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
+    UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:self action:@selector(back)];
+    self.navigationItem.leftBarButtonItems = @[ back ];
+    self.navigationItem.leftItemsSupplementBackButton = NO;
+
+    _searchBar = [[KSChatSearchBar alloc] init];
+    [_searchBar setEntrance:NO];
+    _searchBar.delegate = self;
+    _searchBar.mySearchBar.text = self.keyword;
+    self.navigationItem.titleView = _searchBar;
+
+    _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
+    _tableView.delegate = self;
+    _tableView.dataSource = self;
+    _tableView.backgroundColor = [UIColor groupTableViewBackgroundColor];
+    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+    _tableView.rowHeight = 60.f;
+    [_tableView registerClass:TUISearchResultCell.class forCellReuseIdentifier:Id];
+    [_tableView registerClass:TUISearchResultHeaderFooterView.class forHeaderFooterViewReuseIdentifier:HFId];
+    [self.view addSubview:_tableView];
+
+    if (self.module == TUISearchResultModuleChatHistory) {
+        [self.dataProvider searchForKeyword:self.searchBar.mySearchBar.text forModules:self.module param:self.param];
+    }
+}
+
+- (void)back {
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)viewWillLayoutSubviews {
+    [super viewWillLayoutSubviews];
+    self.tableView.frame = self.view.bounds;
+    self.searchBar.frame = CGRectMake(0, 0, self.view.mm_w, 44);
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    self.navigationController.navigationBar.backgroundColor = [UIColor groupTableViewBackgroundColor];
+    [self.navigationController.navigationBar setBackgroundImage:[self imageWithColor:[UIColor groupTableViewBackgroundColor]]
+                                                  forBarMetrics:UIBarMetricsDefault];
+    self.navigationController.navigationBar.shadowImage = [UIImage new];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    self.navigationController.navigationBar.backgroundColor = nil;
+    [self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
+    self.navigationController.navigationBar.shadowImage = nil;
+}
+
+#pragma mark - Table view data source
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.results.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    TUISearchResultCell *cell = [tableView dequeueReusableCellWithIdentifier:Id forIndexPath:indexPath];
+    if (indexPath.row >= self.results.count) {
+        return cell;
+    }
+    [cell fillWithData:self.results[indexPath.row]];
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:NO];
+    if (indexPath.row >= self.results.count) {
+        return;
+    }
+    TUISearchResultCellModel *cellModel = self.results[indexPath.row];
+    [self onSelectModel:cellModel module:self.module];
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return self.results.count == 0 ? 0 : 30;
+}
+
+- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
+    TUISearchResultHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HFId];
+    headerView.isFooter = NO;
+    headerView.title = titleForModule(self.module, YES);
+    return headerView;
+}
+
+- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
+    return nil;
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    [self.view endEditing:YES];
+    [self.searchBar endEditing:YES];
+
+    if (self.allowPageRequest && scrollView.contentOffset.y + scrollView.bounds.size.height > scrollView.contentSize.height) {
+        self.allowPageRequest = NO;
+        NSMutableDictionary *param = [NSMutableDictionary dictionaryWithDictionary:self.param];
+        param[TUISearchChatHistoryParamKeyPage] = @(self.pageIndex);
+        param[TUISearchChatHistoryParamKeyCount] = @(TUISearchDefaultPageSize);
+        self.param = [NSDictionary dictionaryWithDictionary:param];
+        [self.dataProvider searchForKeyword:self.searchBar.mySearchBar.text forModules:self.module param:self.param];
+    }
+}
+
+- (void)onBack {
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)onSelectModel:(TUISearchResultCellModel *)cellModel module:(TUISearchResultModule)module {
+    [self.searchBar endEditing:YES];
+    if (module == TUISearchResultModuleChatHistory) {
+        if (![cellModel.context isKindOfClass:NSDictionary.class]) {
+            if ([cellModel.context isKindOfClass:V2TIMMessage.class]) {
+                V2TIMMessage *message = cellModel.context;
+                NSString *title = message.userID;
+                if (cellModel.title.length > 0) {
+                    title = cellModel.title;
+                }
+                NSDictionary *param = @{
+                    TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+                    TUICore_TUIChatObjectFactory_ChatViewController_UserID : message.userID ?: @"",
+                    TUICore_TUIChatObjectFactory_ChatViewController_GroupID : message.groupID ?: @"",
+                    TUICore_TUIChatObjectFactory_ChatViewController_HighlightKeyword : self.searchBar.mySearchBar.text ?: @"",
+                    TUICore_TUIChatObjectFactory_ChatViewController_LocateMessage : message,
+                };
+                if (![NSString isEmptyString:message.userID]) { // 单聊
+                KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+                ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+                ctrl.locateMessage = message;
+                TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+                model.userID = message.userID;
+                ctrl.conversation = model;
+                [self.navigationController pushViewController:ctrl animated:YES];
+            }
+            else { // 群聊
+                KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+                ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+                ctrl.locateMessage = message;
+                TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+                model.groupID = message.groupID;
+                ctrl.conversation = model;
+                [self.navigationController pushViewController:ctrl animated:YES];
+            }
+                return;
+            }
+            return;
+        }
+        NSDictionary *convInfo = cellModel.context;
+        NSString *conversationId = convInfo[kSearchChatHistoryConversationId];
+        V2TIMConversation *conversation = convInfo[kSearchChatHistoryConverationInfo];
+        NSArray *msgs = convInfo[kSearchChatHistoryConversationMsgs];
+        if (msgs.count == 1) {
+            NSString *title = cellModel.title ?: cellModel.titleAttributeString.string;
+            NSDictionary *param = @{
+                TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_UserID : conversation.userID ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_GroupID : conversation.groupID ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_HighlightKeyword : self.searchBar.mySearchBar.text ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_LocateMessage : msgs.firstObject,
+            };
+            if (![NSString isEmptyString:conversation.userID]) { // 单聊
+                KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+                ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+                ctrl.locateMessage = msgs.firstObject;
+                TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+                model.userID = conversation.userID;
+                ctrl.conversation = model;
+                [self.navigationController pushViewController:ctrl animated:YES];
+            }
+            else { // 群聊
+                KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+                ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+                ctrl.locateMessage = msgs.firstObject;
+                TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+                model.groupID = conversation.groupID;
+                ctrl.conversation = model;
+                [self.navigationController pushViewController:ctrl animated:YES];
+
+            }
+            
+            
+            return;
+        }
+
+        NSMutableArray *results = [NSMutableArray array];
+        for (V2TIMMessage *message in msgs) {
+            TUISearchResultCellModel *model = [[TUISearchResultCellModel alloc] init];
+            model.title = message.nickName ?: message.sender;
+            NSString *desc = [TUISearchDataProvider matchedTextForMessage:message withKey:self.searchBar.mySearchBar.text];
+            model.detailsAttributeString = [TUISearchDataProvider attributeStringWithText:desc key:self.searchBar.mySearchBar.text];
+            model.avatarUrl = message.faceURL;
+            model.groupType = conversation.groupID;
+            model.avatarImage = conversation.type == V2TIM_C2C ? DefaultAvatarImage : DefaultGroupAvatarImageByGroupType(conversation.groupType);
+            model.context = message;
+            [results addObject:model];
+        }
+        KSSearchResultListController *vc =
+            [[KSSearchResultListController alloc] initWithResults:results
+                                                           keyword:self.searchBar.mySearchBar.text
+                                                            module:module
+                                                             param:@{TUISearchChatHistoryParamKeyConversationId : conversationId}];
+        [self.navigationController pushViewController:vc animated:YES];
+        return;
+    }
+
+    NSDictionary *param = nil;
+    NSString *title = cellModel.title ?: cellModel.titleAttributeString.string;
+    if (module == TUISearchResultModuleContact && [cellModel.context isKindOfClass:V2TIMFriendInfo.class]) {
+        V2TIMFriendInfo *friend = cellModel.context;
+        param = @{
+            TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_UserID : friend.userID ?: @"",
+
+        };
+        KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.userID = friend.userID;
+        ctrl.conversation = model;
+        [self.navigationController pushViewController:ctrl animated:YES];
+    }
+
+    if (module == TUISearchResultModuleGroup && [cellModel.context isKindOfClass:V2TIMGroupInfo.class]) {
+        V2TIMGroupInfo *group = cellModel.context;
+        param = @{
+            TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_GroupID : group.groupID ?: @"",
+
+        };
+        KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.groupID = group.groupID;
+        ctrl.conversation = model;
+        [self.navigationController pushViewController:ctrl animated:YES];
+    }
+}
+
+#pragma mark - TUISearchBarDelegate
+- (void)searchBarDidCancelClicked:(TUISearchBar *)searchBar {
+    [self dismissViewControllerAnimated:NO completion:nil];
+}
+
+- (void)searchBar:(TUISearchBar *)searchBar searchText:(NSString *)key {
+    [self.results removeAllObjects];
+    self.allowPageRequest = YES;
+    self.pageIndex = 0;
+    NSMutableDictionary *param = [NSMutableDictionary dictionaryWithDictionary:self.param];
+    param[TUISearchChatHistoryParamKeyPage] = @(self.pageIndex);
+    self.param = [NSDictionary dictionaryWithDictionary:param];
+
+    [self.dataProvider searchForKeyword:key forModules:self.module param:self.param];
+}
+
+#pragma mark - TUISearchResultDelegate
+- (void)onSearchResults:(NSDictionary<NSNumber *, NSArray<TUISearchResultCellModel *> *> *)results forModules:(TUISearchResultModule)modules {
+    NSArray *arrayM = [results objectForKey:@(modules)];
+    if (arrayM == nil) {
+        arrayM = @[];
+    }
+
+    [self.results addObjectsFromArray:arrayM];
+    [self.tableView reloadData];
+
+    self.allowPageRequest = (arrayM.count >= TUISearchDefaultPageSize);
+    self.pageIndex = (arrayM.count < TUISearchDefaultPageSize) ? self.pageIndex : self.pageIndex + 1;
+
+    if (!self.allowPageRequest) {
+    }
+}
+
+- (void)onSearchError:(NSString *)errMsg {
+    NSLog(@"search error: %@", errMsg);
+}
+
+- (UIImage *)imageWithColor:(UIColor *)color {
+    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
+    UIGraphicsBeginImageContext(rect.size);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+
+    CGContextSetFillColorWithColor(context, [color CGColor]);
+    CGContextFillRect(context, rect);
+
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+
+    return image;
+}
+
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchViewController.h

@@ -0,0 +1,18 @@
+//
+//  KSSearchViewController.h
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2023/7/20.
+//
+
+#import <TUISearch/TUISearch.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSSearchViewController : TUISearchViewController
+
+@property (nonatomic, strong) NSString *groupId; // 搜索群组的时候使用
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 339 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/KSSearchViewController.m

@@ -0,0 +1,339 @@
+//
+//  KSSearchViewController.m
+//  KulexiuSchoolStudent
+//
+//  Created by 王智 on 2023/7/20.
+//
+
+#import "KSSearchViewController.h"
+#import <TIMCommon/TIMDefine.h>
+#import <TUICore/TUICore.h>
+#import "KSChatSearchBar.h"
+#import "TUISearchDataProvider.h"
+#import "TUISearchResultCell.h"
+#import "TUISearchResultCellModel.h"
+#import "TUISearchResultHeaderFooterView.h"
+#import "KSSearchResultListController.h"
+#import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
+
+@interface KSSearchViewController ()<UITableViewDelegate, UITableViewDataSource, TUISearchBarDelegate, TUISearchResultDelegate>
+
+@property(nonatomic, strong) KSChatSearchBar *searchBar;
+
+@property(nonatomic, strong) UITableView *tableView;
+
+@property(nonatomic, strong) TUISearchDataProvider *dataProvider;
+
+@end
+
+@implementation KSSearchViewController
+
+static NSString *const Id = @"cell";
+static NSString *const HFId = @"HFId";
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.ks_prefersNavigationBarHidden = NO;
+    _dataProvider = [[TUISearchDataProvider alloc] init];
+    _dataProvider.delegate = self;
+    [self setupViews];
+    [TUITool addUnsupportNotificationInVC:self];
+}
+
+- (void)dealloc {
+    NSLog(@"%s dealloc", __FUNCTION__);
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)setupViews {
+    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
+    _searchBar = [[KSChatSearchBar alloc] init];
+    [_searchBar setEntrance:NO];
+    _searchBar.delegate = self;
+    self.navigationItem.titleView = _searchBar;
+
+    _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
+    _tableView.delegate = self;
+    _tableView.dataSource = self;
+    _tableView.backgroundColor = [UIColor groupTableViewBackgroundColor];
+    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+    _tableView.rowHeight = 60.f;
+    [_tableView registerClass:TUISearchResultCell.class forCellReuseIdentifier:Id];
+    [_tableView registerClass:TUISearchResultHeaderFooterView.class forHeaderFooterViewReuseIdentifier:HFId];
+    [self.view addSubview:_tableView];
+
+    [_searchBar.mySearchBar becomeFirstResponder];
+}
+
+- (void)viewWillLayoutSubviews {
+    [super viewWillLayoutSubviews];
+    self.tableView.frame = self.view.bounds;
+    self.searchBar.frame = CGRectMake(0, 0, KPortraitWidth, 44);
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+}
+
+#pragma mark - TUISearchResultDelegate
+- (void)onSearchError:(NSString *)errMsg {
+}
+
+- (void)onSearchResults:(NSDictionary<NSNumber *, NSArray<TUISearchResultCellModel *> *> *)results forModules:(TUISearchResultModule)modules {
+    [self.tableView reloadData];
+}
+
+#pragma mark - UITableViewDataSource、TUITableViewDelegate
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return self.dataProvider.resultSet.allKeys.count;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSArray *results = [self resultForSection:section];
+    return results.count > kMaxNumOfPerModule ? kMaxNumOfPerModule : results.count;
+}
+
+- (TUISearchResultCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    TUISearchResultCell *cell = [tableView dequeueReusableCellWithIdentifier:Id forIndexPath:indexPath];
+    TUISearchResultModule module = TUISearchResultModuleContact;
+    NSArray *results = [self resultForSection:indexPath.section module:&module];
+    if (results.count <= indexPath.row) {
+        return cell;
+    }
+    [cell fillWithData:results[indexPath.row]];
+    return cell;
+}
+
+- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
+    TUISearchResultModule module = TUISearchResultModuleContact;
+    NSArray *results = [self resultForSection:section module:&module];
+    if (results.count < kMaxNumOfPerModule) {
+        return [UIView new];
+    }
+    __weak typeof(self) weakSelf = self;
+    TUISearchResultHeaderFooterView *footerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HFId];
+    footerView.isFooter = YES;
+    footerView.title = titleForModule(module, NO);
+    footerView.onTap = ^{
+      [weakSelf onSelectMoreModule:module results:results];
+    };
+    return footerView;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    NSArray *results = [self resultForSection:section];
+    if (results.count < kMaxNumOfPerModule) {
+        return 10;
+    }
+    return 44;
+}
+
+- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
+    TUISearchResultModule module = TUISearchResultModuleContact;
+    [self resultForSection:section module:&module];
+    TUISearchResultHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HFId];
+    headerView.isFooter = NO;
+    headerView.title = titleForModule(module, YES);
+    headerView.onTap = nil;
+    return headerView;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 30;
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    [self.view endEditing:YES];
+    [self.searchBar endEditing:YES];
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:NO];
+    TUISearchResultModule module = TUISearchResultModuleContact;
+    NSArray *results = [self resultForSection:indexPath.section module:&module];
+    if (results.count <= indexPath.row) {
+        return;
+    }
+    TUISearchResultCellModel *cellModel = results[indexPath.row];
+    [self onSelectModel:cellModel module:module];
+}
+
+
+#pragma mark - action
+- (void)onSelectModel:(TUISearchResultCellModel *)cellModel module:(TUISearchResultModule)module {
+    [self.searchBar endEditing:YES];
+
+    if (module == TUISearchResultModuleChatHistory) {
+        if (![NSString isEmptyString:self.groupId] && [cellModel.context isKindOfClass:[V2TIMMessage class]]) {
+            V2TIMMessage *msg = (V2TIMMessage *)cellModel.context;
+            // 进入群聊页面
+            KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+            ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+            ctrl.locateMessage = msg;
+            TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+            model.groupID = cellModel.groupID;
+            ctrl.conversation = model;
+            [self.navigationController pushViewController:ctrl animated:YES];
+            return;
+        }
+        if (![cellModel.context isKindOfClass:NSDictionary.class]) {
+            return;
+        }
+        NSDictionary *convInfo = cellModel.context;
+        NSString *conversationId = convInfo[kSearchChatHistoryConversationId];
+        V2TIMConversation *conversation = convInfo[kSearchChatHistoryConverationInfo];
+        NSArray *msgs = convInfo[kSearchChatHistoryConversationMsgs];
+        if (msgs.count == 1) {
+            NSString *title = cellModel.title ?: cellModel.titleAttributeString.string;
+            NSDictionary *param = @{
+                TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_UserID : conversation.userID ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_GroupID : conversation.groupID ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_HighlightKeyword : self.searchBar.mySearchBar.text ?: @"",
+                TUICore_TUIChatObjectFactory_ChatViewController_LocateMessage : msgs.firstObject,
+            };
+            
+            if (![NSString isEmptyString:conversation.userID]) { // 单聊
+                KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+                ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+                ctrl.locateMessage = msgs.firstObject;
+                TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+                model.userID = conversation.userID;
+                ctrl.conversation = model;
+                [self.navigationController pushViewController:ctrl animated:YES];
+            }
+            else { // 群聊
+                KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+                ctrl.highlightKeyword = self.searchBar.mySearchBar.text;
+                ctrl.locateMessage = msgs.firstObject;
+                TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+                model.groupID = conversation.groupID;
+                ctrl.conversation = model;
+                [self.navigationController pushViewController:ctrl animated:YES];
+
+            }
+            return;
+        }
+
+        NSMutableArray *results = [NSMutableArray array];
+        for (V2TIMMessage *message in msgs) {
+            TUISearchResultCellModel *model = [[TUISearchResultCellModel alloc] init];
+            model.title = message.nickName ?: message.sender;
+            NSString *desc = [TUISearchDataProvider matchedTextForMessage:message withKey:self.searchBar.mySearchBar.text];
+            model.detailsAttributeString = [TUISearchDataProvider attributeStringWithText:desc key:self.searchBar.mySearchBar.text];
+            model.avatarUrl = message.faceURL;
+            model.groupType = conversation.groupType;
+            model.avatarImage = conversation.type == V2TIM_C2C ? DefaultAvatarImage : DefaultGroupAvatarImageByGroupType(conversation.groupType);
+            ;
+            model.context = message;
+            [results addObject:model];
+        }
+        KSSearchResultListController *vc =
+            [[KSSearchResultListController alloc] initWithResults:results
+                                                           keyword:self.searchBar.mySearchBar.text
+                                                            module:module
+                                                             param:@{TUISearchChatHistoryParamKeyConversationId : conversationId}];
+        [self.navigationController pushViewController:vc animated:YES];
+        return;
+    }
+
+    NSDictionary *param = nil;
+
+    if (module == TUISearchResultModuleContact && [cellModel.context isKindOfClass:V2TIMFriendInfo.class]) {
+        V2TIMFriendInfo *friend = cellModel.context;
+        NSString *title = cellModel.title ?: cellModel.titleAttributeString.string;
+        param = @{
+            TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_UserID : friend.userID ?: @"",
+        };
+        KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.userID = friend.userID;
+        ctrl.conversation = model;
+        [self.navigationController pushViewController:ctrl animated:YES];
+    }
+
+    if (module == TUISearchResultModuleGroup && [cellModel.context isKindOfClass:V2TIMGroupInfo.class]) {
+        V2TIMGroupInfo *group = cellModel.context;
+        NSString *title = cellModel.title ?: cellModel.titleAttributeString.string;
+        param = @{
+            TUICore_TUIChatObjectFactory_ChatViewController_Title : title ?: @"",
+            TUICore_TUIChatObjectFactory_ChatViewController_GroupID : group.groupID ?: @"",
+        };
+        KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.groupID = group.groupID;
+        ctrl.conversation = model;
+        [self.navigationController pushViewController:ctrl animated:YES];
+    }
+}
+
+- (void)onSelectMoreModule:(TUISearchResultModule)module results:(NSArray<TUISearchResultCellModel *> *)results {
+    KSSearchResultListController *vc = [[KSSearchResultListController alloc] initWithResults:results
+                                                                                       keyword:self.searchBar.mySearchBar.text
+                                                                                        module:module
+                                                                                         param:nil];
+    [self.navigationController pushViewController:vc animated:YES];
+}
+
+#pragma mark - viewmodel
+- (NSArray *)resultForSection:(NSInteger)section {
+    return [self resultForSection:section module:nil];
+}
+
+- (NSArray *)resultForSection:(NSInteger)section module:(TUISearchResultModule *)module {
+    NSArray *keys = self.dataProvider.resultSet.allKeys;
+    if (section >= keys.count) {
+        return 0;
+    }
+    keys = [keys sortedArrayUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
+      return [obj1 intValue] < [obj2 intValue] ? NSOrderedAscending : NSOrderedDescending;
+    }];
+
+    NSNumber *key = keys[section];
+    if (module) {
+        *module = (TUISearchResultModule)[key integerValue];
+    }
+    return [self.dataProvider.resultSet objectForKey:key];
+}
+
+#pragma mark - TUISearchBarDelegate
+- (void)searchBarDidCancelClicked:(TUISearchBar *)searchBar {
+    [self dismissViewControllerAnimated:NO completion:nil];
+}
+
+- (void)searchBar:(TUISearchBar *)searchBar searchText:(NSString *)key {
+    NSDictionary *parm = nil;
+    if (![NSString isEmptyString:self.groupId]) {
+        NSString *conversationID = [NSString stringWithFormat:@"group_%@", self.groupId];
+
+        parm = @{TUISearchChatHistoryParamKeyConversationId:conversationID};
+        [self.dataProvider searchForKeyword:key forModules:TUISearchResultModuleAll param:parm];
+    }
+    else {
+        [self.dataProvider searchForKeyword:key forModules:TUISearchResultModuleAll param:parm];
+
+    }
+}
+- (UIImage *)imageWithColor:(UIColor *)color {
+    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
+    UIGraphicsBeginImageContext(rect.size);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+
+    CGContextSetFillColorWithColor(context, [color CGColor]);
+    CGContextFillRect(context, rect);
+
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+
+    return image;
+}
+
+@end
+
+

+ 0 - 40
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Model/KSSearchResultModel.h

@@ -1,40 +0,0 @@
-//
-//  KSSearchResultModel.h
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <Foundation/Foundation.h>
-#import <RongIMKit/RongIMKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface KSSearchResultModel : NSObject
-
-//该字段需要单独设置,不会在 modelForMessage 设置
-//@property (nonatomic, assign) RCDSearchType searchType;
-
-@property (nonatomic, assign) RCConversationType conversationType;
-
-@property (nonatomic, copy) NSString *targetId;
-
-@property (nonatomic, copy) NSString *name;
-
-@property (nonatomic, copy) NSString *portraitUri;
-
-@property (nonatomic, copy) NSString *otherInformation;
-
-@property (nonatomic, assign) int count;
-
-@property (nonatomic, copy) NSString *objectName;
-
-@property (nonatomic, assign) long long time;
-
-+ (instancetype)modelForMessage:(RCMessage *)message;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 44
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/Model/KSSearchResultModel.m

@@ -1,44 +0,0 @@
-//
-//  KSSearchResultModel.m
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import "KSSearchResultModel.h"
-
-@implementation KSSearchResultModel
-
-+ (instancetype)modelForMessage:(RCMessage *)message {
-    KSSearchResultModel *messegeModel = [[KSSearchResultModel alloc] init];
-    messegeModel.conversationType = message.conversationType;
-    messegeModel.targetId = message.targetId;
-    messegeModel.time = message.sentTime;
-    messegeModel.objectName = message.objectName;
-    if (message.conversationType == ConversationType_GROUP) {
-        RCUserInfo *user = [[RCIM sharedRCIM] getGroupUserInfoCache:message.senderUserId withGroupId:message.targetId];
-        messegeModel.name = user.name;
-        messegeModel.portraitUri = user.portraitUri;
-    } else if (message.conversationType == ConversationType_PRIVATE) {
-        RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:message.targetId];
-        messegeModel.name = user.name;
-        messegeModel.portraitUri = user.portraitUri;
-    }
-    NSString *string = nil;
-    if ([message.content isKindOfClass:[RCRichContentMessage class]]) {
-        RCRichContentMessage *rich = (RCRichContentMessage *)message.content;
-        string = rich.title;
-    } else if ([message.content isKindOfClass:[RCFileMessage class]]) {
-        RCFileMessage *file = (RCFileMessage *)message.content;
-        string = file.name;
-    } else {
-        string = [RCKitUtility formatMessage:message.content];
-    }
-
-    messegeModel.otherInformation = string;
-    return messegeModel;
-}
-
-
-@end

+ 0 - 17
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSRCSearchBar.h

@@ -1,17 +0,0 @@
-//
-//  KSRCSearchBar.h
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface KSRCSearchBar : UISearchBar
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 36
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSRCSearchBar.m

@@ -1,36 +0,0 @@
-//
-//  KSRCSearchBar.m
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import "KSRCSearchBar.h"
-
-@implementation KSRCSearchBar
-
-- (instancetype)initWithFrame:(CGRect)frame {
-    self = [super initWithFrame:frame];
-    if (self) {
-        self.placeholder = @"搜索";
-        self.keyboardType = UIKeyboardTypeDefault;
-        if (@available(iOS 13.0, *)) {
-            self.searchTextField.backgroundColor = HexRGBAlpha(0xf6f8f9, 0.6f);
-            
-        }
-        //设置顶部搜索栏的背景色
-//        self.barTintColor = THEMECOLOR;
-    }
-    return self;
-}
-
-/*
-// Only override drawRect: if you perform custom drawing.
-// An empty implementation adversely affects performance during animation.
-- (void)drawRect:(CGRect)rect {
-    // Drawing code
-}
-*/
-
-@end

+ 0 - 19
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchRCLabel.h

@@ -1,19 +0,0 @@
-//
-//  KSSearchRCLabel.h
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface KSSearchRCLabel : UILabel
-
-- (void)attributedText:(NSString *)textString byHighlightedText:(NSString *)highlightedText;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 87
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchRCLabel.m

@@ -1,87 +0,0 @@
-//
-//  KSSearchRCLabel.m
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import "KSSearchRCLabel.h"
-#import "KSUtilities.h"
-
-@implementation KSSearchRCLabel
-
-- (void)attributedText:(NSString *)textString byHighlightedText:(NSString *)highlightedText {
-    NSRange range = [self getRange:highlightedText inText:textString];
-    NSString *string = [self isBeyond:textString range:range];
-    if (![string isEqualToString:textString]) {
-        range = [self getRange:highlightedText inText:string];
-    }
-    
-    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
-    
-    [attributedString addAttribute:NSForegroundColorAttributeName value:HexRGB(0x2dc7aa) range:range];
-    self.attributedText = attributedString.copy;
-}
-
-- (NSRange)getRange:(NSString *)searchText inText:(NSString *)text {
-    NSRange range = NSMakeRange(0, 0);
-    NSString *twoStr = [[searchText stringByReplacingOccurrencesOfString:@" " withString:@""] lowercaseString];
-    if ([[text lowercaseString] containsString:[searchText lowercaseString]]) {
-        range = [[text lowercaseString] rangeOfString:[searchText lowercaseString]];
-    } else if ([[text lowercaseString] containsString:twoStr]) {
-        range = [[text lowercaseString] rangeOfString:twoStr];
-    } else if ([[[KSUtilities hanZiToPinYinWithString:text] lowercaseString] containsString:twoStr]) {
-        NSString *str = [KSUtilities hanZiToPinYinWithString:text];
-        range = [str rangeOfString:[searchText uppercaseString]];
-    }
-    return range;
-}
-
-- (NSString *)isBeyond:(NSString *)text range:(NSRange)range {
-    NSString *string = nil;
-    if (range.location + range.length < 16) {
-        self.lineBreakMode = NSLineBreakByTruncatingTail;
-        string = text;
-    } else if (text.length - range.location < 16) {
-        self.lineBreakMode = NSLineBreakByTruncatingHead;
-        string = text;
-    } else {
-        self.lineBreakMode = NSLineBreakByTruncatingTail;
-        if (range.length > 16) {
-            string = [self
-                      relaceEnterBySpace:[NSString
-                                          stringWithFormat:@"...%@", [text substringWithRange:NSMakeRange(range.location,
-                                                                                                          range.length)]]];
-        } else {
-            string = [self
-                      relaceEnterBySpace:[NSString
-                                          stringWithFormat:@"...%@",
-                                          [text substringWithRange:NSMakeRange(
-                                                                               range.location -
-                                                                               (16 - range.length) / 2,
-                                                                               text.length -
-                                                                               (range.location -
-                                                                                (16 - range.length) / 2))]]];
-        }
-    }
-    return string;
-}
-
-- (NSString *)relaceEnterBySpace:(NSString *)originalString {
-    NSString *string = [originalString stringByReplacingOccurrencesOfString:@"\r\n" withString:@" "];
-    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
-    string = [string stringByReplacingOccurrencesOfString:@"\r" withString:@" "];
-    return string;
-}
-
-
-/*
- // Only override drawRect: if you perform custom drawing.
- // An empty implementation adversely affects performance during animation.
- - (void)drawRect:(CGRect)rect {
- // Drawing code
- }
- */
-
-@end

+ 0 - 30
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchResultViewCell.h

@@ -1,30 +0,0 @@
-//
-//  KSSearchResultViewCell.h
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@class KSSearchResultModel;
-@class KSSearchRCLabel;
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface KSSearchResultViewCell : UITableViewCell
-
-@property (nonatomic, strong) UIImageView *headerView;
-
-@property (nonatomic, strong) KSSearchRCLabel *nameLabel;
-
-@property (nonatomic, strong) KSSearchRCLabel *additionalLabel;
-
-@property (nonatomic, strong) NSString *searchString;
-
-- (void)setDataModel:(KSSearchResultModel *)model;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 153
KulexiuForStudent/KulexiuForStudent/Module/Chat/Search/View/KSSearchResultViewCell.m

@@ -1,153 +0,0 @@
-//
-//  KSSearchResultViewCell.m
-//  TeacherDaya
-//
-//  Created by Kyle on 2020/10/27.
-//  Copyright © 2020 DayaMusic. All rights reserved.
-//
-
-#import "KSSearchResultViewCell.h"
-#import "KSSearchResultModel.h"
-#import "KSSearchRCLabel.h"
-
-@interface KSSearchResultViewCell ()
-
-@property (nonatomic, strong) UILabel *otherLabel;
-
-@property (nonatomic, strong) UILabel *timeLabel;
-
-@end
-
-@implementation KSSearchResultViewCell
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
-    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
-    if (self) {
-        self.backgroundColor = HexRGBAlpha(0xffffff, 0.4);
-        self.selectionStyle = UITableViewCellSelectionStyleNone;
-        [self loadView];
-    }
-    return self;
-}
-
-- (void)setDataModel:(KSSearchResultModel *)model {
-    float namelLabelWidth = kScreenWidth - 20 - 48 - 9.5;
-    if (model.time) {
-        self.timeLabel.hidden = NO;
-        namelLabelWidth -= 100;
-    } else {
-        self.timeLabel.hidden = YES;
-    }
-    if (!(model.otherInformation.length > 0) || !(model.name.length > 0)) {
-        self.nameLabel.frame =
-            CGRectMake(CGRectGetMaxX(self.headerView.frame) + 9.5, (65 - 17) / 2, namelLabelWidth, 17);
-        self.additionalLabel.hidden = YES;
-        self.otherLabel.hidden = YES;
-        NSString *str = nil;
-        if (model.otherInformation.length > 0) {
-            str = model.otherInformation;
-        } else {
-            str = model.name;
-        }
-        [self.nameLabel attributedText:str byHighlightedText:self.searchString];
-    } else {
-        self.nameLabel.frame = CGRectMake(CGRectGetMaxX(self.headerView.frame) + 9.5,
-                                          CGRectGetMinY(self.headerView.frame) + 3, namelLabelWidth, 17);
-        self.additionalLabel.hidden = NO;
-        self.otherLabel.hidden = NO;
-        CGFloat height = CGRectGetMaxY(self.headerView.frame) - 20;
-        CGFloat width = CGRectGetMaxX(self.headerView.frame) + 9.5;
-        CGFloat additionalLabelWidth = kScreenWidth - 20 - 48 - 9.5;
-        
-        if ([model.objectName isEqualToString:@"RC:FileMsg"]) {
-            self.otherLabel.text = @"[文件]";
-        } else if ([model.objectName isEqualToString:@"RC:ImgTextMsg"]) {
-            self.otherLabel.text = @"[链接]";
-        } else {
-            self.otherLabel.text = @"";
-            self.otherLabel.frame = CGRectZero;
-            CGRect rect = self.additionalLabel.frame;
-            rect.origin.x = width;
-            rect.size.width = additionalLabelWidth;
-            self.additionalLabel.frame = rect;
-        }
-        self.otherLabel.frame = CGRectMake(width, height, 40, 16);
-        [self.otherLabel sizeToFit];
-        self.additionalLabel.frame = CGRectMake(width + self.otherLabel.frame.size.width, height,
-                                                additionalLabelWidth - CGRectGetWidth(self.otherLabel.frame), 16);
-        if (model.time) {
-            self.timeLabel.text = [RCKitUtility convertConversationTime:model.time / 1000];
-        }
-        self.nameLabel.text = model.name;
-        if (model.count > 1) {
-            self.additionalLabel.text = model.otherInformation;
-        } else {
-            [self.additionalLabel attributedText:model.otherInformation byHighlightedText:self.searchString];
-        }
-        
-    }
-
-    if (!(model.portraitUri.length > 0)) {
-        if (model.conversationType == ConversationType_GROUP) {
-            self.headerView.image = [self imageNamed:@"default_group_portrait" ofBundle:@"RongCloud.bundle"];
-        }
-        else {
-            self.headerView.image = [self imageNamed:@"default_portrait_msg" ofBundle:@"RongCloud.bundle"];
-        }
-        
-    } else {
-        if (model.conversationType == ConversationType_GROUP) {
-            [self.headerView
-                sd_setImageWithURL:[NSURL URLWithString:[model.portraitUri getUrlEndcodeString]]
-                  placeholderImage:[self imageNamed:@"default_group_portrait" ofBundle:@"RongCloud.bundle"]];
-        }
-        else {
-            [self.headerView
-                sd_setImageWithURL:[NSURL URLWithString:[model.portraitUri getUrlEndcodeString]]
-                  placeholderImage:[self imageNamed:@"default_portrait_msg" ofBundle:@"RongCloud.bundle"]];
-        }
-        
-    }
-}
-
-- (void)loadView {
-    self.headerView = [[UIImageView alloc] initWithFrame:CGRectMake(10, (65 - 48) / 2, 48, 48)];
-    self.headerView.layer.cornerRadius = 24;
-    self.headerView.layer.masksToBounds = YES;
-    [self.contentView addSubview:self.headerView];
-
-    self.nameLabel = [[KSSearchRCLabel alloc] initWithFrame:CGRectZero];
-    self.nameLabel.font = [UIFont systemFontOfSize:15.f];
-    self.nameLabel.textColor = HexRGB(0x000000);
-    [self.contentView addSubview:self.nameLabel];
-
-    self.timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(kScreen_Width - 100 - 10, (65 - 48) / 2, 100, 17)];
-    self.timeLabel.textColor = HexRGB(0x999999);
-    self.timeLabel.font = [UIFont systemFontOfSize:15.f];
-    self.timeLabel.textAlignment = NSTextAlignmentRight;
-    [self.contentView addSubview:self.timeLabel];
-
-    self.otherLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    self.otherLabel.textColor = HexRGB(0x999999);
-    self.otherLabel.font = [UIFont systemFontOfSize:14.f];
-
-    self.additionalLabel = [[KSSearchRCLabel alloc] initWithFrame:CGRectZero];
-    self.additionalLabel.font = [UIFont systemFontOfSize:14.f];
-    self.additionalLabel.textColor = HexRGB(0x999999);
-    
-    [self.contentView addSubview:self.otherLabel];
-    [self.contentView addSubview:self.additionalLabel];
-}
-
-- (UIImage *)imageNamed:(NSString *)name ofBundle:(NSString *)bundleName {
-    UIImage *image = nil;
-    NSString *image_name = [NSString stringWithFormat:@"%@.png", name];
-    NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
-    NSString *bundlePath = [resourcePath stringByAppendingPathComponent:bundleName];
-    NSString *image_path = [bundlePath stringByAppendingPathComponent:image_name];
-
-    image = [[UIImage alloc] initWithContentsOfFile:image_path];
-    return image;
-}
-
-@end

+ 41 - 31
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m

@@ -9,6 +9,7 @@
 #import "SCIndexView.h"
 #import "UITableView+SCIndexView.h"
 #import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
 #import "GroupListModel.h"
 #import "GroupListViewCell.h"
 #import "ContractListCell.h"
@@ -307,40 +308,49 @@
 
 - (void)sendMessageWithTargetId:(NSString *)targetId isGroup:(BOOL)isGroup {
     
-    RCImageMessage *imgMsg = [RCImageMessage messageWithImage:self.shareImage];
-    imgMsg.full = YES;
-    RCConversationType type = isGroup ? ConversationType_GROUP : ConversationType_PRIVATE;
-    [[RCIMClient sharedRCIMClient] sendMediaMessage:type targetId:targetId content:imgMsg pushContent:nil pushData:nil progress:^(int progress, long messageId) {
-        
-    } success:^(long messageId) {
-        dispatch_main_async_safe(^{
-            if (self.callback) {
-                self.callback(YES, @"发送成功");
-            }
-        });
-        
-    } error:^(RCErrorCode errorCode, long messageId) {
-        dispatch_main_async_safe(^{
-            if (self.callback) {
-                self.callback(NO, @"发送失败");
-            }
-        });
-        
-    } cancel:^(long messageId) {
-        dispatch_main_async_safe(^{
-            if (self.callback) {
-                self.callback(NO,@"已取消");
-            }
-        });
-    }];
+//    RCImageMessage *imgMsg = [RCImageMessage messageWithImage:self.shareImage];
+//    imgMsg.full = YES;
+//    RCConversationType type = isGroup ? ConversationType_GROUP : ConversationType_PRIVATE;
+//    [[RCIMClient sharedRCIMClient] sendMediaMessage:type targetId:targetId content:imgMsg pushContent:nil pushData:nil progress:^(int progress, long messageId) {
+//        
+//    } success:^(long messageId) {
+//        dispatch_main_async_safe(^{
+//            if (self.callback) {
+//                self.callback(YES, @"发送成功");
+//            }
+//        });
+//        
+//    } error:^(RCErrorCode errorCode, long messageId) {
+//        dispatch_main_async_safe(^{
+//            if (self.callback) {
+//                self.callback(NO, @"发送失败");
+//            }
+//        });
+//        
+//    } cancel:^(long messageId) {
+//        dispatch_main_async_safe(^{
+//            if (self.callback) {
+//                self.callback(NO,@"已取消");
+//            }
+//        });
+//    }];
 }
 
 - (void)chatConversationWithTargetId:(NSString *)targetId targetName:(NSString *)targetName isGroup:(BOOL)isGroup {
-    KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-    conversationVC.targetId = targetId;
-    conversationVC.conversationType = isGroup ? ConversationType_GROUP : ConversationType_PRIVATE;
-    conversationVC.title = targetName;
-    [self.naviController pushViewController:conversationVC animated:YES];
+    if (isGroup) {
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.groupID = targetId;
+        KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+        ctrl.conversation = model;
+        [self.naviController pushViewController:ctrl animated:YES];
+    }
+    else {
+        TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+        model.userID = targetId;
+        KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+        ctrl.conversation = model;
+        [self.naviController pushViewController:ctrl animated:YES];
+    }
 }
 
 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {

+ 6 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatListSearchView.h

@@ -13,8 +13,14 @@ NS_ASSUME_NONNULL_BEGIN
 
 @interface KSChatListSearchView : UIView
 
+@property (nonatomic, assign) BOOL isClickSearch;
+
+@property (weak, nonatomic) IBOutlet UITextField *searchField;
+
 + (instancetype)shareInstance;
 
+- (void)configText:(NSString *)text;
+
 - (void)topSearchCallback:(ChatListSearch)callback;
 
 @end

+ 11 - 5
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatListSearchView.m

@@ -9,7 +9,6 @@
 
 @interface KSChatListSearchView ()<UITextFieldDelegate>
 
-@property (weak, nonatomic) IBOutlet UITextField *searchField;
 
 @property (nonatomic, copy) ChatListSearch callback;
 
@@ -20,7 +19,10 @@
 - (void)awakeFromNib {
     [super awakeFromNib];
     self.searchField.delegate = self;
-    self.searchField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"查找聊天记录" attributes:@{NSForegroundColorAttributeName:HexRGB(0x999999)}];
+}
+
+- (void)configText:(NSString *)text {
+    self.searchField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:text attributes:@{NSForegroundColorAttributeName:HexRGB(0x999999)}];
 }
 
 
@@ -36,11 +38,15 @@
 }
 
 - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
-    if (self.callback) {
-        self.callback();
+    if (self.isClickSearch) {
+        if (self.callback) {
+            self.callback();
+        }
+        return NO;
     }
-    return NO;
+    return YES;
 }
+
 - (IBAction)searchButtonClick:(id)sender {
     if (self.callback) {
         self.callback();

+ 0 - 1
KulexiuForStudent/KulexiuForStudent/Module/Course/AccompanyCourse/Controller/AccompanyDetailViewController.m

@@ -16,7 +16,6 @@
 #import "HomeworkDetailModel.h"
 #import "EvaluateDetailModel.h"
 #import "AccompanyAlertView.h"
-#import "KSChatConversationViewController.h"
 #import "WMPlayer.h"
 #import "RecordCheckManager.h"
 #import "KSPremissionAlert.h"

+ 6 - 5
KulexiuForStudent/KulexiuForStudent/Module/Course/Controller/CourseViewController.m

@@ -12,6 +12,7 @@
 #import "KSFullDatePicker.h"
 #import "TableCourseModel.h"
 #import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
 #import "KSEnterLiveroomManager.h"
 #import "KSBaseWKWebViewController.h"
 #import "AccompanyCourseCell.h"
@@ -507,11 +508,11 @@
         [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
-    KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-    conversationVC.targetId = targetId;
-    conversationVC.title = targetName;
-    conversationVC.conversationType = isGroup ? ConversationType_GROUP : ConversationType_PRIVATE;
-    [self.navigationController pushViewController:conversationVC animated:YES];
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.groupID = targetId;
+    KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+    ctrl.conversation = model;
+    [self.navigationController pushViewController:ctrl animated:YES];
 }
 
 - (void)liveCourseDetail:(NSString *)courseId courseGroupId:(NSString *)courseGroupId {

+ 5 - 3
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.m

@@ -14,6 +14,7 @@
 #import "EvaluateDetailModel.h"
 #import "AccompanyAlertView.h"
 #import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
 #import "WMPlayer.h"
 #import "RecordCheckManager.h"
 #import "KSPremissionAlert.h"
@@ -227,9 +228,10 @@
         [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
-    KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
-    ctrl.targetId = targetId;
-    ctrl.conversationType = ConversationType_GROUP;
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.groupID = targetId;
+    KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+    ctrl.conversation = model;
     [self.navigationController pushViewController:ctrl animated:YES];
 }
 

+ 0 - 4
KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m

@@ -504,10 +504,6 @@
     [KSNetworkingManager queryStudentInfoRequest:KS_GET success:^(NSDictionary * _Nonnull dic) {
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
             self.mineInfo = [[StudentInfoModel alloc] initWithDictionary:[dic ks_dictionaryValueForKey:@"data"]];
-            NSString *rongToken = UserDefault(RongTokenKey);
-            if ([NSString isEmptyString:rongToken]) {
-                [USER_MANAGER queryUserInfoConnectRongCloud:YES];
-            }
             [self refreshSource:checkSubject];
         }
         else {

+ 12 - 12
KulexiuForStudent/KulexiuForStudent/Module/Live/Controller/LiveVideoRoomViewController.m

@@ -530,8 +530,8 @@ static int clickPraiseBtnTimes  = 0;
             [seatArray addObject:user.userId];
         }
     }
-    if (self.micStatus == MICSTATUS_CONNECTING && ![seatArray containsObject:UserDefault(RongCloudID)]) {
-        [seatArray addObject:UserDefault(RongCloudID)];
+    if (self.micStatus == MICSTATUS_CONNECTING && ![seatArray containsObject:UserDefault(IM_USERID)]) {
+        [seatArray addObject:UserDefault(IM_USERID)];
     }
     
     if (seatArray.count) {
@@ -1209,7 +1209,7 @@ static int clickPraiseBtnTimes  = 0;
     SEATRESPONSE type = isApprove ? SEATRESPONSE_AUDIENCEAPPROVE : SEATRESPONSE_AUDIENCEREJECT;
     KSLiveChatroomSeatResponse *responseMessage = [[KSLiveChatroomSeatResponse alloc] init];
     responseMessage.type = type;
-    responseMessage.audienceId = UserDefault(RongCloudID);
+    responseMessage.audienceId = UserDefault(IM_USERID);
     responseMessage.audienceName = UserDefault(NicknameKey);
     MJWeakSelf;
     [self sendMessage:responseMessage displayMessage:YES callback:^(BOOL success) {
@@ -1349,7 +1349,7 @@ static int clickPraiseBtnTimes  = 0;
                 }
                 else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomWelcome class]]) {
                     //  过滤自己发送的欢迎消息
-                    if ([rcMessage.senderUserId isEqualToString:UserDefault(RongCloudID)]) {
+                    if ([rcMessage.senderUserId isEqualToString:UserDefault(IM_USERID)]) {
                         return;
                     }
 //                    if ([rcMessage.senderUserId isEqual:self.createrId]) { // 如果是老师 重置连麦申请状态
@@ -1371,7 +1371,7 @@ static int clickPraiseBtnTimes  = 0;
                 }
                 else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomKickOut class]]) {
                     KSLiveChatroomKickOut *kickMessage = (KSLiveChatroomKickOut *)rcMessage.content;
-                    NSString *currentUserId = UserDefault(RongCloudID);
+                    NSString *currentUserId = UserDefault(IM_USERID);
                     if ([kickMessage.targetId isEqualToString:currentUserId]) {
                         __blockSelf.micStatus = MICSTATUS_NOMAL;
                         [__blockSelf kickOutLiveRoom];
@@ -1408,7 +1408,7 @@ static int clickPraiseBtnTimes  = 0;
                 else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatApply class]]) {
                     KSLiveChatroomSeatApply *seatApplyMessage = (KSLiveChatroomSeatApply *)rcMessage.content;
                     // 只处理和自己相关的消息
-                    if (![seatApplyMessage.audienceId isEqualToString:UserDefault(RongCloudID)]) {
+                    if (![seatApplyMessage.audienceId isEqualToString:UserDefault(IM_USERID)]) {
                         // 刷新麦序
                         return;
                     }
@@ -1431,7 +1431,7 @@ static int clickPraiseBtnTimes  = 0;
                 // 连麦回复消息(暂不处理)
                 else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatResponse class]]) {
                     KSLiveChatroomSeatResponse *seatResponseMessage = (KSLiveChatroomSeatResponse *)rcMessage.content;
-                    if (![seatResponseMessage.audienceId isEqualToString:UserDefault(RongCloudID)]) { // 只处理和自己相关的消息
+                    if (![seatResponseMessage.audienceId isEqualToString:UserDefault(IM_USERID)]) { // 只处理和自己相关的消息
                         return;
                     }
                     if (seatResponseMessage.type == SEATRESPONSE_TEACHERAPPROVE && __blockSelf.micStatus == MICSTATUS_WAITING) { //
@@ -1486,14 +1486,14 @@ static int clickPraiseBtnTimes  = 0;
                 }
                 else if ([rcMessage.content isMemberOfClass:[KSLiveBlockUser class]]) { // 黑名单
                     KSLiveBlockUser *blockMessage = (KSLiveBlockUser *)rcMessage.content;
-                    if ([blockMessage.userId isEqualToString:UserDefault(RongCloudID)]) {
+                    if ([blockMessage.userId isEqualToString:UserDefault(IM_USERID)]) {
                         __blockSelf.blacklistFlag = YES;
                         [__blockSelf resetConnectionStatus];
                     }
                 }
                 else if ([rcMessage.content isMemberOfClass:[KSLiveUnBlockUser class]]) {
                     KSLiveUnBlockUser *unBlockMessage = (KSLiveUnBlockUser *)rcMessage.content;
-                    if ([unBlockMessage.userId isEqualToString:UserDefault(RongCloudID)]) {
+                    if ([unBlockMessage.userId isEqualToString:UserDefault(IM_USERID)]) {
                         __blockSelf.blacklistFlag = NO;
                     }
                 }
@@ -1574,7 +1574,7 @@ static int clickPraiseBtnTimes  = 0;
             RCMessage *message = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:__weakself.roomId direction:MessageDirection_SEND content:messageContent];
             message.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
             
-            message.senderUserId = UserDefault(RongCloudID);
+            message.senderUserId = UserDefault(IM_USERID);
             if (displayMessage) {
                 [__weakself appendAndDisplayMessage:message];
             }
@@ -1722,7 +1722,7 @@ static int clickPraiseBtnTimes  = 0;
     SEATHANDLE type = isApply ? SEATHANDLE_APPLY : SEATHANDLE_CANCELAPPLY;
     KSLiveChatroomSeatApply *applyMessage = [[KSLiveChatroomSeatApply alloc] init];
     applyMessage.type = type;
-    applyMessage.audienceId = UserDefault(RongCloudID);
+    applyMessage.audienceId = UserDefault(IM_USERID);
     applyMessage.audienceName = UserDefault(NicknameKey);
     applyMessage.audienceAvatar = UserDefault(AvatarUrlKey);
     applyMessage.teacherId = self.createrId;
@@ -2251,7 +2251,7 @@ static int clickPraiseBtnTimes  = 0;
 
 - (void)sendDownSeatMessage {
     KSLiveChatroomDownSeat *downSeatMessage = [[KSLiveChatroomDownSeat alloc] init];
-    downSeatMessage.audienceId = UserDefault(RongCloudID);
+    downSeatMessage.audienceId = UserDefault(IM_USERID);
     downSeatMessage.audienceName = UserDefault(NicknameKey);
     MJWeakSelf;
     [self sendMessage:downSeatMessage displayMessage:NO callback:^(BOOL success) {

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Module/Live/View/SeatContentView.m

@@ -37,7 +37,7 @@
 - (void)setupUI {
     self.backgroundColor = [UIColor clearColor];
     
-    if ([self.userId isEqualToString:UserDefault(RongCloudID)]) { // 自己
+    if ([self.userId isEqualToString:UserDefault(UIDKey)]) { // 自己
         [self.userAvatar sd_setImageWithURL:[NSURL URLWithString:[UserDefault(AvatarUrlKey) getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:USERDEFAULT_LOGO]];
         self.userAvatar.layer.borderColor = HexRGB(0xf37f17).CGColor;
         self.userAvatar.layer.borderWidth = 1.0f;

+ 0 - 23
KulexiuForStudent/KulexiuForStudent/Module/Login/Controller/SubjectChooseViewController.h

@@ -1,23 +0,0 @@
-//
-//  SubjectChooseViewController.h
-//  KulexiuForStudent
-//
-//  Created by 王智 on 2022/4/5.
-//
-
-#import "KSBaseViewController.h"
-
-
-typedef void(^SubjectChooseCallback)(void);
-NS_ASSUME_NONNULL_BEGIN
-
-/// 声部选择
-@interface SubjectChooseViewController : KSBaseViewController
-
-@property (nonatomic, assign) BOOL isModalPresent;
-
-- (void)chooseSubjectCallback:(SubjectChooseCallback)callback;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 294
KulexiuForStudent/KulexiuForStudent/Module/Login/Controller/SubjectChooseViewController.m

@@ -1,294 +0,0 @@
-//
-//  SubjectChooseViewController.m
-//  KulexiuForStudent
-//
-//  Created by 王智 on 2022/4/5.
-//
-
-#import "SubjectChooseViewController.h"
-#import "SubjectChooseBodyView.h"
-#import "DZNSegmentedControl.h"
-#import <ZKCycleScrollView.h>
-#import <CHIPageControl/CHIPageControl-Swift.h>
-#import "SubjectImageCell.h"
-#import "InstrumentMessageModel.h"
-#import "KSSegmentControl.h"
-
-@interface SubjectChooseViewController ()<ZKCycleScrollViewDelegate,ZKCycleScrollViewDataSource,KSSegmentControlDelegate>
-
-@property (nonatomic, strong) ZKCycleScrollView *imageCycle;
-
-@property (nonatomic, strong) CHIPageControlJaloro *pageControl;
-
-@property (nonatomic, strong) SubjectChooseBodyView *bodyView;
-
-@property (nonatomic, strong) NSMutableArray *imageArray;
-
-@property (nonatomic, strong) NSMutableArray *parentArray;
-
-@property (nonatomic, strong) NSMutableArray *instrumentArray;
-
-@property (nonatomic, assign) NSInteger chooseIndex;
-
-@property (nonatomic, strong) KSSegmentControl *segCtrl;
-
-@property (nonatomic, strong) InstrumentMessageModel *chooseInstrument;
-
-@property (nonatomic, copy) SubjectChooseCallback callback;
-
-@end
-
-@implementation SubjectChooseViewController
-
-- (void)chooseSubjectCallback:(SubjectChooseCallback)callback {
-    if (callback) {
-        self.callback = callback;
-    }
-}
-
-
-- (void)viewDidLoad {
-    [super viewDidLoad];
-    // Do any additional setup after loading the view.
-    [self allocTitle:@"乐器选择"];
-    [self configUI];
-    [self requestSubjectMessage];
-}
-
-
-- (void)requestSubjectMessage {
-    [self showhud];
-    [KSNetworkingManager studentQuerySubject:KS_GET success:^(NSDictionary * _Nonnull dic) {
-        [self removehub];
-        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
-            [self evaluateSource:[dic ks_arrayValueForKey:@"data"]];
-        }
-        else {
-            [self MBPShow:MESSAGEKEY];
-        }
-    } faliure:^(NSError * _Nonnull error) {
-        [self removehub];
-    }];
-}
-
-- (void)evaluateSource:(NSArray *)sourceArray {
-    @autoreleasepool {
-        NSMutableArray *valueArray = [sourceArray mutableCopy];
-        
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-            NSMutableArray *parentNodeArray = [NSMutableArray array];
-            NSMutableArray *instrumentArray = [NSMutableArray array];
-            for (NSInteger i = 0; i < valueArray.count; i++) {
-                NSMutableDictionary *parentNodeDic = [NSMutableDictionary dictionary];
-                NSDictionary *parm = valueArray[i];
-                [parentNodeDic setValue:[parm ks_stringValueForKey:@"id"] forKey:@"subjectId"];
-                [parentNodeDic setValue:[parm ks_stringValueForKey:@"name"] forKey:@"subjectName"];
-                
-                NSArray *subjects = [parm ks_arrayValueForKey:@"subjects"];
-                if (subjects.count > 0) { // 存在子节点,才添加父节点
-                    // 添加父节点分类
-                    [parentNodeArray addObject:parentNodeDic];
-                    
-                    NSMutableArray *subjectModelArray = [NSMutableArray array];
-                    for (NSDictionary *dic in subjects) {
-                        InstrumentMessageModel *model = [[InstrumentMessageModel alloc] initWithDictionary:dic];
-                        [subjectModelArray addObject:model];
-                    }
-                    [instrumentArray addObject:subjectModelArray];
-                }
-            }
-            self.parentArray = [NSMutableArray arrayWithArray:parentNodeArray];
-            self.instrumentArray = [NSMutableArray arrayWithArray:instrumentArray];
-            dispatch_main_async_safe(^{
-                [self resetChooseStatus];
-                [self refreshView];
-            });
-        });
-    };
-}
-
-- (void)resetChooseStatus {
-    self.chooseIndex = 0;
-    NSMutableArray *sourceArray = self.instrumentArray[self.chooseIndex];
-    self.imageArray = sourceArray;
-    self.chooseInstrument = self.imageArray[self.chooseIndex];
-}
-// 刷新页面
-- (void)refreshView {
-    if (self.parentArray.count  <= 0) {
-        return;
-    }
-    NSMutableArray *titleArray = [NSMutableArray array];
-    for (NSDictionary *parm in self.parentArray) {
-        [titleArray addObject:[parm ks_stringValueForKey:@"subjectName"]];
-    }
-    [self.segCtrl configWithArray:titleArray];
-    NSMutableArray *sourceArray = self.instrumentArray[self.chooseIndex];
-    self.imageArray = sourceArray;
-    [self.imageCycle reloadData];
-    [self.imageCycle scrollToItemAtIndex:0 animated:YES];
-    [self refreshBottomView:0];
-}
-
-- (void)refreshBottomView:(NSInteger)index {
-    InstrumentMessageModel *model = self.imageArray[index];
-    self.bodyView.subjectName.text = [NSString returnNoNullStringWithString:model.name];
-    self.bodyView.subjectDesc.text = [NSString returnNoNullStringWithString:model.desc];
-    [self.bodyView.sureButton setTitle:[NSString stringWithFormat:@"开启%@学习之路",model.name] forState:UIControlStateNormal];
-    self.chooseInstrument = self.imageArray[index];
-}
-
-- (void)configUI {
-    [self.view addSubview:self.segCtrl];
-    [self.segCtrl mas_makeConstraints:^(MASConstraintMaker *make) {
-        make.left.right.top.mas_equalTo(self.view);
-        make.height.mas_equalTo(60);
-    }];
-    
-    [self.view addSubview:self.bodyView];
-    [self.bodyView mas_makeConstraints:^(MASConstraintMaker *make) {
-        make.left.right.mas_equalTo(self.view);
-        make.top.mas_equalTo(self.segCtrl.mas_bottom);
-        make.bottom.mas_equalTo(self.view.mas_bottom);
-    }];
-    [self.bodyView.chooseView addSubview:self.imageCycle];
-    [self.imageCycle mas_makeConstraints:^(MASConstraintMaker *make) {
-        make.left.right.top.bottom.mas_equalTo(self.bodyView.chooseView);
-    }];
-    self.imageCycle.itemSize = CGSizeMake(kScreenWidth - 132, 300);
-
-    [self.bodyView addSubview:self.pageControl];
-    [self.pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
-        make.left.right.mas_equalTo(self.bodyView);
-        make.top.mas_equalTo(self.bodyView.chooseView.mas_bottom).offset(10);
-        make.height.mas_equalTo(15.0f);
-    }];
-    
-}
-
-#pragma mark ----- segCtrl delegate
-- (void)didSelectIndex:(NSInteger)chooseIndex {
-    self.chooseIndex = chooseIndex;
-    [self refreshView];
-}
-
-#pragma mark -- ZKCycleScrollView DataSource
-- (NSInteger)numberOfItemsInCycleScrollView:(ZKCycleScrollView *)cycleScrollView {
-    return self.imageArray.count;
-}
-
-- (__kindof UICollectionViewCell *)cycleScrollView:(ZKCycleScrollView *)cycleScrollView cellForItemAtIndex:(NSInteger)index {
-    SubjectImageCell *cell = [cycleScrollView dequeueReusableCellWithReuseIdentifier:@"SubjectImageCell" forIndex:index];
-    InstrumentMessageModel *model = self.imageArray[index];
-    [cell.instrumentImage sd_setImageWithURL:[NSURL URLWithString:[model.img getUrlEndcodeString]]];
-    return cell;
-}
-
-#pragma mark -- ZKCycleScrollView Delegate
-- (void)cycleScrollView:(ZKCycleScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index {
-    // 对应当前的数据源刷新数据
-    NSLog(@"index = %zd",index);
-}
-
-- (void)cycleScrollViewDidScroll:(ZKCycleScrollView *)cycleScrollView progress:(CGFloat)progress {
-    // 对应当前的数据源刷新数据
-    
-    _pageControl.progress = progress;
-    NSLog(@"progress = %f", progress);
-}
-
-- (void)cycleScrollView:(ZKCycleScrollView *)cycleScrollView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
-    
-    [self refreshBottomView:toIndex];
-    
-}
-
-#pragma mark ---- lazying
-- (ZKCycleScrollView *)imageCycle {
-    if (!_imageCycle) {
-        _imageCycle = [[ZKCycleScrollView alloc] initWithFrame:CGRectZero shouldInfiniteLoop:NO];
-        _imageCycle.delegate = self;
-        _imageCycle.dataSource = self;
-        _imageCycle.hidesPageControl = YES;
-        _imageCycle.autoScroll = NO;
-        _imageCycle.itemSpacing = 6.0f;
-        _imageCycle.itemZoomScale = 0.85;
-        [_imageCycle registerCellNib:[UINib nibWithNibName:@"SubjectImageCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:@"SubjectImageCell"];
-    }
-    return _imageCycle;
-}
-
-- (CHIPageControlJaloro *)pageControl {
-    if (!_pageControl) {
-        _pageControl = [[CHIPageControlJaloro alloc] initWithFrame:CGRectZero];
-        _pageControl.radius = 3;
-        _pageControl.padding = 8;
-        _pageControl.inactiveTransparency = 0.8f;// 未命中点的不透明度
-        _pageControl.tintColor = HexRGB(0xd8d8d8);
-        _pageControl.currentPageTintColor = THEMECOLOR;
-        _pageControl.numberOfPages = self.imageArray.count;
-        _pageControl.transform = CGAffineTransformMakeScale(0.5, 0.5);
-    }
-    return _pageControl;
-}
-
-- (KSSegmentControl *)segCtrl {
-    if (!_segCtrl) {
-        _segCtrl = [[KSSegmentControl alloc] init];
-        _segCtrl.delegate = self;
-    }
-    return _segCtrl;
-}
-
-- (SubjectChooseBodyView *)bodyView {
-    if (!_bodyView) {
-        _bodyView = [SubjectChooseBodyView shareInstance];
-        MJWeakSelf;
-        [_bodyView chooseSubjectCallback:^{
-            [weakSelf sureChooseSubject];
-        }];
-    }
-    return _bodyView;
-}
-
-
-- (void)sureChooseSubject {
-    NSString *subjectId = self.chooseInstrument.internalBaseClassIdentifier;
-    [self showhud];
-    [KSNetworkingManager studentSetSubject:KS_GET subjectIds:subjectId success:^(NSDictionary * _Nonnull dic) {
-        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
-            MJWeakSelf;
-            [self KSShowMsg:@"设置成功" promptCompletion:^{
-                if (weakSelf.callback) {
-                    weakSelf.callback();
-                }
-                [weakSelf backAction];
-            }];
-        }
-        else {
-            [self MBPShow:MESSAGEKEY];
-        }
-    } faliure:^(NSError * _Nonnull error) {
-        [self removehub];
-    }];
-}
-
-- (void)backAction {
-    if (self.isModalPresent) {
-        [self.navigationController dismissViewControllerAnimated:YES completion:nil];
-    }
-    else {
-        [self.navigationController popViewControllerAnimated:YES];
-    }
-}
-/*
-#pragma mark - Navigation
-
-// In a storyboard-based application, you will often want to do a little preparation before navigation
-- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
-    // Get the new view controller using [segue destinationViewController].
-    // Pass the selected object to the new view controller.
-}
-*/
-
-@end

+ 6 - 5
KulexiuForStudent/KulexiuForStudent/Module/Login/Guide/Controller/GuideViewController.m

@@ -111,11 +111,12 @@
 }
 - (void)toHomeView {
     [KSNetworkingManager configRequestHeader];
-    [USER_MANAGER queryUserInfoConnectRongCloud:YES];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    [appDelegate initTableBar];
-    UITabBarController *tabBarController = appDelegate.tabBarController;
-    [tabBarController setSelectedIndex:0];
+    [USER_MANAGER queryUserInfoConnectionIMCallback:^(UserInfo * _Nonnull userInfo) {
+        AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+        [appDelegate initTableBar];
+        UITabBarController *tabBarController = appDelegate.tabBarController;
+        [tabBarController setSelectedIndex:0];
+    }];
 }
 
 #pragma mark --- scroll view delegate

+ 3 - 2
KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfoManager.h

@@ -32,11 +32,12 @@ NS_ASSUME_NONNULL_BEGIN
 // 获取信息回调
 - (void)queryUserInfoCallback:(UserInfoCallback)callback;
 
-- (void)queryUserInfoConnectRongCloud:(BOOL)connectRM;
+// 获取信息并连接IM
+- (void)queryUserInfoConnectionIMCallback:(UserInfoCallback)callback;
 
 - (void)queryUserInfoSendLoginUMCount;
 
-- (void)checkTokenEnableConnectRongCloud;
+- (void)checkTokenEnableConnectIM;
 
 - (BOOL)checkIMConnected;
 

+ 34 - 75
KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfoManager.m

@@ -9,11 +9,10 @@
 #import "ArchiveTools.h"
 #import "JPUSHService.h"
 #import <Bugly/Bugly.h>
-#import <RongIMKit/RongIMKit.h>
-#import "RCConnectionManager.h"
-#import "AppDelegate.h"
+#import "AppDelegate+AppService.h"
 #import "KSTipsAlert.h"
 #import <UMCommon/MobClick.h>
+#import "TXIMLinsenter.h"
 
 @interface UserInfoManager ()
 
@@ -81,7 +80,7 @@
                 }
                 else {
                     [self showMessage:@"登录过期,请重新登录"];
-                    [KSNetworkingManager logoutAction];
+                    [APPLOGIN_MANAGER logoutAction];
                     NSLog(@"----dddd");
                 }
             }];
@@ -92,7 +91,7 @@
 - (void)showTipsAlert {
     [KSTipsAlert shareInstanceWithTitle:@"提示" descMessage:@"聊天功能已断开,是否重新连接?" leftTitle:@"取消" rightTitle:@"连接" callback:^(BOOL isSure) {
         if (isSure) {
-            [self connectRongCloud];
+            [self connectIM];
         }
     }];
 }
@@ -114,7 +113,7 @@
     if (callback) {
         self.callback = callback;
     }
-    [self queryUserInfoConnectRongCloud:NO];
+    [self queryUserInfoConnectIM];
 }
 
 - (void)checkTokenEnableCallback:(void(^)(BOOL enable))checkCallback {
@@ -130,7 +129,7 @@
     }];
 }
 
-- (void)queryUserInfoConnectRongCloud:(BOOL)connectRM {
+- (void)queryUserInfoConnectIM {
 
     [KSNetworkingManager queryUserInfo:KS_GET success:^(NSDictionary * _Nonnull dic) {
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
@@ -147,36 +146,28 @@
             NSString *uid = self.userInfo.userId;
             UserDefaultSet(uid, UIDKey);
             
-            // 融云ID
-            NSString *rongCloudId = self.userInfo.imUserId;
-            UserDefaultSet(rongCloudId, RongCloudID);
+            NSString *imUserID = self.userInfo.imUserId;
+            UserDefaultSet(imUserID, IM_USERID);
             
-            NSString *rongToken = UserDefault(RongTokenKey);
-            BOOL needConnect = NO;
-            if ([NSString isEmptyString:rongToken]) {
-                needConnect = YES;
-            }
-
-            UserDefaultSet(self.userInfo.imToken, RongTokenKey);
+            UserDefaultSet(self.userInfo.imToken, IM_TOKEN);
             UserDefaultSet(self.userInfo.username, NicknameKey);
             UserDefaultSet(self.userInfo.avatar, AvatarUrlKey);
             [[NSUserDefaults standardUserDefaults] synchronize];
             
-            RCUserInfo *currentUserInfo =
-            [[RCUserInfo alloc] initWithUserId:UserDefault(RongCloudID) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
-            [RCIM sharedRCIM].currentUserInfo = currentUserInfo;
+            NSString *imToken = UserDefault(IM_TOKEN);
+            BOOL needConnect = NO;
+            if (![NSString isEmptyString:imToken] && [TXIM_LINSENTER isCurrentUserLoginIM] == NO) {
+                needConnect = YES;
+            }
             
-            if (connectRM) {
-
+            if (needConnect) {
                 // 设置推送别名
                 [JPUSHService setAlias:UserDefault(UIDKey) completion:nil seq:0];
                 [Bugly setUserIdentifier:UserDefault(UIDKey)];
-                [self connectRongCloud];
+                [self connectIM];
             }
-            else if (self.callback) {
-                if (needConnect) {
-                    [self connectRongCloud];
-                }
+            
+            if (self.callback) {
                 self.callback(self.userInfo);
                 self.callback = nil;
             }
@@ -195,17 +186,16 @@
     }];
 }
 
-- (void)checkTokenEnableConnectRongCloud {
+- (void)checkTokenEnableConnectIM {
     [self checkTokenEnableCallback:^(BOOL enable) {
         if (enable) {
-            [self connectRongCloud];
+            [self connectIM];
         }
     }];
 }
 
 - (BOOL)checkIMConnected {
-   RCConnectionStatus connStatus =  [[RCIM sharedRCIM] getConnectionStatus];
-    if (connStatus == ConnectionStatus_Connected) {
+    if ([TXIM_LINSENTER isCurrentUserLoginIM]) {
         return YES;
     }
     else {
@@ -243,47 +233,20 @@
     }
 }
 
-- (void)connectRongCloud {
-    NSString *rongToken = UserDefault(RongTokenKey);
-    if ([NSString isEmptyString:rongToken]) {
+- (void)connectIM {
+    NSString *imToken = UserDefault(IM_TOKEN);
+    if ([NSString isEmptyString:imToken]) {
         return;
     }
-    
-    // 融云登录
-    [[RCIM sharedRCIM] connectWithToken:UserDefault(RongTokenKey) dbOpened:^(RCDBErrorCode code) {
-        
-    } success:^(NSString *userId) {
-        
-        [RCConnectionManager shareManager].isConnected = YES;
-        // 设置个人信息
-        RCUserInfo *currentUserInfo =
-        [[RCUserInfo alloc] initWithUserId:userId name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
-        [RCIM sharedRCIM].currentUserInfo = currentUserInfo;
-        dispatch_async(dispatch_get_main_queue(), ^{
-            
-            AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-            [appDelegate displayUnreadMessageCount];
-        });
-        
-        
-    } error:^(RCConnectErrorCode errorCode) {
-        
-        if (errorCode == RC_CONN_TOKEN_INCORRECT) {
-            
+    [TXIM_LINSENTER TXIMLoginWithUserId:UserDefault(IM_USERID) sig:imToken callback:^(BOOL isSuccess, NSString * _Nullable msg) {
+        if (isSuccess) {
             dispatch_async(dispatch_get_main_queue(), ^{
-                // 再次获取token
                 AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-                [appDelegate requestRongCloudToken];
+                [appDelegate displayUnreadMessageCount];
             });
         }
         else {
-            
-            if (errorCode == RC_CONNECTION_EXIST) {
-                [RCConnectionManager shareManager].isConnected = YES;
-                
-                return;
-            }
-            NSString *message = [NSString stringWithFormat:@"IM连接错误%zd",errorCode];
+            NSString *message = [NSString stringWithFormat:@"IM连接错误:%@",msg];
             dispatch_main_async_safe(^{
                 [self showMessage:message];
             });
@@ -360,15 +323,11 @@
             
             NSString *uid = self.userInfo.userId;
             UserDefaultSet(uid, UIDKey);
-            // 融云ID
-            NSString *rongCloudId = self.userInfo.imUserId;
-            UserDefaultSet(rongCloudId, RongCloudID);
-            NSString *rongToken = UserDefault(RongTokenKey);
-            BOOL needConnect = NO;
-            if ([NSString isEmptyString:rongToken]) {
-                needConnect = YES;
-            }
-            UserDefaultSet(self.userInfo.imToken, RongTokenKey);
+            
+            // IM ID
+            NSString *IMUserId = self.userInfo.imUserId;
+            UserDefaultSet(IMUserId, IM_USERID);
+            UserDefaultSet(self.userInfo.imToken, IM_TOKEN);
             UserDefaultSet(self.userInfo.username, NicknameKey);
             UserDefaultSet(self.userInfo.avatar, AvatarUrlKey);
             [[NSUserDefaults standardUserDefaults] synchronize];
@@ -376,7 +335,7 @@
             // 设置推送别名
             [JPUSHService setAlias:UserDefault(UIDKey) completion:nil seq:0];
             [Bugly setUserIdentifier:UserDefault(UIDKey)];
-            [self connectRongCloud];
+            [self connectIM];
             [self startUMCountAndLoginCount];
             
         }

+ 0 - 4
KulexiuForStudent/KulexiuForStudent/Module/Mine/Controller/MineViewController.m

@@ -109,10 +109,6 @@
     [KSNetworkingManager queryStudentInfoRequest:KS_GET success:^(NSDictionary * _Nonnull dic) {
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
             self.mineInfo = [[StudentInfoModel alloc] initWithDictionary:[dic ks_dictionaryValueForKey:@"data"]];
-            NSString *rongToken = UserDefault(RongTokenKey);
-            if ([NSString isEmptyString:rongToken]) {
-                [USER_MANAGER queryUserInfoConnectRongCloud:YES];
-            }
             [self refreshView];
         }
         else {

+ 11 - 9
KulexiuForStudent/KulexiuForStudent/Module/Mine/Homework/View/HomeworkBodyView.m

@@ -8,6 +8,7 @@
 #import "HomeworkBodyView.h"
 #import "HomeworkListCell.h"
 #import "KSChatConversationViewController.h"
+#import "KSGroupConversationController.h"
 #import "HomeworkSortView.h"
 #import "KSFullDatePicker.h"
 #import "HomeworkDetailViewController.h"
@@ -198,18 +199,19 @@
 }
 
 - (void)chatGroup:(NSString *)targetId {
-    KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-    conversationVC.targetId = targetId;
-    conversationVC.conversationType = ConversationType_GROUP;
-    [self.naviController pushViewController:conversationVC animated:YES];
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.groupID = targetId;
+    KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+    ctrl.conversation = model;
+    [self.naviController pushViewController:ctrl animated:YES];
 }
 
 - (void)chatStudent:(NSString *)studentId name:(NSString *)name {
-    KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-    conversationVC.targetId = studentId;
-    conversationVC.title = name;
-    conversationVC.conversationType = ConversationType_PRIVATE;
-    [self.naviController pushViewController:conversationVC animated:YES];
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.userID = studentId;
+    KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+    ctrl.conversation = model;
+    [self.naviController pushViewController:ctrl animated:YES];
 }
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

+ 11 - 8
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLessonBodyView.m

@@ -12,6 +12,7 @@
 #import "LiveLessonModel.h"
 #import "AccompanyLessonModel.h"
 #import "KSChatConversationViewController.h"
+#include "KSGroupConversationController.h"
 #import "MyLessonSearchView.h"
 #import "NewClassPopView.h"
 #import "KSFullDatePicker.h"
@@ -450,10 +451,11 @@
     switch (type) {
         case ACCOMPANY_TYPE_CHAT: // 聊天
         {
-            KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-            conversationVC.targetId = model.userId;
-            conversationVC.conversationType = ConversationType_PRIVATE;
-            [self.naviController pushViewController:conversationVC animated:YES];
+            TUIChatConversationModel *conversation = [[TUIChatConversationModel alloc] init];
+            conversation.userID = model.userId;
+            KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+            ctrl.conversation = conversation;
+            [self.naviController pushViewController:ctrl animated:YES];
         }
             break;
         case ACCOMPANY_DETAIL:  // 陪练课详情
@@ -482,10 +484,11 @@
         [self MBPShow:@"报名未结束,暂无群组"];
         return;
     }
-    KSChatConversationViewController *conversationVC = [[KSChatConversationViewController alloc] init];
-    conversationVC.targetId = targetId;
-    conversationVC.conversationType = ConversationType_GROUP;
-    [self.naviController pushViewController:conversationVC animated:YES];
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.groupID = targetId;
+    KSGroupConversationController *ctrl = [[KSGroupConversationController alloc] init];
+    ctrl.conversation = model;
+    [self.naviController pushViewController:ctrl animated:YES];
 }
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

+ 1 - 17
KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/ModifyPhoneChangeController.m

@@ -86,23 +86,7 @@
 }
 
 - (void)successChangeBack {
-    USER_MANAGER.hasShowFlash = NO;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
-    [[NSUserDefaults standardUserDefaults] synchronize];
-    [KSNetworkingManager clearRequestHeader];
-    LoginViewController *loginVC = [[LoginViewController alloc] init];
-    CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    appDelegate.window.rootViewController = navCtrl;
+    [APPLOGIN_MANAGER logoutAction];
 }
 
 

+ 1 - 18
KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/ModifyViewController.m

@@ -12,7 +12,6 @@
 #import "AppDelegate.h"
 #import "CustomNavViewController.h"
 #import "JPUSHService.h"
-#import "RCConnectionManager.h"
 #import "UserInfoManager.h"
 
 @interface ModifyViewController ()
@@ -80,23 +79,7 @@
 
 // 重新登录
 - (void)toLoginView {
-    USER_MANAGER.hasShowFlash = NO;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
-    [[NSUserDefaults standardUserDefaults] synchronize];
-    [KSNetworkingManager clearRequestHeader];
-    LoginViewController *loginVC = [[LoginViewController alloc] init];
-    CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    appDelegate.window.rootViewController = navCtrl;
+    [APPLOGIN_MANAGER logoutAction];
 }
 
 #pragma mark --- 验证码

+ 1 - 18
KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/SettingViewController.m

@@ -138,24 +138,7 @@
 }
 
 - (void)clearSource {
-    [self clearUMCount];
-    USER_MANAGER.hasShowFlash = NO;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
-    [[NSUserDefaults standardUserDefaults] synchronize];
-    [KSNetworkingManager clearRequestHeader];
-    LoginViewController *loginVC = [[LoginViewController alloc] init];
-    CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    appDelegate.window.rootViewController = navCtrl;
+    [APPLOGIN_MANAGER logoutAction];
 }
 /*
 #pragma mark - Navigation

+ 1 - 24
KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/Controller/UserSettingViewController.m

@@ -7,8 +7,6 @@
 
 #import "UserSettingViewController.h"
 #import "UseBodyView.h"
-#import "RCConnectionManager.h"
-#import "LoginViewController.h"
 #import "AppDelegate.h"
 #import "CustomNavViewController.h"
 #import "JPUSHService.h"
@@ -55,10 +53,6 @@
     [KSNetworkingManager  queryStudentInfoRequest:KS_GET success:^(NSDictionary * _Nonnull dic) {
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
             StudentInfoModel *studentInfo = [[StudentInfoModel alloc] initWithDictionary:[dic ks_dictionaryValueForKey:@"data"]];
-            NSString *rongToken = UserDefault(RongTokenKey);
-            if ([NSString isEmptyString:rongToken]) {
-                [USER_MANAGER queryUserInfoConnectRongCloud:YES];
-            }
             [self refreshStudentSubject:studentInfo.subjectName];
         }
         else {
@@ -340,24 +334,7 @@
 }
 
 - (void)clearSource {
-    [self clearUMCount];
-    USER_MANAGER.hasShowFlash = NO;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
-    [[NSUserDefaults standardUserDefaults] synchronize];
-    [KSNetworkingManager clearRequestHeader];
-    LoginViewController *loginVC = [[LoginViewController alloc] init];
-    CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    appDelegate.window.rootViewController = navCtrl;
+    [APPLOGIN_MANAGER logoutAction];
 }
 
 #pragma mark --- RSKImageCropViewControllerDelegate

+ 1 - 17
KulexiuForStudent/KulexiuForStudent/Module/Mine/Setting/DeleteAccount/Controller/AccountDeleteViewController.m

@@ -91,23 +91,7 @@
 }
 
 - (void)successDeleteBack {
-    USER_MANAGER.hasShowFlash = NO;
-    [RCConnectionManager shareManager].isNeedJoin = NO;
-    [RCConnectionManager shareManager].isNeedShowMessage = NO;
-    [[RCIM sharedRCIM] logout];
-    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
-    // 取消推送别名
-    [JPUSHService deleteAlias:nil seq:0];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:TokenKey];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:Token_type];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RefreshToken];
-    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RongTokenKey];
-    [[NSUserDefaults standardUserDefaults] synchronize];
-    [KSNetworkingManager clearRequestHeader];
-    LoginViewController *loginVC = [[LoginViewController alloc] init];
-    CustomNavViewController *navCtrl = [[CustomNavViewController alloc] initWithRootViewController:loginVC];
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    appDelegate.window.rootViewController = navCtrl;
+    [APPLOGIN_MANAGER logoutAction];
 }
 
 #pragma mark --- 验证码

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Module/SealClass/Sections/NewWhiteboard/KSWhiteboardView.m

@@ -581,7 +581,7 @@
     if (phase == WhiteRoomPhaseDisconnected && self.roomUuid && self.roomToken) {
         self.reconnecting = YES;
         NSDictionary *payload = @{@"avatar": @"https://white-pan.oss-cn-shanghai.aliyuncs.com/40/image/mask.jpg"};
-        WhiteRoomConfig *roomConfig = [[WhiteRoomConfig alloc] initWithUUID:self.roomUuid roomToken:self.roomToken uid:UserDefault(RongCloudID) userPayload:payload];
+        WhiteRoomConfig *roomConfig = [[WhiteRoomConfig alloc] initWithUUID:self.roomUuid roomToken:self.roomToken uid:UserDefault(IM_USERID) userPayload:payload];
         [self.sdk joinRoomWithConfig:roomConfig callbacks:self completionHandler:^(BOOL success, WhiteRoom * _Nullable room, NSError * _Nullable error) {
             self.reconnecting = NO;
             NSLog(@"reconnected");

+ 28 - 3
KulexiuForStudent/Podfile

@@ -1,5 +1,8 @@
 # Uncomment the next line to define a global platform for your project
- platform :ios, '11.0'
+ platform :ios, '12.0'
+
+# 防止 TUIKit 组件里的 *.xcassets 与您项目里面冲突。
+install! 'cocoapods', :disable_input_output_paths => true
 
 target 'KulexiuForStudent' do
   # Comment the next line if you don't want to use dynamic frameworks
@@ -12,7 +15,7 @@ target 'KulexiuForStudent' do
   pod 'AFNetworking', '~> 4.0'
   pod 'Masonry', '~> 1.1.0'
   pod 'MBProgressHUD', '~> 1.2.0'
-  pod 'SDWebImage', '~> 5.12.5'
+  pod 'SDWebImage', '~> 5.16.0'
   pod 'MJRefresh', '~> 3.1.12'
   pod 'IQKeyboardManager'
   pod 'Reachability', '~> 3.2'
@@ -23,7 +26,7 @@ target 'KulexiuForStudent' do
   pod 'Bugly'
   pod 'Whiteboard'
   pod 'RSKImageCropper'
-  pod 'ZKCycleScrollView'
+#  pod 'ZKCycleScrollView'
   pod 'CHIPageControl'
   pod 'TYCyclePagerView'
 #  友盟
@@ -49,6 +52,16 @@ target 'KulexiuForStudent' do
   pod 'AlipaySDK-iOS'
   #lottie 动画库
   pod 'lottie-ios', '~> 2.5'
+  
+  # 集成聊天功能
+    pod 'TUIChat/UI_Classic'
+    # 集成会话功能
+    pod 'TUIConversation/UI_Classic'
+    # 集成群组功能
+    pod 'TUIGroup/UI_Classic'
+    # 集成搜索功能(需要购买旗舰版套餐)
+    pod 'TUISearch/UI_Classic'
+  
   # Pods for KulexiuForStudent
 
   target 'KulexiuForStudentTests' do
@@ -61,3 +74,15 @@ target 'KulexiuForStudent' do
   end
 
 end
+
+#Pods config
+#Fix Xcode14 Bundle target error
+post_install do |installer|
+    installer.generated_projects.each do |project|
+          project.targets.each do |target|
+              target.build_configurations.each do |config|
+                  config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
+               end
+          end
+   end
+end

+ 224 - 12
KulexiuForStudent/Podfile.lock

@@ -47,6 +47,7 @@ PODS:
   - MJRefresh (3.1.17)
   - NTLBridge (3.1.4)
   - Reachability (3.2)
+  - ReactiveObjC (3.1.1)
   - RongCloudIM/ChatRoom (5.3.1):
     - RongCloudIM/IMLibCore
   - RongCloudIM/CustomerService (5.3.1):
@@ -69,11 +70,206 @@ PODS:
   - RongCloudRTC/RongRTCLib (5.3.1.2):
     - RongCloudIM/IMLibCore (>= 5.3.1)
   - RSKImageCropper (3.0.2)
-  - SDWebImage (5.12.5):
-    - SDWebImage/Core (= 5.12.5)
-  - SDWebImage/Core (5.12.5)
+  - SDWebImage (5.16.0):
+    - SDWebImage/Core (= 5.16.0)
+  - SDWebImage/Core (5.16.0)
   - SocketRocket (0.6.0)
   - SSZipArchive (2.4.3)
+  - TIMCommon (7.3.4358):
+    - TIMCommon/BaseCell (= 7.3.4358)
+    - TIMCommon/CommonModel (= 7.3.4358)
+    - TIMCommon/UI_Classic (= 7.3.4358)
+    - TIMCommon/UI_Minimalist (= 7.3.4358)
+  - TIMCommon/BaseCell (7.3.4358):
+    - TIMCommon/BaseCell/CellData (= 7.3.4358)
+    - TIMCommon/BaseCell/CellUI (= 7.3.4358)
+  - TIMCommon/BaseCell/CellData (7.3.4358):
+    - TIMCommon/CommonModel
+  - TIMCommon/BaseCell/CellUI (7.3.4358):
+    - TIMCommon/BaseCell/CellData
+  - TIMCommon/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TIMCommon/UI_Classic (7.3.4358):
+    - TIMCommon/UI_Classic/Cell (= 7.3.4358)
+  - TIMCommon/UI_Classic/Cell (7.3.4358):
+    - TIMCommon/UI_Classic/Cell/CellData (= 7.3.4358)
+    - TIMCommon/UI_Classic/Cell/CellUI (= 7.3.4358)
+  - TIMCommon/UI_Classic/Cell/CellData (7.3.4358):
+    - TIMCommon/BaseCell
+  - TIMCommon/UI_Classic/Cell/CellUI (7.3.4358):
+    - TIMCommon/UI_Classic/Cell/CellData
+  - TIMCommon/UI_Minimalist (7.3.4358):
+    - TIMCommon/UI_Minimalist/Cell (= 7.3.4358)
+  - TIMCommon/UI_Minimalist/Cell (7.3.4358):
+    - TIMCommon/UI_Minimalist/Cell/CellData (= 7.3.4358)
+    - TIMCommon/UI_Minimalist/Cell/CellUI (= 7.3.4358)
+  - TIMCommon/UI_Minimalist/Cell/CellData (7.3.4358):
+    - TIMCommon/BaseCell
+  - TIMCommon/UI_Minimalist/Cell/CellUI (7.3.4358):
+    - TIMCommon/UI_Minimalist/Cell/CellData
+  - TUIChat/BaseCell (7.3.4358):
+    - TUIChat/BaseCell/CellData (= 7.3.4358)
+    - TUIChat/BaseCell/CellUI (= 7.3.4358)
+  - TUIChat/BaseCell/CellData (7.3.4358):
+    - TUIChat/CommonModel
+  - TUIChat/BaseCell/CellUI (7.3.4358):
+    - TUIChat/BaseCell/CellData
+  - TUIChat/BaseDataProvider (7.3.4358):
+    - TUIChat/BaseCell
+  - TUIChat/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TIMCommon (= 7.3.4358)
+    - TUIChat/VoiceConvert
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIChat/CommonUI (7.3.4358):
+    - TUIChat/CommonUI/Camera (= 7.3.4358)
+    - TUIChat/CommonUI/Pendency (= 7.3.4358)
+    - TUIChat/CommonUI/Pop (= 7.3.4358)
+  - TUIChat/CommonUI/Camera (7.3.4358):
+    - TUIChat/BaseDataProvider
+  - TUIChat/CommonUI/Pendency (7.3.4358):
+    - TUIChat/BaseDataProvider
+  - TUIChat/CommonUI/Pop (7.3.4358):
+    - TUIChat/BaseDataProvider
+  - TUIChat/UI_Classic (7.3.4358):
+    - TUIChat/UI_Classic/Cell (= 7.3.4358)
+    - TUIChat/UI_Classic/Chat (= 7.3.4358)
+    - TUIChat/UI_Classic/DataProvider (= 7.3.4358)
+    - TUIChat/UI_Classic/Header (= 7.3.4358)
+    - TUIChat/UI_Classic/Input (= 7.3.4358)
+    - TUIChat/UI_Classic/Service (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell/CellData (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Base (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellData/Chat (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellData/Custom (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellData/Reply (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell/CellData/Base (7.3.4358):
+    - TUIChat/CommonUI
+  - TUIChat/UI_Classic/Cell/CellData/Chat (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Base
+  - TUIChat/UI_Classic/Cell/CellData/Custom (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Chat
+  - TUIChat/UI_Classic/Cell/CellData/Reply (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Custom
+  - TUIChat/UI_Classic/Cell/CellUI (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Base (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI/Chat (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI/Custom (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI/Reply (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell/CellUI/Base (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData
+  - TUIChat/UI_Classic/Cell/CellUI/Chat (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Base
+  - TUIChat/UI_Classic/Cell/CellUI/Custom (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Chat
+  - TUIChat/UI_Classic/Cell/CellUI/Reply (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Custom
+  - TUIChat/UI_Classic/Chat (7.3.4358):
+    - TUIChat/UI_Classic/Input
+  - TUIChat/UI_Classic/DataProvider (7.3.4358):
+    - TUIChat/UI_Classic/Cell
+  - TUIChat/UI_Classic/Header (7.3.4358):
+    - TUIChat/UI_Classic/Service
+  - TUIChat/UI_Classic/Input (7.3.4358):
+    - TUIChat/UI_Classic/DataProvider
+  - TUIChat/UI_Classic/Service (7.3.4358):
+    - TUIChat/UI_Classic/Chat
+  - TUIChat/VoiceConvert (7.3.4358)
+  - TUIConversation/BaseCell (7.3.4358):
+    - TUIConversation/BaseCell/CellData (= 7.3.4358)
+    - TUIConversation/BaseCell/CellUI (= 7.3.4358)
+  - TUIConversation/BaseCell/CellData (7.3.4358):
+    - TUIConversation/CommonModel
+  - TUIConversation/BaseCell/CellUI (7.3.4358):
+    - TUIConversation/BaseCell/CellData
+  - TUIConversation/BaseDataProvider (7.3.4358):
+    - TUIConversation/BaseCell
+  - TUIConversation/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - TIMCommon (= 7.3.4358)
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIConversation/UI_Classic (7.3.4358):
+    - TUIConversation/UI_Classic/DataProvider (= 7.3.4358)
+    - TUIConversation/UI_Classic/Header (= 7.3.4358)
+    - TUIConversation/UI_Classic/Service (= 7.3.4358)
+    - TUIConversation/UI_Classic/UI (= 7.3.4358)
+  - TUIConversation/UI_Classic/DataProvider (7.3.4358):
+    - TUIConversation/BaseDataProvider
+  - TUIConversation/UI_Classic/Header (7.3.4358):
+    - TUIConversation/UI_Classic/Service
+  - TUIConversation/UI_Classic/Service (7.3.4358):
+    - TUIConversation/UI_Classic/UI
+  - TUIConversation/UI_Classic/UI (7.3.4358):
+    - TUIConversation/UI_Classic/DataProvider
+  - TUICore (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TUICore/ImSDK_Plus (= 7.3.4358)
+  - TUICore/Base (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+  - TUICore/ImSDK_Plus (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TUICore/Base
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIGroup/BaseCell (7.3.4358):
+    - TUIGroup/BaseCell/CellData (= 7.3.4358)
+    - TUIGroup/BaseCell/CellUI (= 7.3.4358)
+  - TUIGroup/BaseCell/CellData (7.3.4358):
+    - TUIGroup/CommonModel
+  - TUIGroup/BaseCell/CellUI (7.3.4358):
+    - TUIGroup/BaseCell/CellData
+  - TUIGroup/BaseDataProvider (7.3.4358):
+    - TUIGroup/BaseCell
+  - TUIGroup/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - TIMCommon (= 7.3.4358)
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIGroup/CommonUI (7.3.4358):
+    - TUIGroup/BaseDataProvider
+  - TUIGroup/UI_Classic (7.3.4358):
+    - TUIGroup/UI_Classic/Header (= 7.3.4358)
+    - TUIGroup/UI_Classic/Service (= 7.3.4358)
+    - TUIGroup/UI_Classic/UI (= 7.3.4358)
+  - TUIGroup/UI_Classic/Header (7.3.4358):
+    - TUIGroup/UI_Classic/Service
+  - TUIGroup/UI_Classic/Service (7.3.4358):
+    - TUIGroup/UI_Classic/UI
+  - TUIGroup/UI_Classic/UI (7.3.4358):
+    - TUIGroup/CommonUI
+  - TUISearch/BaseCell (7.3.4358):
+    - TUISearch/BaseCell/CellData (= 7.3.4358)
+    - TUISearch/BaseCell/CellUI (= 7.3.4358)
+  - TUISearch/BaseCell/CellData (7.3.4358):
+    - TIMCommon (= 7.3.4358)
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUISearch/BaseCell/CellUI (7.3.4358):
+    - TUISearch/BaseCell/CellData
+  - TUISearch/BaseDataProvider (7.3.4358):
+    - TUISearch/BaseCell
+  - TUISearch/UI_Classic (7.3.4358):
+    - TUISearch/UI_Classic/Header (= 7.3.4358)
+    - TUISearch/UI_Classic/Service (= 7.3.4358)
+    - TUISearch/UI_Classic/UI (= 7.3.4358)
+  - TUISearch/UI_Classic/Header (7.3.4358):
+    - TUISearch/UI_Classic/Service
+  - TUISearch/UI_Classic/Service (7.3.4358):
+    - TUISearch/UI_Classic/UI
+  - TUISearch/UI_Classic/UI (7.3.4358):
+    - TUISearch/BaseDataProvider
+  - TXIMSDK_Plus_iOS (7.3.4358)
   - TYCyclePagerView (1.2.0)
   - Whiteboard (2.16.48):
     - Whiteboard/Whiteboard-YYModel (= 2.16.48)
@@ -99,7 +295,6 @@ PODS:
     - Whiteboard/Resource
     - Whiteboard/Room
   - YYModel (1.0.4)
-  - ZKCycleScrollView (2.0.1)
 
 DEPENDENCIES:
   - AFNetworking (~> 4.0)
@@ -123,12 +318,15 @@ DEPENDENCIES:
   - RongCloudIM/Sight (~> 5.3.1)
   - RongCloudRTC/RongRTCLib (~> 5.3.1.2)
   - RSKImageCropper
-  - SDWebImage (~> 5.12.5)
+  - SDWebImage (~> 5.16.0)
   - SocketRocket
   - SSZipArchive
+  - TUIChat/UI_Classic
+  - TUIConversation/UI_Classic
+  - TUIGroup/UI_Classic
+  - TUISearch/UI_Classic
   - TYCyclePagerView
   - Whiteboard
-  - ZKCycleScrollView
 
 SPEC REPOS:
   trunk:
@@ -149,19 +347,26 @@ SPEC REPOS:
     - MJRefresh
     - NTLBridge
     - Reachability
+    - ReactiveObjC
     - RongCloudIM
     - RongCloudRTC
     - RSKImageCropper
     - SDWebImage
     - SocketRocket
     - SSZipArchive
+    - TIMCommon
+    - TUIChat
+    - TUIConversation
+    - TUICore
+    - TUIGroup
+    - TUISearch
+    - TXIMSDK_Plus_iOS
     - TYCyclePagerView
     - Whiteboard
     - YYModel
-    - ZKCycleScrollView
 
 SPEC CHECKSUMS:
-  AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
+  AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
   AlipaySDK-iOS: 9289d94792535cd14c5c241c720a7e981edd7035
   Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55
   CHIPageControl: a787bf7205c9b7e7fbfc412be36c5e8636b68f86
@@ -178,17 +383,24 @@ SPEC CHECKSUMS:
   MJRefresh: ee5b68f639775462faba4db0fd243baf4d42c2cf
   NTLBridge: 49780dc966976d3221a0eb03c7368617c1987cb6
   Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
+  ReactiveObjC: 011caa393aa0383245f2dcf9bf02e86b80b36040
   RongCloudIM: 869a9411f57b55ae9424b8253e299eff84f4d9bc
   RongCloudRTC: 3ad2cdafd8168b9cb5d9abec6d84bdeaefd4bff3
   RSKImageCropper: 1ac71e9a82e3f41eea3eedfff8eacb0d3821c9ec
-  SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e
+  SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6
   SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
   SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
+  TIMCommon: 2adea2895422a640e100125f6fccc0dc2aeff44b
+  TUIChat: 557dd6872606d9da7f36913af92ee95c8e651795
+  TUIConversation: 643823f80f0958b7263ac24411e397fcd5f37e78
+  TUICore: b0e525287eb03f95fe648a696c9ffb253fc87098
+  TUIGroup: 6a4133f356bd240997ac11bb94f89648899096f7
+  TUISearch: 18a208d0ef13eb7bf7f44eae01ffefb26803aaf3
+  TXIMSDK_Plus_iOS: bc72c7cec1b5e975c3cc6629692c849513a932f5
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
   Whiteboard: 7a09387d227121ad8fb3cbfdc6b66a383c024a0e
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
-  ZKCycleScrollView: 4b353d17b7f469b245a1c606d5a977e72b940895
 
-PODFILE CHECKSUM: dcda1baded1f0037d2b98e9b2ae8166675aa8795
+PODFILE CHECKSUM: 18d094cb5b71761b4f3218491660e33d7db2bc38
 
-COCOAPODS: 1.11.3
+COCOAPODS: 1.12.1

+ 224 - 12
KulexiuForStudent/Pods/Manifest.lock

@@ -47,6 +47,7 @@ PODS:
   - MJRefresh (3.1.17)
   - NTLBridge (3.1.4)
   - Reachability (3.2)
+  - ReactiveObjC (3.1.1)
   - RongCloudIM/ChatRoom (5.3.1):
     - RongCloudIM/IMLibCore
   - RongCloudIM/CustomerService (5.3.1):
@@ -69,11 +70,206 @@ PODS:
   - RongCloudRTC/RongRTCLib (5.3.1.2):
     - RongCloudIM/IMLibCore (>= 5.3.1)
   - RSKImageCropper (3.0.2)
-  - SDWebImage (5.12.5):
-    - SDWebImage/Core (= 5.12.5)
-  - SDWebImage/Core (5.12.5)
+  - SDWebImage (5.16.0):
+    - SDWebImage/Core (= 5.16.0)
+  - SDWebImage/Core (5.16.0)
   - SocketRocket (0.6.0)
   - SSZipArchive (2.4.3)
+  - TIMCommon (7.3.4358):
+    - TIMCommon/BaseCell (= 7.3.4358)
+    - TIMCommon/CommonModel (= 7.3.4358)
+    - TIMCommon/UI_Classic (= 7.3.4358)
+    - TIMCommon/UI_Minimalist (= 7.3.4358)
+  - TIMCommon/BaseCell (7.3.4358):
+    - TIMCommon/BaseCell/CellData (= 7.3.4358)
+    - TIMCommon/BaseCell/CellUI (= 7.3.4358)
+  - TIMCommon/BaseCell/CellData (7.3.4358):
+    - TIMCommon/CommonModel
+  - TIMCommon/BaseCell/CellUI (7.3.4358):
+    - TIMCommon/BaseCell/CellData
+  - TIMCommon/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TIMCommon/UI_Classic (7.3.4358):
+    - TIMCommon/UI_Classic/Cell (= 7.3.4358)
+  - TIMCommon/UI_Classic/Cell (7.3.4358):
+    - TIMCommon/UI_Classic/Cell/CellData (= 7.3.4358)
+    - TIMCommon/UI_Classic/Cell/CellUI (= 7.3.4358)
+  - TIMCommon/UI_Classic/Cell/CellData (7.3.4358):
+    - TIMCommon/BaseCell
+  - TIMCommon/UI_Classic/Cell/CellUI (7.3.4358):
+    - TIMCommon/UI_Classic/Cell/CellData
+  - TIMCommon/UI_Minimalist (7.3.4358):
+    - TIMCommon/UI_Minimalist/Cell (= 7.3.4358)
+  - TIMCommon/UI_Minimalist/Cell (7.3.4358):
+    - TIMCommon/UI_Minimalist/Cell/CellData (= 7.3.4358)
+    - TIMCommon/UI_Minimalist/Cell/CellUI (= 7.3.4358)
+  - TIMCommon/UI_Minimalist/Cell/CellData (7.3.4358):
+    - TIMCommon/BaseCell
+  - TIMCommon/UI_Minimalist/Cell/CellUI (7.3.4358):
+    - TIMCommon/UI_Minimalist/Cell/CellData
+  - TUIChat/BaseCell (7.3.4358):
+    - TUIChat/BaseCell/CellData (= 7.3.4358)
+    - TUIChat/BaseCell/CellUI (= 7.3.4358)
+  - TUIChat/BaseCell/CellData (7.3.4358):
+    - TUIChat/CommonModel
+  - TUIChat/BaseCell/CellUI (7.3.4358):
+    - TUIChat/BaseCell/CellData
+  - TUIChat/BaseDataProvider (7.3.4358):
+    - TUIChat/BaseCell
+  - TUIChat/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TIMCommon (= 7.3.4358)
+    - TUIChat/VoiceConvert
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIChat/CommonUI (7.3.4358):
+    - TUIChat/CommonUI/Camera (= 7.3.4358)
+    - TUIChat/CommonUI/Pendency (= 7.3.4358)
+    - TUIChat/CommonUI/Pop (= 7.3.4358)
+  - TUIChat/CommonUI/Camera (7.3.4358):
+    - TUIChat/BaseDataProvider
+  - TUIChat/CommonUI/Pendency (7.3.4358):
+    - TUIChat/BaseDataProvider
+  - TUIChat/CommonUI/Pop (7.3.4358):
+    - TUIChat/BaseDataProvider
+  - TUIChat/UI_Classic (7.3.4358):
+    - TUIChat/UI_Classic/Cell (= 7.3.4358)
+    - TUIChat/UI_Classic/Chat (= 7.3.4358)
+    - TUIChat/UI_Classic/DataProvider (= 7.3.4358)
+    - TUIChat/UI_Classic/Header (= 7.3.4358)
+    - TUIChat/UI_Classic/Input (= 7.3.4358)
+    - TUIChat/UI_Classic/Service (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell/CellData (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Base (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellData/Chat (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellData/Custom (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellData/Reply (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell/CellData/Base (7.3.4358):
+    - TUIChat/CommonUI
+  - TUIChat/UI_Classic/Cell/CellData/Chat (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Base
+  - TUIChat/UI_Classic/Cell/CellData/Custom (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Chat
+  - TUIChat/UI_Classic/Cell/CellData/Reply (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData/Custom
+  - TUIChat/UI_Classic/Cell/CellUI (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Base (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI/Chat (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI/Custom (= 7.3.4358)
+    - TUIChat/UI_Classic/Cell/CellUI/Reply (= 7.3.4358)
+  - TUIChat/UI_Classic/Cell/CellUI/Base (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellData
+  - TUIChat/UI_Classic/Cell/CellUI/Chat (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Base
+  - TUIChat/UI_Classic/Cell/CellUI/Custom (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Chat
+  - TUIChat/UI_Classic/Cell/CellUI/Reply (7.3.4358):
+    - TUIChat/UI_Classic/Cell/CellUI/Custom
+  - TUIChat/UI_Classic/Chat (7.3.4358):
+    - TUIChat/UI_Classic/Input
+  - TUIChat/UI_Classic/DataProvider (7.3.4358):
+    - TUIChat/UI_Classic/Cell
+  - TUIChat/UI_Classic/Header (7.3.4358):
+    - TUIChat/UI_Classic/Service
+  - TUIChat/UI_Classic/Input (7.3.4358):
+    - TUIChat/UI_Classic/DataProvider
+  - TUIChat/UI_Classic/Service (7.3.4358):
+    - TUIChat/UI_Classic/Chat
+  - TUIChat/VoiceConvert (7.3.4358)
+  - TUIConversation/BaseCell (7.3.4358):
+    - TUIConversation/BaseCell/CellData (= 7.3.4358)
+    - TUIConversation/BaseCell/CellUI (= 7.3.4358)
+  - TUIConversation/BaseCell/CellData (7.3.4358):
+    - TUIConversation/CommonModel
+  - TUIConversation/BaseCell/CellUI (7.3.4358):
+    - TUIConversation/BaseCell/CellData
+  - TUIConversation/BaseDataProvider (7.3.4358):
+    - TUIConversation/BaseCell
+  - TUIConversation/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - TIMCommon (= 7.3.4358)
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIConversation/UI_Classic (7.3.4358):
+    - TUIConversation/UI_Classic/DataProvider (= 7.3.4358)
+    - TUIConversation/UI_Classic/Header (= 7.3.4358)
+    - TUIConversation/UI_Classic/Service (= 7.3.4358)
+    - TUIConversation/UI_Classic/UI (= 7.3.4358)
+  - TUIConversation/UI_Classic/DataProvider (7.3.4358):
+    - TUIConversation/BaseDataProvider
+  - TUIConversation/UI_Classic/Header (7.3.4358):
+    - TUIConversation/UI_Classic/Service
+  - TUIConversation/UI_Classic/Service (7.3.4358):
+    - TUIConversation/UI_Classic/UI
+  - TUIConversation/UI_Classic/UI (7.3.4358):
+    - TUIConversation/UI_Classic/DataProvider
+  - TUICore (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TUICore/ImSDK_Plus (= 7.3.4358)
+  - TUICore/Base (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+  - TUICore/ImSDK_Plus (7.3.4358):
+    - ReactiveObjC
+    - SDWebImage
+    - TUICore/Base
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIGroup/BaseCell (7.3.4358):
+    - TUIGroup/BaseCell/CellData (= 7.3.4358)
+    - TUIGroup/BaseCell/CellUI (= 7.3.4358)
+  - TUIGroup/BaseCell/CellData (7.3.4358):
+    - TUIGroup/CommonModel
+  - TUIGroup/BaseCell/CellUI (7.3.4358):
+    - TUIGroup/BaseCell/CellData
+  - TUIGroup/BaseDataProvider (7.3.4358):
+    - TUIGroup/BaseCell
+  - TUIGroup/CommonModel (7.3.4358):
+    - ReactiveObjC
+    - TIMCommon (= 7.3.4358)
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUIGroup/CommonUI (7.3.4358):
+    - TUIGroup/BaseDataProvider
+  - TUIGroup/UI_Classic (7.3.4358):
+    - TUIGroup/UI_Classic/Header (= 7.3.4358)
+    - TUIGroup/UI_Classic/Service (= 7.3.4358)
+    - TUIGroup/UI_Classic/UI (= 7.3.4358)
+  - TUIGroup/UI_Classic/Header (7.3.4358):
+    - TUIGroup/UI_Classic/Service
+  - TUIGroup/UI_Classic/Service (7.3.4358):
+    - TUIGroup/UI_Classic/UI
+  - TUIGroup/UI_Classic/UI (7.3.4358):
+    - TUIGroup/CommonUI
+  - TUISearch/BaseCell (7.3.4358):
+    - TUISearch/BaseCell/CellData (= 7.3.4358)
+    - TUISearch/BaseCell/CellUI (= 7.3.4358)
+  - TUISearch/BaseCell/CellData (7.3.4358):
+    - TIMCommon (= 7.3.4358)
+    - TUICore (= 7.3.4358)
+    - TXIMSDK_Plus_iOS (= 7.3.4358)
+  - TUISearch/BaseCell/CellUI (7.3.4358):
+    - TUISearch/BaseCell/CellData
+  - TUISearch/BaseDataProvider (7.3.4358):
+    - TUISearch/BaseCell
+  - TUISearch/UI_Classic (7.3.4358):
+    - TUISearch/UI_Classic/Header (= 7.3.4358)
+    - TUISearch/UI_Classic/Service (= 7.3.4358)
+    - TUISearch/UI_Classic/UI (= 7.3.4358)
+  - TUISearch/UI_Classic/Header (7.3.4358):
+    - TUISearch/UI_Classic/Service
+  - TUISearch/UI_Classic/Service (7.3.4358):
+    - TUISearch/UI_Classic/UI
+  - TUISearch/UI_Classic/UI (7.3.4358):
+    - TUISearch/BaseDataProvider
+  - TXIMSDK_Plus_iOS (7.3.4358)
   - TYCyclePagerView (1.2.0)
   - Whiteboard (2.16.48):
     - Whiteboard/Whiteboard-YYModel (= 2.16.48)
@@ -99,7 +295,6 @@ PODS:
     - Whiteboard/Resource
     - Whiteboard/Room
   - YYModel (1.0.4)
-  - ZKCycleScrollView (2.0.1)
 
 DEPENDENCIES:
   - AFNetworking (~> 4.0)
@@ -123,12 +318,15 @@ DEPENDENCIES:
   - RongCloudIM/Sight (~> 5.3.1)
   - RongCloudRTC/RongRTCLib (~> 5.3.1.2)
   - RSKImageCropper
-  - SDWebImage (~> 5.12.5)
+  - SDWebImage (~> 5.16.0)
   - SocketRocket
   - SSZipArchive
+  - TUIChat/UI_Classic
+  - TUIConversation/UI_Classic
+  - TUIGroup/UI_Classic
+  - TUISearch/UI_Classic
   - TYCyclePagerView
   - Whiteboard
-  - ZKCycleScrollView
 
 SPEC REPOS:
   trunk:
@@ -149,19 +347,26 @@ SPEC REPOS:
     - MJRefresh
     - NTLBridge
     - Reachability
+    - ReactiveObjC
     - RongCloudIM
     - RongCloudRTC
     - RSKImageCropper
     - SDWebImage
     - SocketRocket
     - SSZipArchive
+    - TIMCommon
+    - TUIChat
+    - TUIConversation
+    - TUICore
+    - TUIGroup
+    - TUISearch
+    - TXIMSDK_Plus_iOS
     - TYCyclePagerView
     - Whiteboard
     - YYModel
-    - ZKCycleScrollView
 
 SPEC CHECKSUMS:
-  AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
+  AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
   AlipaySDK-iOS: 9289d94792535cd14c5c241c720a7e981edd7035
   Bugly: afe841bba2ea6de6d432a3c125240a5e75949c55
   CHIPageControl: a787bf7205c9b7e7fbfc412be36c5e8636b68f86
@@ -178,17 +383,24 @@ SPEC CHECKSUMS:
   MJRefresh: ee5b68f639775462faba4db0fd243baf4d42c2cf
   NTLBridge: 49780dc966976d3221a0eb03c7368617c1987cb6
   Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
+  ReactiveObjC: 011caa393aa0383245f2dcf9bf02e86b80b36040
   RongCloudIM: 869a9411f57b55ae9424b8253e299eff84f4d9bc
   RongCloudRTC: 3ad2cdafd8168b9cb5d9abec6d84bdeaefd4bff3
   RSKImageCropper: 1ac71e9a82e3f41eea3eedfff8eacb0d3821c9ec
-  SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e
+  SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6
   SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
   SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
+  TIMCommon: 2adea2895422a640e100125f6fccc0dc2aeff44b
+  TUIChat: 557dd6872606d9da7f36913af92ee95c8e651795
+  TUIConversation: 643823f80f0958b7263ac24411e397fcd5f37e78
+  TUICore: b0e525287eb03f95fe648a696c9ffb253fc87098
+  TUIGroup: 6a4133f356bd240997ac11bb94f89648899096f7
+  TUISearch: 18a208d0ef13eb7bf7f44eae01ffefb26803aaf3
+  TXIMSDK_Plus_iOS: bc72c7cec1b5e975c3cc6629692c849513a932f5
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
   Whiteboard: 7a09387d227121ad8fb3cbfdc6b66a383c024a0e
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
-  ZKCycleScrollView: 4b353d17b7f469b245a1c606d5a977e72b940895
 
-PODFILE CHECKSUM: dcda1baded1f0037d2b98e9b2ae8166675aa8795
+PODFILE CHECKSUM: 18d094cb5b71761b4f3218491660e33d7db2bc38
 
-COCOAPODS: 1.11.3
+COCOAPODS: 1.12.1

File diff suppressed because it is too large
+ 4040 - 2363
KulexiuForStudent/Pods/Pods.xcodeproj/project.pbxproj


+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/AFNetworking.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Bugly.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/CHIPageControl.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/IQKeyboardManager.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JCore.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JPush.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXCategoryView.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXPagingView.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MBProgressHUD.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJExtension.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJRefresh.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Masonry.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent-KulexiuForStudentUITests.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudentTests.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RSKImageCropper.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Reachability.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RongCloudIM.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RongCloudRTC.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SDWebImage.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SSZipArchive.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SocketRocket.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard-Whiteboard.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/YYModel.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1420"
+   LastUpgradeVersion = "1300"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 0 - 58
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/ZKCycleScrollView.xcscheme

@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1420"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "36A2305B276FAAAA5356557E6EE334F5"
-               BuildableName = "ZKCycleScrollView.framework"
-               BlueprintName = "ZKCycleScrollView"
-               ReferencedContainer = "container:Pods.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 40 - 5
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -99,6 +99,11 @@
 			<key>isShown</key>
 			<false/>
 		</dict>
+		<key>ReactiveObjC.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
 		<key>RongCloudIM.xcscheme</key>
 		<dict>
 			<key>isShown</key>
@@ -124,27 +129,57 @@
 			<key>isShown</key>
 			<false/>
 		</dict>
-		<key>TYCyclePagerView.xcscheme</key>
+		<key>TIMCommon.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
 		</dict>
-		<key>Whiteboard-Whiteboard.xcscheme</key>
+		<key>TUIChat.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
 		</dict>
-		<key>Whiteboard.xcscheme</key>
+		<key>TUIConversation.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
 		</dict>
-		<key>YYModel.xcscheme</key>
+		<key>TUICore.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>TUIGroup.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>TUISearch.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>TXIMSDK_Plus_iOS.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>TYCyclePagerView.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>Whiteboard-Whiteboard.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>
 		</dict>
-		<key>ZKCycleScrollView.xcscheme</key>
+		<key>Whiteboard.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
+		<key>YYModel.xcscheme</key>
 		<dict>
 			<key>isShown</key>
 			<false/>

Some files were not shown because too many files changed in this diff