TUIMessageReadViewController_Minimalist.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. //
  2. // TUIMessageReadViewController_Minimalist.m
  3. // TUIChat
  4. //
  5. // Created by xia on 2022/3/10.
  6. // Copyright © 2023 Tencent. All rights reserved.
  7. //
  8. #import "TUIMessageReadViewController_Minimalist.h"
  9. #import <TUICore/TUICore.h>
  10. #import <TUICore/TUIThemeManager.h>
  11. #import <TUICore/TUITool.h>
  12. #import <TUICore/UIColor+TUIHexColor.h>
  13. #import "TUIImageMessageCellData.h"
  14. #import "TUIMemberCellData.h"
  15. #import "TUIMemberCell_Minimalist.h"
  16. #import "TUIMessageDataProvider.h"
  17. #import "TUIVideoMessageCellData.h"
  18. #import "TUITextMessageCellData.h"
  19. #import "TUIReplyMessageCellData.h"
  20. #import "TUIVoiceMessageCellData.h"
  21. #import "TUIMessageCellConfig_Minimalist.h"
  22. @interface TUIMessageReadViewController_Minimalist () <UITableViewDelegate, UITableViewDataSource,TUINotificationProtocol>
  23. @property(nonatomic, strong) TUIMessageCellData *cellData;
  24. @property(nonatomic, assign) BOOL showReadStatusDisable;
  25. @property(nonatomic, strong) TUIMessageDataProvider *dataProvider;
  26. @property(nonatomic, strong) UIView *messageBackView;
  27. @property(nonatomic, strong) UITableView *tableView;
  28. @property(nonatomic, strong) NSMutableArray *readMembers;
  29. @property(nonatomic, strong) NSMutableArray *unreadMembers;
  30. @property(nonatomic, assign) NSUInteger readSeq;
  31. @property(nonatomic, assign) NSUInteger unreadSeq;
  32. @property(nonatomic, copy) NSString *c2cReceiverName;
  33. @property(nonatomic, copy) NSString *c2cReceiverAvatarUrl;
  34. @property(nonatomic, strong) TUIMessageCell_Minimalist *alertView;
  35. @property(nonatomic, strong) TUIMessageCellConfig_Minimalist *messageCellConfig;
  36. @end
  37. @implementation TUIMessageReadViewController_Minimalist
  38. #pragma mark - Life cycle
  39. - (void)viewDidLoad {
  40. [super viewDidLoad];
  41. if ([self isGroupMessageRead]) {
  42. [self loadMembers];
  43. }
  44. [self setupViews];
  45. // Do any additional setup after loading the view.
  46. [TUICore registerEvent:TUICore_TUIPluginNotify subKey:TUICore_TUIPluginNotify_DidChangePluginViewSubKey object:self];
  47. }
  48. - (void)viewWillLayoutSubviews {
  49. [super viewWillLayoutSubviews];
  50. [self layoutViews];
  51. }
  52. - (void)viewWillAppear:(BOOL)animated {
  53. [super viewWillAppear:animated];
  54. [self updateRootMsg];
  55. if (_viewWillShowHandler) {
  56. _viewWillShowHandler(_alertView);
  57. }
  58. }
  59. - (void)viewDidAppear:(BOOL)animated {
  60. [super viewDidAppear:animated];
  61. if (_viewDidShowHandler) {
  62. _viewDidShowHandler(_alertView);
  63. }
  64. }
  65. - (void)viewWillDisappear:(BOOL)animated {
  66. [super viewWillDisappear:animated];
  67. if (_viewWillDismissHandler) {
  68. _viewWillDismissHandler(_alertView);
  69. }
  70. }
  71. - (void)dealloc {
  72. NSLog(@"%s dealloc", __FUNCTION__);
  73. }
  74. #pragma mark - Public
  75. - (instancetype)initWithCellData:(TUIMessageCellData *)data
  76. dataProvider:(TUIMessageDataProvider *)dataProvider
  77. showReadStatusDisable:(BOOL)showReadStatusDisable
  78. c2cReceiverName:(NSString *)name
  79. c2cReceiverAvatar:(NSString *)avatarUrl {
  80. self = [super init];
  81. if (self) {
  82. self.cellData = data;
  83. self.dataProvider = dataProvider;
  84. self.showReadStatusDisable = showReadStatusDisable;
  85. self.c2cReceiverName = name;
  86. self.c2cReceiverAvatarUrl = avatarUrl;
  87. }
  88. return self;
  89. }
  90. #pragma mark - Private
  91. - (void)setupViews {
  92. self.view.backgroundColor = TIMCommonDynamicColor(@"controller_bg_color", @"#F2F3F5");
  93. [self setupTitleView];
  94. [self setupMessageView];
  95. }
  96. - (void)layoutViews {
  97. float backViewTop = self.navigationController.navigationBar.mm_maxY;
  98. self.messageBackView.frame = CGRectMake(0, 0, self.view.bounds.size.width, kScale390(17)+ kScale390(24)+ kScale390(4));
  99. self.tableView.mm_top(backViewTop).mm_left(0).mm_width(self.view.mm_w).mm_height(self.view.mm_h - _tableView.mm_y);
  100. }
  101. - (void)setupTitleView {
  102. UILabel *titleLabel = [[UILabel alloc] init];
  103. titleLabel.text = TIMCommonLocalizableString(MessageInfo);
  104. titleLabel.font = [UIFont systemFontOfSize:18.0];
  105. titleLabel.textColor = TIMCommonDynamicColor(@"nav_title_text_color", @"#000000");
  106. [titleLabel sizeToFit];
  107. self.navigationItem.titleView = titleLabel;
  108. }
  109. - (void)setupMessageView {
  110. UIView *messageBackView = [[UIView alloc] init];
  111. messageBackView.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF");
  112. messageBackView.userInteractionEnabled = YES;
  113. self.messageBackView = messageBackView;
  114. self.tableView.tableHeaderView = self.messageBackView;
  115. self.tableView.tableHeaderView.userInteractionEnabled = YES;
  116. UILabel *dateLabel = [[UILabel alloc] init];
  117. [messageBackView addSubview:dateLabel];
  118. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  119. [formatter setDateFormat:@"MM-dd HH:mm"];
  120. NSString *dateString = [formatter stringFromDate:self.cellData.innerMessage.timestamp];
  121. dateLabel.text = dateString;
  122. dateLabel.font = [UIFont systemFontOfSize:kScale390(14)];
  123. dateLabel.textAlignment = isRTL()?NSTextAlignmentRight:NSTextAlignmentLeft;
  124. dateLabel.textColor = TUIChatDynamicColor(@"chat_message_read_name_date_text_color", @"#999999");
  125. [dateLabel sizeToFit];
  126. [dateLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  127. make.centerX.mas_equalTo(self.view);
  128. make.top.mas_equalTo(kScale390(17));
  129. make.width.mas_equalTo(dateLabel.frame.size.width);
  130. make.height.mas_equalTo(kScale390(24));
  131. }];
  132. }
  133. - (void)updateRootMsg {
  134. TUIMessageCellData *data = self.alertViewCellData;
  135. self.alertViewCellData.showAvatar = NO;
  136. self.alertViewCellData.showMessageModifyReplies = NO;
  137. }
  138. - (void)loadMembers {
  139. [self getReadMembersWithCompletion:^(int code, NSString *desc, NSArray *members, BOOL isFinished) {
  140. [self.tableView reloadData];
  141. }];
  142. [self getUnreadMembersWithCompletion:^(int code, NSString *desc, NSArray *members, BOOL isFinished) {
  143. [self.tableView reloadData];
  144. }];
  145. }
  146. - (void)getReadMembersWithCompletion:(void (^)(int code, NSString *desc, NSArray *members, BOOL isFinished))completion {
  147. @weakify(self);
  148. [TUIMessageDataProvider
  149. getReadMembersOfMessage:self.cellData.innerMessage
  150. filter:V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ
  151. nextSeq:self.readSeq
  152. completion:^(int code, NSString *_Nonnull desc, NSArray *_Nonnull members, NSUInteger nextSeq, BOOL isFinished) {
  153. @strongify(self);
  154. if (code != 0) {
  155. return;
  156. }
  157. [self.readMembers addObjectsFromArray:members];
  158. self.readSeq = isFinished ? -1 : nextSeq;
  159. if (completion) {
  160. completion(code, desc, members, isFinished);
  161. }
  162. }];
  163. }
  164. - (void)getUnreadMembersWithCompletion:(void (^)(int code, NSString *desc, NSArray *members, BOOL isFinished))completion {
  165. @weakify(self);
  166. [TUIMessageDataProvider
  167. getReadMembersOfMessage:self.cellData.innerMessage
  168. filter:V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_UNREAD
  169. nextSeq:self.unreadSeq
  170. completion:^(int code, NSString *_Nonnull desc, NSArray *_Nonnull members, NSUInteger nextSeq, BOOL isFinished) {
  171. @strongify(self);
  172. if (code != 0) {
  173. return;
  174. }
  175. [self.unreadMembers addObjectsFromArray:members];
  176. self.unreadSeq = isFinished ? -1 : nextSeq;
  177. if (completion) {
  178. completion(code, desc, members, isFinished);
  179. }
  180. }];
  181. }
  182. - (void)getUserOrFriendProfileVCWithUserID:(NSString *)userID SuccBlock:(void (^)(UIViewController *vc))succ failBlock:(nullable V2TIMFail)fail {
  183. NSDictionary *param = @{
  184. TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_UserIDKey: userID ? : @"",
  185. TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_SuccKey: succ ? : ^(UIViewController *vc){},
  186. TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_FailKey: fail ? : ^(int code, NSString * desc){}
  187. };
  188. [TUICore createObject:TUICore_TUIContactObjectFactory_Minimalist key:TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod param:param];
  189. }
  190. #pragma mark - UITableViewDataSource & UITableViewDelegate
  191. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  192. [tableView deselectRowAtIndexPath:indexPath animated:NO];
  193. TUICommonCellData *data = [self members][indexPath.row];
  194. @weakify(self);
  195. if ([data isKindOfClass:TUIMemberDescribeCellData.class]) {
  196. return;
  197. } else if ([data isKindOfClass:TUIMemberCellData.class]) {
  198. if ([self isGroupMessageRead]) {
  199. if (indexPath.row >= [self members].count) {
  200. return;
  201. }
  202. TUIMemberCellData *currentData = (TUIMemberCellData *)data;
  203. [self getUserOrFriendProfileVCWithUserID:currentData.userID
  204. SuccBlock:^(UIViewController *vc) {
  205. @strongify(self);
  206. [self.navigationController pushViewController:vc animated:YES];
  207. }
  208. failBlock:nil];
  209. } else {
  210. [self getUserOrFriendProfileVCWithUserID:self.cellData.innerMessage.userID
  211. SuccBlock:^(UIViewController *vc) {
  212. @strongify(self);
  213. [self.navigationController pushViewController:vc animated:YES];
  214. }
  215. failBlock:nil];
  216. }
  217. }
  218. }
  219. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  220. return 2;
  221. }
  222. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  223. if(section == 0){
  224. return 1;
  225. }
  226. return [self members].count;
  227. }
  228. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  229. if (indexPath.section == 0) {
  230. TUIMessageCell *cell = nil;
  231. TUIMessageCellData *data = self.alertViewCellData;
  232. cell = [tableView dequeueReusableCellWithIdentifier:data.reuseId forIndexPath:indexPath];
  233. cell.delegate = self;
  234. [cell fillWithData:data];
  235. [cell notifyBottomContainerReadyOfData:nil];
  236. return cell;
  237. }
  238. TUICommonCellData *data = [self members][indexPath.row];
  239. TUICommonTableViewCell *cell = nil;
  240. if ([data isKindOfClass:TUIMemberDescribeCellData.class]) {
  241. cell = [tableView dequeueReusableCellWithIdentifier:@"TUIMemberDescribeCell_Minimalist" forIndexPath:indexPath];
  242. } else {
  243. cell = [tableView dequeueReusableCellWithIdentifier:kMemberCellReuseId forIndexPath:indexPath];
  244. }
  245. [cell fillWithData:data];
  246. return cell;
  247. }
  248. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  249. if (indexPath.section == 0) {
  250. CGFloat margin = 0;
  251. if (self.cellData.sameToNextMsgSender) {
  252. margin = 10;
  253. }
  254. return [self.messageCellConfig getHeightFromMessageCellData:self.cellData] + margin;
  255. }
  256. TUICommonCellData *data = [self members][indexPath.row];
  257. if ([data isKindOfClass:TUIMemberDescribeCellData.class]) {
  258. return kScale390(57);
  259. } else {
  260. return kScale390(57);
  261. }
  262. return kScale390(57);
  263. }
  264. #pragma mark - datasource
  265. - (NSArray *)members {
  266. NSMutableArray *dataArray = [NSMutableArray arrayWithCapacity:2];
  267. if ([self isGroupMessageRead]) {
  268. if (self.readMembers.count > 0) {
  269. TUIMemberDescribeCellData *describeCellData = [[TUIMemberDescribeCellData alloc] init];
  270. describeCellData.title = TIMCommonLocalizableString(GroupReadBy);
  271. describeCellData.icon = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_all_people_read")];
  272. [dataArray addObject:describeCellData];
  273. for (V2TIMGroupMemberInfo *member in self.readMembers) {
  274. TUIMemberCellData *data = [[TUIMemberCellData alloc] initWithUserID:member.userID
  275. nickName:member.nickName
  276. friendRemark:member.friendRemark
  277. nameCard:member.nameCard
  278. avatarUrl:member.faceURL
  279. detail:nil];
  280. [dataArray addObject:data];
  281. }
  282. }
  283. if (self.unreadMembers.count > 0) {
  284. TUIMemberDescribeCellData *describeCellData = [[TUIMemberDescribeCellData alloc] init];
  285. describeCellData.title = TIMCommonLocalizableString(GroupDeliveredTo);
  286. describeCellData.icon = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_some_people_read")];
  287. [dataArray addObject:describeCellData];
  288. for (V2TIMGroupMemberInfo *member in self.unreadMembers) {
  289. TUIMemberCellData *data = [[TUIMemberCellData alloc] initWithUserID:member.userID
  290. nickName:member.nickName
  291. friendRemark:member.friendRemark
  292. nameCard:member.nameCard
  293. avatarUrl:member.faceURL
  294. detail:nil];
  295. [dataArray addObject:data];
  296. }
  297. }
  298. } else {
  299. if (self.cellData.direction == MsgDirectionIncoming) {
  300. return dataArray;
  301. }
  302. NSString *detail = nil;
  303. BOOL isPeerRead = self.cellData.messageReceipt.isPeerRead;
  304. TUIMemberDescribeCellData *describeCellData = [[TUIMemberDescribeCellData alloc] init];
  305. if (isPeerRead) {
  306. describeCellData.title = TIMCommonLocalizableString(C2CReadBy);
  307. describeCellData.icon = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_all_people_read")];
  308. } else {
  309. describeCellData.title = TIMCommonLocalizableString(C2CDeliveredTo);
  310. describeCellData.icon = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_some_people_read")];
  311. }
  312. TUIMemberCellData *data = [[TUIMemberCellData alloc] initWithUserID:self.cellData.innerMessage.userID
  313. nickName:nil
  314. friendRemark:self.c2cReceiverName
  315. nameCard:nil
  316. avatarUrl:self.c2cReceiverAvatarUrl
  317. detail:detail];
  318. [dataArray addObject:describeCellData];
  319. [dataArray addObject:data];
  320. }
  321. return dataArray;
  322. }
  323. - (NSMutableArray *)readMembers {
  324. if (!_readMembers) {
  325. _readMembers = [[NSMutableArray alloc] init];
  326. }
  327. return _readMembers;
  328. }
  329. - (NSMutableArray *)unreadMembers {
  330. if (!_unreadMembers) {
  331. _unreadMembers = [[NSMutableArray alloc] init];
  332. }
  333. return _unreadMembers;
  334. }
  335. - (BOOL)isGroupMessageRead {
  336. return self.cellData.innerMessage.groupID.length > 0;
  337. }
  338. - (UITableView *)tableView {
  339. if (!_tableView) {
  340. _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
  341. _tableView.delegate = self;
  342. _tableView.dataSource = self;
  343. _tableView.contentInset = UIEdgeInsetsMake(0, 0, 8, 0);
  344. [_tableView setBackgroundColor:TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF")];
  345. [self.view addSubview:_tableView];
  346. UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
  347. [_tableView setTableFooterView:view];
  348. _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  349. [_tableView registerClass:[TUIMemberCell_Minimalist class] forCellReuseIdentifier:kMemberCellReuseId];
  350. [_tableView registerClass:[TUIMemberDescribeCell_Minimalist class] forCellReuseIdentifier:@"TUIMemberDescribeCell_Minimalist"];
  351. [self.messageCellConfig bindTableView:self.tableView];
  352. }
  353. return _tableView;
  354. }
  355. - (void)dataProvider:(TUIMessageBaseDataProvider *)dataProvider onRemoveHeightCache:(TUIMessageCellData *)cellData {
  356. if (cellData) {
  357. [self.messageCellConfig removeHeightCacheOfMessageCellData:cellData];
  358. }
  359. }
  360. - (TUIMessageCellConfig_Minimalist *)messageCellConfig {
  361. if (_messageCellConfig == nil) {
  362. _messageCellConfig = [[TUIMessageCellConfig_Minimalist alloc] init];
  363. }
  364. return _messageCellConfig;
  365. }
  366. #pragma mark - TUINotificationProtocol
  367. - (void)onNotifyEvent:(NSString *)key subKey:(NSString *)subKey object:(id)anObject param:(NSDictionary *)param {
  368. if ([key isEqualToString:TUICore_TUIPluginNotify] && [subKey isEqualToString:TUICore_TUIPluginNotify_DidChangePluginViewSubKey]) {
  369. // Translation View is Shown or content changed.
  370. TUIMessageCellData *data = param[TUICore_TUIPluginNotify_DidChangePluginViewSubKey_Data];
  371. [self clearAndReloadCellOfData:data];
  372. }
  373. }
  374. - (void)clearAndReloadCellOfData:(TUIMessageCellData *)data {
  375. [self.messageCellConfig removeHeightCacheOfMessageCellData:data];
  376. [self.tableView reloadData];
  377. }
  378. @end