提交
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TUIConversationCellData_Classic.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2022/10/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationCellData.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationCellData_Minimalist : TUIConversationCellData
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TUIConversationCellData_Minimalist.m
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2022/10/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationCellData_Minimalist.h"
|
||||
|
||||
@implementation TUIConversationCellData_Minimalist
|
||||
|
||||
- (CGFloat)heightOfWidth:(CGFloat)width {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TUIConversationCell_Minimalist.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2022/10/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationCell.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationCell_Minimalist : TUIConversationCell
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,391 @@
|
||||
//
|
||||
// TUIConversationCell_Minimalist.m
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2022/10/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationCell_Minimalist.h"
|
||||
#import "TUIConversationConfig.h"
|
||||
|
||||
@implementation TUIConversationCell_Minimalist
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
|
||||
if (self) {
|
||||
self.titleLabel.font = [UIFont boldSystemFontOfSize:kScale390(14)];
|
||||
self.titleLabel.textColor = TUIDynamicColor(@"", TUIThemeModuleCore_Minimalist, @"#000000");
|
||||
self.subTitleLabel.font = [UIFont systemFontOfSize:kScale390(12)];
|
||||
self.lastMessageStatusImageView.hidden = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)fillWithData:(TUIConversationCellData *)convData {
|
||||
self.convData = convData;
|
||||
|
||||
self.titleLabel.textColor = TUIDynamicColor(@"", TUIThemeModuleCore_Minimalist, @"#000000");
|
||||
if ([TUIConversationConfig sharedConfig].cellTitleLabelFont) {
|
||||
self.titleLabel.font = [TUIConversationConfig sharedConfig].cellTitleLabelFont;
|
||||
}
|
||||
|
||||
self.subTitleLabel.attributedText = convData.subTitle;
|
||||
if ([TUIConversationConfig sharedConfig].cellSubtitleLabelFont) {
|
||||
self.subTitleLabel.font = [TUIConversationConfig sharedConfig].cellSubtitleLabelFont;
|
||||
}
|
||||
|
||||
self.timeLabel.text = [TUITool convertDateToStr:convData.time];
|
||||
if ([TUIConversationConfig sharedConfig].cellTimeLabelFont) {
|
||||
self.timeLabel.font = [TUIConversationConfig sharedConfig].cellTimeLabelFont;
|
||||
}
|
||||
|
||||
[self configRedPoint:convData];
|
||||
|
||||
[self configHeadImageView:convData];
|
||||
|
||||
@weakify(self);
|
||||
[[[RACObserve(convData, title) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSString *x) {
|
||||
@strongify(self);
|
||||
self.titleLabel.text = x;
|
||||
}];
|
||||
|
||||
NSString *imageName =
|
||||
(convData.showCheckBox && convData.selected) ? TIMCommonImagePath(@"icon_select_selected") : TIMCommonImagePath(@"icon_select_normal");
|
||||
self.selectedIcon.image = [UIImage imageNamed:imageName];
|
||||
|
||||
UIImage *image =
|
||||
TUIDynamicImage(@"", TUIThemeModuleConversation_Minimalist, [UIImage imageNamed:TUIConversationImagePath_Minimalist(@"message_not_disturb")]);
|
||||
[self.notDisturbView setImage:image];
|
||||
|
||||
[self configOnlineStatusIcon:convData];
|
||||
|
||||
[self configDisplayLastMessageStatusImage:convData];
|
||||
|
||||
// tell constraints they need updating
|
||||
[self setNeedsUpdateConstraints];
|
||||
|
||||
// update constraints now so we can animate the change
|
||||
[self updateConstraintsIfNeeded];
|
||||
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)configHeadImageView:(TUIConversationCellData *)convData {
|
||||
if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) {
|
||||
self.headImageView.layer.masksToBounds = YES;
|
||||
self.headImageView.layer.cornerRadius = self.headImageView.frame.size.height / 2;
|
||||
} else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) {
|
||||
self.headImageView.layer.masksToBounds = YES;
|
||||
self.headImageView.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Setup default avatar
|
||||
*/
|
||||
if (convData.groupID.length > 0) {
|
||||
/**
|
||||
* ,
|
||||
* If it is a group, change the group default avatar to the last used avatar
|
||||
*/
|
||||
UIImage *avatar = nil;
|
||||
if (TUIConfig.defaultConfig.enableGroupGridAvatar) {
|
||||
NSString *key = [NSString stringWithFormat:@"TUIConversationLastGroupMember_%@", convData.groupID];
|
||||
NSInteger member = [NSUserDefaults.standardUserDefaults integerForKey:key];
|
||||
avatar = [TUIGroupAvatar getCacheAvatarForGroup:convData.groupID number:(UInt32)member];
|
||||
}
|
||||
convData.avatarImage = avatar ? avatar : DefaultGroupAvatarImageByGroupType(convData.groupType);
|
||||
;
|
||||
}
|
||||
|
||||
@weakify(self);
|
||||
|
||||
[[RACObserve(convData, faceUrl) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSString *faceUrl) {
|
||||
@strongify(self);
|
||||
if (self.convData.groupID.length > 0) {
|
||||
/**
|
||||
*
|
||||
* Group avatar
|
||||
*/
|
||||
if (IS_NOT_EMPTY_NSSTRING(faceUrl)) {
|
||||
/**
|
||||
*
|
||||
* The group avatar has been manually set externally
|
||||
*/
|
||||
[self.headImageView sd_setImageWithURL:[NSURL URLWithString:faceUrl] placeholderImage:self.convData.avatarImage];
|
||||
} else {
|
||||
/**
|
||||
* The group avatar has not been set externally. If the synthetic avatar is allowed, the synthetic avatar will be used; otherwise, the default
|
||||
* avatar will be used.
|
||||
*/
|
||||
if (TUIConfig.defaultConfig.enableGroupGridAvatar) {
|
||||
/**
|
||||
*
|
||||
* If the synthetic avatar is allowed, the synthetic avatar will be used
|
||||
* 1. Asynchronously obtain the cached synthetic avatar according to the number of group members
|
||||
* 2. If the cache is hit, use the cached synthetic avatar directly
|
||||
* 3. If the cache is not hit, recompose a new avatar
|
||||
*
|
||||
* Note:
|
||||
* 1. Since "asynchronously obtaining cached avatars" and "synthesizing avatars" take a long time, it is easy to cause cell reuse problems, so
|
||||
* it is necessary to confirm whether to assign values directly according to groupID.
|
||||
* 2. Use SDWebImage to implement placeholder, because SDWebImage has already dealt with the problem of cell reuse
|
||||
*/
|
||||
|
||||
// 1. Obtain group avatar from cache
|
||||
|
||||
// fix: The getCacheGroupAvatar needs to request the
|
||||
// network. When the network is disconnected, since the headImageView is not set, the current conversation sends a message, the conversation
|
||||
// is moved up, and the avatar of the first conversation is reused, resulting in confusion of the avatar.
|
||||
[self.headImageView sd_setImageWithURL:nil placeholderImage:convData.avatarImage];
|
||||
[TUIGroupAvatar
|
||||
getCacheGroupAvatar:convData.groupID
|
||||
callback:^(UIImage *avatar, NSString *groupID) {
|
||||
@strongify(self);
|
||||
if ([groupID isEqualToString:self.convData.groupID]) {
|
||||
// 1.1 When the callback is invoked, the cell is not reused
|
||||
|
||||
if (avatar != nil) {
|
||||
// 2. Hit the cache and assign directly
|
||||
[self.headImageView sd_setImageWithURL:nil placeholderImage:avatar];
|
||||
} else {
|
||||
// 3. Synthesize new avatars asynchronously without hitting cache
|
||||
|
||||
[self.headImageView sd_setImageWithURL:nil placeholderImage:convData.avatarImage];
|
||||
[TUIGroupAvatar
|
||||
fetchGroupAvatars:convData.groupID
|
||||
placeholder:convData.avatarImage
|
||||
callback:^(BOOL success, UIImage *image, NSString *groupID) {
|
||||
@strongify(self);
|
||||
if ([groupID isEqualToString:self.convData.groupID]) {
|
||||
// When the callback is invoked, the cell is not reused
|
||||
[self.headImageView
|
||||
sd_setImageWithURL:nil
|
||||
placeholderImage:success ? image
|
||||
: DefaultGroupAvatarImageByGroupType(self.convData.groupType)];
|
||||
} else {
|
||||
// When the callback is invoked, the cell has been reused to other groupIDs.
|
||||
// Since a new callback will be triggered when the new groupID synthesizes new avatar, it is
|
||||
// ignored here
|
||||
}
|
||||
}];
|
||||
}
|
||||
} else {
|
||||
// 1.2 When the callback is invoked, the cell has been reused to other groupIDs. Since a new callback will be triggered
|
||||
// when the new groupID gets the cache, it is ignored here
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
/**
|
||||
* Synthetic avatars are not allowed, use the default avatar directly
|
||||
*/
|
||||
[self.headImageView sd_setImageWithURL:nil placeholderImage:convData.avatarImage];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Personal avatar
|
||||
*/
|
||||
[self.headImageView sd_setImageWithURL:[NSURL URLWithString:faceUrl] placeholderImage:self.convData.avatarImage];
|
||||
}
|
||||
}];
|
||||
}
|
||||
- (void)configRedPoint:(TUIConversationCellData *)convData {
|
||||
if (convData.isNotDisturb) {
|
||||
if (0 == convData.unreadCount) {
|
||||
self.notDisturbRedDot.hidden = YES;
|
||||
} else {
|
||||
self.notDisturbRedDot.hidden = NO;
|
||||
}
|
||||
self.notDisturbView.hidden = NO;
|
||||
self.unReadView.hidden = YES;
|
||||
UIImage *image = TUIConversationBundleThemeImage(@"conversation_message_not_disturb_img", @"message_not_disturb");
|
||||
[self.notDisturbView setImage:image];
|
||||
} else {
|
||||
self.notDisturbRedDot.hidden = YES;
|
||||
self.notDisturbView.hidden = YES;
|
||||
[self.unReadView setNum:convData.unreadCount];
|
||||
self.unReadView.hidden = convData.unreadCount == 0 ? YES : ![TUIConversationConfig sharedConfig].showCellUnreadCount;
|
||||
}
|
||||
|
||||
// Mark As Unread
|
||||
if (convData.isMarkAsUnread) {
|
||||
// When marked as unread, don't care about 'unreadCount', you need to display red dot/number 1 according to whether do not disturb or not
|
||||
if (convData.isNotDisturb) {
|
||||
// Displays a red dot when marked as unread and do not disturb
|
||||
self.notDisturbRedDot.hidden = NO;
|
||||
} else {
|
||||
// Marked unread Show number 1
|
||||
[self.unReadView setNum:1];
|
||||
self.unReadView.hidden = ![TUIConversationConfig sharedConfig].showCellUnreadCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Collapsed group chat No need for Do Not Disturb icon
|
||||
if (convData.isLocalConversationFoldList) {
|
||||
self.notDisturbView.hidden = YES;
|
||||
}
|
||||
}
|
||||
- (void)configOnlineStatusIcon:(TUIConversationCellData *)convData {
|
||||
@weakify(self);
|
||||
[[RACObserve(TUIConfig.defaultConfig, displayOnlineStatusIcon) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(id _Nullable x) {
|
||||
@strongify(self);
|
||||
if (convData.onlineStatus == TUIConversationOnlineStatusOnline && TUIConfig.defaultConfig.displayOnlineStatusIcon) {
|
||||
self.onlineStatusIcon.hidden = NO;
|
||||
self.onlineStatusIcon.image = TIMCommonDynamicImage(@"icon_online_status", [UIImage imageNamed:TIMCommonImagePath(@"icon_online_status")]);
|
||||
} else if (convData.onlineStatus == TUIConversationOnlineStatusOffline && TUIConfig.defaultConfig.displayOnlineStatusIcon) {
|
||||
self.onlineStatusIcon.hidden = YES;
|
||||
self.onlineStatusIcon.image = nil;
|
||||
} else {
|
||||
self.onlineStatusIcon.hidden = YES;
|
||||
self.onlineStatusIcon.image = nil;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)configDisplayLastMessageStatusImage:(TUIConversationCellData *)convData {
|
||||
UIImage *image = [self getDisplayLastMessageStatusImage:convData];
|
||||
self.lastMessageStatusImageView.image = image;
|
||||
}
|
||||
|
||||
- (UIImage *)getDisplayLastMessageStatusImage:(TUIConversationCellData *)convData {
|
||||
UIImage *image = nil;
|
||||
if (!convData.draftText && (V2TIM_MSG_STATUS_SENDING == convData.lastMessage.status || V2TIM_MSG_STATUS_SEND_FAIL == convData.lastMessage.status)) {
|
||||
if (V2TIM_MSG_STATUS_SENDING == convData.lastMessage.status) {
|
||||
image = [UIImage imageNamed:TUIConversationImagePath_Minimalist(@"icon_sendingmark")];
|
||||
} else {
|
||||
image = [UIImage imageNamed:TUIConversationImagePath_Minimalist(@"msg_error_for_conv")];
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// this is Apple's recommended place for adding/updating constraints
|
||||
- (void)updateConstraints {
|
||||
|
||||
[super updateConstraints];
|
||||
|
||||
CGFloat height = [self.convData heightOfWidth:self.mm_w];
|
||||
self.mm_h = height;
|
||||
CGFloat imgHeight = height - 2 * (kScale390(12));
|
||||
|
||||
if (self.convData.isOnTop) {
|
||||
self.contentView.backgroundColor = [TUIConversationConfig sharedConfig].pinnedCellBackgroundColor ? : TUIConversationDynamicColor(@"conversation_cell_top_bg_color", @"#F4F4F4");
|
||||
} else {
|
||||
self.contentView.backgroundColor = [TUIConversationConfig sharedConfig].cellBackgroundColor ? : TUIConversationDynamicColor(@"conversation_cell_bg_color", @"#FFFFFF");
|
||||
}
|
||||
|
||||
CGFloat selectedIconSize = 20;
|
||||
if (self.convData.showCheckBox) {
|
||||
self.selectedIcon.hidden = NO;
|
||||
} else {
|
||||
self.selectedIcon.hidden = YES;
|
||||
}
|
||||
|
||||
[self.selectedIcon mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.convData.showCheckBox) {
|
||||
make.width.height.mas_equalTo(selectedIconSize);
|
||||
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(10);
|
||||
make.centerY.mas_equalTo(self.contentView.mas_centerY);
|
||||
}
|
||||
}];
|
||||
|
||||
[self.headImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(imgHeight);
|
||||
make.centerY.mas_equalTo(self.contentView.mas_centerY);
|
||||
if (self.convData.showCheckBox) {
|
||||
make.leading.mas_equalTo(self.selectedIcon.mas_trailing).mas_offset(kScale390(16));
|
||||
}
|
||||
else {
|
||||
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(kScale390(16));
|
||||
}
|
||||
}];
|
||||
|
||||
if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) {
|
||||
self.headImageView.layer.masksToBounds = YES;
|
||||
self.headImageView.layer.cornerRadius = imgHeight / 2;
|
||||
} else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) {
|
||||
self.headImageView.layer.masksToBounds = YES;
|
||||
self.headImageView.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius;
|
||||
}
|
||||
[self.timeLabel sizeToFit];
|
||||
[self.timeLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(self.timeLabel.frame.size.width);
|
||||
make.height.mas_greaterThanOrEqualTo(self.timeLabel.font.lineHeight);
|
||||
make.top.mas_equalTo(self.subTitleLabel.mas_top);
|
||||
make.trailing.mas_equalTo(self.contentView).mas_offset(- kScale390(8));
|
||||
}];
|
||||
MASAttachKeys(self.timeLabel);
|
||||
|
||||
[self.lastMessageStatusImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(kScale390(14));
|
||||
make.height.mas_equalTo(14);
|
||||
make.trailing.mas_equalTo(self.timeLabel.mas_leading).mas_offset(- (kScale390(1) + kScale390(8)));
|
||||
make.bottom.mas_equalTo(self.timeLabel.mas_bottom);
|
||||
}];
|
||||
MASAttachKeys(self.lastMessageStatusImageView);
|
||||
|
||||
[self.titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_greaterThanOrEqualTo(120);
|
||||
make.height.mas_greaterThanOrEqualTo(self.titleLabel.font.lineHeight);
|
||||
make.top.mas_equalTo(self.contentView.mas_top).mas_offset(kScale390(14));
|
||||
make.leading.mas_equalTo(self.headImageView.mas_trailing).mas_offset(kScale390(8));
|
||||
make.trailing.mas_equalTo(self.timeLabel.mas_leading).mas_offset(- 2*kScale390(14));
|
||||
}];
|
||||
MASAttachKeys(self.titleLabel);
|
||||
|
||||
|
||||
|
||||
[self.subTitleLabel sizeToFit];
|
||||
[self.subTitleLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_greaterThanOrEqualTo(self.subTitleLabel);
|
||||
make.bottom.mas_equalTo(self.contentView).mas_offset(- kScale390(14));
|
||||
make.leading.mas_equalTo(self.titleLabel.mas_leading);
|
||||
make.trailing.mas_equalTo(self.timeLabel.mas_leading).mas_offset(-kScale390(8));
|
||||
}];
|
||||
MASAttachKeys(self.subTitleLabel);
|
||||
|
||||
[self.unReadView.unReadLabel sizeToFit];
|
||||
[self.unReadView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.timeLabel.mas_trailing);
|
||||
make.top.mas_equalTo(self.titleLabel.mas_top);
|
||||
make.width.mas_equalTo(kScale375(18));
|
||||
make.height.mas_equalTo(kScale375(18));
|
||||
}];
|
||||
[self.unReadView.unReadLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.unReadView);
|
||||
make.size.mas_equalTo(self.unReadView.unReadLabel);
|
||||
}];
|
||||
self.unReadView.layer.cornerRadius = kScale375(18) * 0.5;
|
||||
[self.unReadView.layer masksToBounds];
|
||||
|
||||
[self.notDisturbRedDot mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.headImageView.mas_trailing).mas_offset(3);
|
||||
make.top.mas_equalTo(self.headImageView.mas_top).mas_offset(1);
|
||||
make.width.height.mas_equalTo(TConversationCell_Margin_Disturb_Dot);
|
||||
}];
|
||||
|
||||
[self.notDisturbView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(TConversationCell_Margin_Disturb);
|
||||
make.trailing.mas_equalTo(self.timeLabel.mas_trailing);
|
||||
make.top.mas_equalTo(self.titleLabel.mas_top);
|
||||
}];
|
||||
|
||||
[self.onlineStatusIcon mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(kScale375(15));
|
||||
make.leading.mas_equalTo(self.headImageView.mas_trailing).mas_offset(-kScale375(10));
|
||||
make.bottom.mas_equalTo(self.headImageView.mas_bottom).mas_offset(-kScale375(1));
|
||||
}];
|
||||
|
||||
self.onlineStatusIcon.layer.cornerRadius = 0.5 *kScale375(15);
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// TUIConversationForwardSelectCell_Minimalist.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2023/1/31.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationCell_Minimalist.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationForwardSelectCell_Minimalist : UITableViewCell
|
||||
@property(nonatomic, strong) UIButton *selectButton;
|
||||
@property(nonatomic, strong) UIImageView *avatarView;
|
||||
@property(nonatomic, strong) UILabel *titleLabel;
|
||||
@property(nonatomic, strong) TUIConversationCellData *selectData;
|
||||
|
||||
- (void)fillWithData:(TUIConversationCellData *)selectData;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// TUIConversationForwardSelectCell_Minimalist.m
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2023/1/31.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationForwardSelectCell_Minimalist.h"
|
||||
#import <TIMCommon/TUIGroupAvatar+Helper.h>
|
||||
@interface TUIConversationForwardSelectCell_Minimalist ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIConversationForwardSelectCell_Minimalist
|
||||
- (void)setFrame:(CGRect)frame {
|
||||
frame.size.width = Screen_Width;
|
||||
[super setFrame:frame];
|
||||
}
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
if (self) {
|
||||
self.selectButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[self.contentView addSubview:self.selectButton];
|
||||
[self.selectButton setImage:[UIImage imageNamed:TIMCommonImagePath(@"icon_select_normal")] forState:UIControlStateNormal];
|
||||
[self.selectButton setImage:[UIImage imageNamed:TIMCommonImagePath(@"icon_select_pressed")] forState:UIControlStateHighlighted];
|
||||
[self.selectButton setImage:[UIImage imageNamed:TIMCommonImagePath(@"icon_select_selected")] forState:UIControlStateSelected];
|
||||
[self.selectButton setImage:[UIImage imageNamed:TIMCommonImagePath(@"icon_select_selected_disable")] forState:UIControlStateDisabled];
|
||||
self.selectButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
self.selectButton.userInteractionEnabled = NO;
|
||||
|
||||
self.avatarView = [[UIImageView alloc] initWithImage:DefaultAvatarImage];
|
||||
[self.contentView addSubview:self.avatarView];
|
||||
self.avatarView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
|
||||
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||
[self.contentView addSubview:self.titleLabel];
|
||||
self.titleLabel.textColor = TIMCommonDynamicColor(@"form_title_color", @"#000000");
|
||||
|
||||
self.titleLabel.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// this is Apple's recommended place for adding/updating constraints
|
||||
- (void)updateConstraints {
|
||||
|
||||
[super updateConstraints];
|
||||
CGFloat imgWidth = kScale390(40);
|
||||
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(imgWidth);
|
||||
make.centerY.mas_equalTo(self.contentView.mas_centerY);
|
||||
make.leading.mas_equalTo(kScale390(16));
|
||||
}];
|
||||
if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) {
|
||||
self.avatarView.layer.masksToBounds = YES;
|
||||
self.avatarView.layer.cornerRadius = imgWidth / 2;
|
||||
} else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) {
|
||||
self.avatarView.layer.masksToBounds = YES;
|
||||
self.avatarView.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius;
|
||||
}
|
||||
|
||||
[self.selectButton sizeToFit];
|
||||
[self.selectButton mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(self.contentView.mas_centerY);
|
||||
make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-kScale390(42));
|
||||
make.size.mas_equalTo(self.selectButton.frame.size);
|
||||
}];
|
||||
[self.titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(self.avatarView.mas_centerY);
|
||||
make.leading.mas_equalTo(self.avatarView.mas_trailing).mas_offset(12);
|
||||
make.height.mas_equalTo(20);
|
||||
make.trailing.mas_greaterThanOrEqualTo(self.contentView.mas_trailing);
|
||||
|
||||
}];
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)fillWithData:(TUIConversationCellData *)selectData {
|
||||
self.selectData = selectData;
|
||||
self.titleLabel.text = selectData.title;
|
||||
[self configHeadImageView:selectData];
|
||||
[self.selectButton setSelected:selectData.selected];
|
||||
if (selectData.showCheckBox) {
|
||||
self.selectButton.hidden = NO;
|
||||
} else {
|
||||
self.selectButton.hidden = YES;
|
||||
}
|
||||
|
||||
// tell constraints they need updating
|
||||
[self setNeedsUpdateConstraints];
|
||||
|
||||
// update constraints now so we can animate the change
|
||||
[self updateConstraintsIfNeeded];
|
||||
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)configHeadImageView:(TUIConversationCellData *)convData {
|
||||
/**
|
||||
* Setup default avatar
|
||||
*/
|
||||
if (convData.groupID.length > 0) {
|
||||
/**
|
||||
* If it is a group, change the group default avatar to the last used avatar
|
||||
*/
|
||||
convData.avatarImage = [TUIGroupAvatar getNormalGroupCacheAvatar:convData.groupID groupType:convData.groupType];
|
||||
}
|
||||
|
||||
@weakify(self);
|
||||
|
||||
[[RACObserve(convData, faceUrl) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSString *faceUrl) {
|
||||
@strongify(self);
|
||||
NSString *groupID = convData.groupID ?: @"";
|
||||
NSString *pFaceUrl = convData.faceUrl ?: @"";
|
||||
NSString *groupType = convData.groupType ?: @"";
|
||||
UIImage *originAvatarImage = nil;
|
||||
if (convData.groupID.length > 0) {
|
||||
originAvatarImage = convData.avatarImage ?: DefaultGroupAvatarImageByGroupType(groupType);
|
||||
} else {
|
||||
originAvatarImage = convData.avatarImage ?: DefaultAvatarImage;
|
||||
}
|
||||
NSDictionary *param = @{
|
||||
@"groupID" : groupID,
|
||||
@"faceUrl" : pFaceUrl,
|
||||
@"groupType" : groupType,
|
||||
@"originAvatarImage" : originAvatarImage,
|
||||
};
|
||||
[TUIGroupAvatar configAvatarByParam:param targetView:self.avatarView];
|
||||
}];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TUIConversationListDataProvider.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by harvy on 2022/7/14.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TUIConversationListBaseDataProvider.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationListDataProvider_Minimalist : TUIConversationListBaseDataProvider
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// V2TUIConversationListDataProvider.m
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by harvy on 2022/7/14.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationListDataProvider_Minimalist.h"
|
||||
#import <TIMCommon/NSString+TUIEmoji.h>
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
#import "TUIConversationCellData_Minimalist.h"
|
||||
|
||||
@implementation TUIConversationListDataProvider_Minimalist
|
||||
- (Class)getConversationCellClass {
|
||||
return [TUIConversationCellData_Minimalist class];
|
||||
}
|
||||
|
||||
- (void)asnycGetLastMessageDisplay:(NSArray<TUIConversationCellData *> *)duplicateDataList addedDataList:(NSArray<TUIConversationCellData *> *)addedDataList {
|
||||
NSMutableArray *allConversationList = [NSMutableArray array];
|
||||
[allConversationList addObjectsFromArray:duplicateDataList];
|
||||
[allConversationList addObjectsFromArray:addedDataList];
|
||||
|
||||
NSMutableArray *messageList = [NSMutableArray array];
|
||||
for (TUIConversationCellData *cellData in allConversationList) {
|
||||
if (cellData.lastMessage && cellData.lastMessage.msgID) {
|
||||
[messageList addObject:cellData.lastMessage];
|
||||
}
|
||||
}
|
||||
|
||||
if (messageList.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
NSDictionary *param = @{TUICore_TUIChatService_AsyncGetDisplayStringMethod_MsgListKey : messageList};
|
||||
[TUICore callService:TUICore_TUIChatService_Minimalist
|
||||
method:TUICore_TUIChatService_AsyncGetDisplayStringMethod
|
||||
param:param
|
||||
resultCallback:^(NSInteger errorCode, NSString *_Nonnull errorMessage, NSDictionary *_Nonnull param) {
|
||||
if (0 != errorCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cache
|
||||
NSMutableDictionary *dictM = [NSMutableDictionary dictionaryWithDictionary:weakSelf.lastMessageDisplayMap];
|
||||
[param enumerateKeysAndObjectsUsingBlock:^(NSString *msgID, NSString *displayString, BOOL *_Nonnull stop) {
|
||||
[dictM setObject:displayString forKey:msgID];
|
||||
}];
|
||||
weakSelf.lastMessageDisplayMap = [NSDictionary dictionaryWithDictionary:dictM];
|
||||
|
||||
// Refresh if needed
|
||||
NSMutableArray *needRefreshConvList = [NSMutableArray array];
|
||||
for (TUIConversationCellData *cellData in allConversationList) {
|
||||
if (cellData.lastMessage && cellData.lastMessage.msgID && [param.allKeys containsObject:cellData.lastMessage.msgID]) {
|
||||
cellData.subTitle = [self getLastDisplayString:cellData.innerConversation];
|
||||
cellData.foldSubTitle = [self getLastDisplayStringForFoldList:cellData.innerConversation];
|
||||
[needRefreshConvList addObject:cellData];
|
||||
}
|
||||
}
|
||||
NSMutableDictionary<NSString *, NSNumber *> *conversationMap = [NSMutableDictionary dictionary];
|
||||
for (TUIConversationCellData *item in weakSelf.conversationList) {
|
||||
if (item.conversationID) {
|
||||
[conversationMap setObject:@([weakSelf.conversationList indexOfObject:item]) forKey:item.conversationID];
|
||||
}
|
||||
}
|
||||
[weakSelf handleUpdateConversationList:needRefreshConvList positions:conversationMap];
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)getDisplayStringFromService:(V2TIMMessage *)msg {
|
||||
// from cache
|
||||
NSString *displayString = [self.lastMessageDisplayMap objectForKey:msg.msgID];
|
||||
if (displayString.length > 0) {
|
||||
return displayString;
|
||||
}
|
||||
|
||||
// from TUIChat
|
||||
NSDictionary *param = @{TUICore_TUIChatService_GetDisplayStringMethod_MsgKey : msg};
|
||||
return [TUICore callService:TUICore_TUIChatService_Minimalist method:TUICore_TUIChatService_GetDisplayStringMethod param:param];
|
||||
}
|
||||
|
||||
- (NSMutableAttributedString *)getLastDisplayString:(V2TIMConversation *)conv {
|
||||
/**
|
||||
* If has group-at message, the group-at information will be displayed first
|
||||
*/
|
||||
NSString *atStr = [self getGroupAtTipString:conv];
|
||||
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:atStr];
|
||||
NSDictionary *attributeDict = @{NSForegroundColorAttributeName : [UIColor d_systemRedColor]};
|
||||
[attributeString setAttributes:attributeDict range:NSMakeRange(0, attributeString.length)];
|
||||
BOOL hasRiskContent = conv.lastMessage.hasRiskContent;
|
||||
BOOL isRevoked = (conv.lastMessage.status == V2TIM_MSG_STATUS_LOCAL_REVOKED);
|
||||
|
||||
/**
|
||||
* If there is a draft box, the draft box information will be displayed first
|
||||
*/
|
||||
if (conv.draftText.length > 0) {
|
||||
NSAttributedString *draft = [[NSAttributedString alloc] initWithString:TIMCommonLocalizableString(TUIKitMessageTypeDraftFormat)
|
||||
attributes:@{NSForegroundColorAttributeName : RGB(250, 81, 81)}];
|
||||
[attributeString appendAttributedString:draft];
|
||||
|
||||
NSString *draftContentStr = [self getDraftContent:conv];
|
||||
draftContentStr = [draftContentStr getLocalizableStringWithFaceContent];
|
||||
NSAttributedString *draftContent = [[NSAttributedString alloc] initWithString:draftContentStr
|
||||
attributes:@{NSForegroundColorAttributeName : [UIColor d_systemGrayColor]}];
|
||||
[attributeString appendAttributedString:draftContent];
|
||||
} else {
|
||||
/**
|
||||
* No drafts, show conversation lastMsg information
|
||||
*/
|
||||
NSString *lastMsgStr = @"";
|
||||
|
||||
/**
|
||||
* Attempt to get externally customized display information
|
||||
*/
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(getConversationDisplayString:)]) {
|
||||
lastMsgStr = [self.delegate getConversationDisplayString:conv];
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no external customization, get the lastMsg display information through the message module
|
||||
*/
|
||||
if (lastMsgStr.length == 0 && conv.lastMessage) {
|
||||
lastMsgStr = [self getDisplayStringFromService:conv.lastMessage];
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no lastMsg display information and no draft information, return nil directly
|
||||
*/
|
||||
if (lastMsgStr.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
if (hasRiskContent && !isRevoked) {
|
||||
[attributeString appendAttributedString:[[NSAttributedString alloc] initWithString:lastMsgStr
|
||||
attributes:@{NSForegroundColorAttributeName : RGB(233, 68, 68)}]];
|
||||
} else {
|
||||
[attributeString appendAttributedString:[[NSAttributedString alloc] initWithString:lastMsgStr]];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* If do-not-disturb is set, the message do-not-disturb state is displayed
|
||||
* The default state of the meeting type group is V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE, and the UI does not process it.
|
||||
*/
|
||||
if ([self isConversationNotDisturb:conv] && conv.unreadCount > 0) {
|
||||
NSAttributedString *unreadString = [[NSAttributedString alloc]
|
||||
initWithString:[NSString stringWithFormat:@"[%d %@] ", conv.unreadCount, TIMCommonLocalizableString(TUIKitMessageTypeLastMsgCountFormat)]];
|
||||
[attributeString insertAttributedString:unreadString atIndex:0];
|
||||
}
|
||||
|
||||
return attributeString;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TUIConversationListDataProvider.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by harvy on 2022/7/14.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TUIConversationSelectBaseDataProvider.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationSelectDataProvider_Minimalist : TUIConversationSelectBaseDataProvider
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TUIConversationSelectModel.m
|
||||
// TXIMSDK_TUIKit_iOS
|
||||
//
|
||||
// Created by xiangzhang on 2021/6/25.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationSelectDataProvider_Minimalist.h"
|
||||
#import "TUIConversationCellData_Minimalist.h"
|
||||
|
||||
@implementation TUIConversationSelectDataProvider_Minimalist
|
||||
|
||||
- (Class)getConversationCellClass {
|
||||
return [TUIConversationCellData_Minimalist class];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TUIFoldConversationListDataProvider_Minimalist.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2022/11/22.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIFoldConversationListBaseDataProvider.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIFoldConversationListDataProvider_Minimalist : TUIFoldConversationListBaseDataProvider
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// TUIFoldConversationListDataProvider_Minimalist.m
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2022/11/22.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIFoldConversationListDataProvider_Minimalist.h"
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
#import "TUIConversationCellData_Minimalist.h"
|
||||
#import <TIMCommon/NSString+TUIEmoji.h>
|
||||
|
||||
@implementation TUIFoldConversationListDataProvider_Minimalist
|
||||
|
||||
- (Class)getConversationCellClass {
|
||||
return [TUIConversationCellData_Minimalist class];
|
||||
}
|
||||
|
||||
- (NSString *)getDisplayStringFromService:(V2TIMMessage *)msg {
|
||||
NSDictionary *param = @{TUICore_TUIChatService_GetDisplayStringMethod_MsgKey : msg};
|
||||
return [TUICore callService:TUICore_TUIChatService_Minimalist method:TUICore_TUIChatService_GetDisplayStringMethod param:param];
|
||||
}
|
||||
- (NSMutableAttributedString *)getLastDisplayString:(V2TIMConversation *)conv {
|
||||
/**
|
||||
* If has group-at message, the group-at information will be displayed first
|
||||
*/
|
||||
NSString *atStr = [self getGroupAtTipString:conv];
|
||||
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:atStr];
|
||||
NSDictionary *attributeDict = @{NSForegroundColorAttributeName : [UIColor d_systemRedColor]};
|
||||
[attributeString setAttributes:attributeDict range:NSMakeRange(0, attributeString.length)];
|
||||
|
||||
/**
|
||||
* If there is a draft box, the draft box information will be displayed first
|
||||
*/
|
||||
if (conv.draftText.length > 0) {
|
||||
NSAttributedString *draft = [[NSAttributedString alloc] initWithString:TIMCommonLocalizableString(TUIKitMessageTypeDraftFormat)
|
||||
attributes:@{NSForegroundColorAttributeName : RGB(250, 81, 81)}];
|
||||
[attributeString appendAttributedString:draft];
|
||||
|
||||
NSString *draftContentStr = [self getDraftContent:conv];
|
||||
draftContentStr = [draftContentStr getLocalizableStringWithFaceContent];
|
||||
NSAttributedString *draftContent = [[NSAttributedString alloc] initWithString:draftContentStr
|
||||
attributes:@{NSForegroundColorAttributeName : [UIColor d_systemGrayColor]}];
|
||||
[attributeString appendAttributedString:draftContent];
|
||||
} else {
|
||||
/**
|
||||
* No drafts, show conversation lastMsg information
|
||||
*/
|
||||
NSString *lastMsgStr = @"";
|
||||
|
||||
/**
|
||||
* Attempt to get externally customized display information
|
||||
*/
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(getConversationDisplayString:)]) {
|
||||
lastMsgStr = [self.delegate getConversationDisplayString:conv];
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no external customization, get the lastMsg display information through the message module
|
||||
*/
|
||||
if (lastMsgStr.length == 0 && conv.lastMessage) {
|
||||
lastMsgStr = [self getDisplayStringFromService:conv.lastMessage];
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no lastMsg display information and no draft information, return nil directly
|
||||
*/
|
||||
if (lastMsgStr.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
[attributeString appendAttributedString:[[NSAttributedString alloc] initWithString:lastMsgStr]];
|
||||
}
|
||||
|
||||
/**
|
||||
* If do-not-disturb is set, the message do-not-disturb state is displayed
|
||||
* The default state of the meeting type group is V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE, and the UI does not process it.
|
||||
*/
|
||||
if ([self isConversationNotDisturb:conv] && conv.unreadCount > 0) {
|
||||
NSAttributedString *unreadString = [[NSAttributedString alloc]
|
||||
initWithString:[NSString stringWithFormat:@"[%d %@] ", conv.unreadCount, TIMCommonLocalizableString(TUIKitMessageTypeLastMsgCountFormat)]];
|
||||
[attributeString insertAttributedString:unreadString atIndex:0];
|
||||
}
|
||||
|
||||
return attributeString;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// TUIConversation_Minimalist.h
|
||||
// Pods
|
||||
//
|
||||
// Created by harvy on 2022/6/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef TUIConversation_Minimalist_h
|
||||
#define TUIConversation_Minimalist_h
|
||||
|
||||
#import "TUIConversationListController_Minimalist.h"
|
||||
#import "TUIConversationSelectController_Minimalist.h"
|
||||
|
||||
#endif /* TUIConversation_Minimalist_h */
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// TUIConversationObjectFactory_Minimalist.h
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2023/3/29.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* TUIConversationService currently provides two services:
|
||||
* 1. Create a conversation list
|
||||
* 2. Create a conversation selector
|
||||
*
|
||||
* You can call the service through the [TUICore createObject:..] method. The different service parameters are as follows:
|
||||
* > Create a conversation list:
|
||||
* factoryName: TUICore_TUIConversationObjectFactory_Minimalist
|
||||
* key: TUICore_TUIConversationObjectFactory_GetConversationControllerMethod
|
||||
*
|
||||
* > Create conversation selector:
|
||||
* factoryName: TUICore_TUIConversationObjectFactory_Minimalist
|
||||
* key: TUICore_TUIConversationObjectFactory_ConversationSelectVC_Minimalist
|
||||
*
|
||||
*/
|
||||
@interface TUIConversationObjectFactory_Minimalist : NSObject
|
||||
+ (TUIConversationObjectFactory_Minimalist *)shareInstance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// TUIConversationObjectFactory_Minimalist.m
|
||||
// TUIConversation
|
||||
//
|
||||
// Created by wyl on 2023/3/29.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationObjectFactory_Minimalist.h"
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIConversationListController_Minimalist.h"
|
||||
#import "TUIConversationSelectController_Minimalist.h"
|
||||
|
||||
@interface TUIConversationObjectFactory_Minimalist () <TUIObjectProtocol>
|
||||
@end
|
||||
|
||||
@implementation TUIConversationObjectFactory_Minimalist
|
||||
+ (void)load {
|
||||
[TUICore registerObjectFactory:TUICore_TUIConversationObjectFactory_Minimalist objectFactory:[TUIConversationObjectFactory_Minimalist shareInstance]];
|
||||
}
|
||||
+ (TUIConversationObjectFactory_Minimalist *)shareInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static TUIConversationObjectFactory_Minimalist *g_sharedInstance = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
g_sharedInstance = [[TUIConversationObjectFactory_Minimalist alloc] init];
|
||||
});
|
||||
return g_sharedInstance;
|
||||
}
|
||||
|
||||
#pragma mark - TUIObjectProtocol
|
||||
- (id)onCreateObject:(NSString *)method param:(nullable NSDictionary *)param {
|
||||
if ([method isEqualToString:TUICore_TUIConversationObjectFactory_GetConversationControllerMethod]) {
|
||||
return [self createConversationController];
|
||||
} else if ([method isEqualToString:TUICore_TUIConversationObjectFactory_ConversationSelectVC_Minimalist]) {
|
||||
return [self createConversationSelectController];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UIViewController *)createConversationController {
|
||||
return [[TUIConversationListController_Minimalist alloc] init];
|
||||
}
|
||||
|
||||
- (UIViewController *)createConversationSelectController {
|
||||
return [[TUIConversationSelectController_Minimalist alloc] init];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationService_Minimalist : NSObject
|
||||
|
||||
+ (TUIConversationService_Minimalist *)shareInstance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
|
||||
#import "TUIConversationService_Minimalist.h"
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
|
||||
@implementation TUIConversationService_Minimalist
|
||||
|
||||
+ (void)load {
|
||||
TUIRegisterThemeResourcePath(TUIBundlePath(@"TUIConversationTheme_Minimalist", TUIConversationBundle_Key_Class), TUIThemeModuleConversation_Minimalist);
|
||||
}
|
||||
|
||||
+ (TUIConversationService_Minimalist *)shareInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static TUIConversationService_Minimalist *g_sharedInstance = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
g_sharedInstance = [[TUIConversationService_Minimalist alloc] init];
|
||||
});
|
||||
return g_sharedInstance;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Tencent Cloud Communication Service Interface Component TUIKIT - Conversation List Component.
|
||||
*
|
||||
* This file declares the view component of the conversation list.
|
||||
* The conversation list component can display brief information of each conversation in the order of the time when new messages are sent (newer messages are
|
||||
* sorted earlier). The conversation information displayed in the conversation list includes:
|
||||
* 1. Avatar information (user avatar/group avatar)
|
||||
* 2. Conversation title (user nickname/group name)
|
||||
* 3. Conversation message overview (display the latest message content)
|
||||
* 4. The number of unread messages (if there are unread messages)
|
||||
* 5. Conversation time (receive/send time of the latest message)
|
||||
* The conversation information displayed in the conversation list is implemented by TUIConversationCell. For details, please refer to
|
||||
* TUIConversation\Cell\CellUI\TUIConversationCell.h
|
||||
*/
|
||||
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TUIConversationCell.h"
|
||||
#import "TUIConversationListControllerListener.h"
|
||||
#import "TUIConversationListDataProvider_Minimalist.h"
|
||||
#import "TUIConversationMultiChooseView_Minimalist.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
*
|
||||
* 【Module name】 message list interface component (TUIConversationListController_Minimalist)
|
||||
*
|
||||
* 【Function description】 It is responsible for displaying each conversation in the order in which the messages are received, and responding to the user's
|
||||
* operation, providing users with multi-session management functions. The conversation information displayed in the conversation list includes:
|
||||
* 1. Avatar information (user avatar/group avatar)
|
||||
* 2. Conversation title (user nickname/group name)
|
||||
* 3. Conversation message overview (display the latest message content)
|
||||
* 4. The number of unread messages (if there are unread messages)
|
||||
* 5. Conversation time (receive/send time of the latest message)
|
||||
*/
|
||||
@interface TUIConversationListController_Minimalist : UIViewController
|
||||
|
||||
@property(nonatomic, strong) UITableView *tableView;
|
||||
|
||||
@property(nonatomic, strong) TUIConversationMultiChooseView_Minimalist *multiChooseView;
|
||||
|
||||
@property(nonatomic, weak) id<TUIConversationListControllerListener> delegate;
|
||||
|
||||
@property(nonatomic, strong) TUIConversationListBaseDataProvider *dataProvider;
|
||||
|
||||
@property(nonatomic) BOOL isShowBanner;
|
||||
|
||||
@property(nonatomic, copy) void (^dataSourceChanged)(NSInteger count);
|
||||
|
||||
- (void)openMultiChooseBoard:(BOOL)open;
|
||||
|
||||
- (void)enableMultiSelectedMode:(BOOL)enable;
|
||||
|
||||
- (NSArray<TUIConversationCellData *> *)getMultiSelectedResult;
|
||||
|
||||
- (void)startConversation:(V2TIMConversationType)type;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,989 @@
|
||||
//
|
||||
// TUIConversationListController_Minimalist.m
|
||||
// TXIMSDK_TUIKit_iOS
|
||||
//
|
||||
// Created by annidyfeng on 2019/5/17.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationListController_Minimalist.h"
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TIMCommon/TUIFloatViewController.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import "TUIConversationCellData_Minimalist.h"
|
||||
#import "TUIConversationCell_Minimalist.h"
|
||||
#import "TUIFoldListViewController_Minimalist.h"
|
||||
#import "TUIConversationConfig.h"
|
||||
|
||||
static NSString *kConversationCell_Minimalist_ReuseId = @"kConversationCell_Minimalist_ReuseId";
|
||||
|
||||
@interface TUIConversationListController_Minimalist () <UIGestureRecognizerDelegate,
|
||||
UITableViewDelegate,
|
||||
UITableViewDataSource,
|
||||
UIPopoverPresentationControllerDelegate,
|
||||
TUINotificationProtocol,
|
||||
TUIConversationListDataProviderDelegate,
|
||||
TUIPopViewDelegate>
|
||||
@property(nonatomic, strong) UIBarButtonItem *moreItem;
|
||||
@property(nonatomic, strong) UIBarButtonItem *editItem;
|
||||
@property(nonatomic, strong) UIBarButtonItem *doneItem;
|
||||
@property(nonatomic, assign) BOOL showCheckBox;
|
||||
@end
|
||||
|
||||
@implementation TUIConversationListController_Minimalist
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.isShowBanner = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Life Cycle
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self setupNavigation];
|
||||
[self setupViews];
|
||||
[self.dataProvider loadNexPageConversations];
|
||||
self.showCheckBox = NO;
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(onFriendInfoChanged:) name:@"FriendInfoChangedNotification" object:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(startCreatGroupNotification:)
|
||||
name:@"kTUIConversationCreatGroupNotification"
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[TUICore unRegisterEventByObject:self];
|
||||
}
|
||||
|
||||
- (UIColor *)navBackColor {
|
||||
return [UIColor whiteColor];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
if (@available(iOS 15.0, *)) {
|
||||
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
|
||||
[appearance configureWithDefaultBackground];
|
||||
appearance.shadowColor = nil;
|
||||
appearance.backgroundEffect = nil;
|
||||
appearance.backgroundColor = [self navBackColor];
|
||||
UINavigationBar *navigationBar = self.navigationController.navigationBar;
|
||||
navigationBar.backgroundColor = [self navBackColor];
|
||||
navigationBar.barTintColor = [self navBackColor];
|
||||
navigationBar.shadowImage = [UIImage new];
|
||||
navigationBar.standardAppearance = appearance;
|
||||
navigationBar.scrollEdgeAppearance = appearance;
|
||||
} else {
|
||||
UINavigationBar *navigationBar = self.navigationController.navigationBar;
|
||||
navigationBar.backgroundColor = [self navBackColor];
|
||||
navigationBar.barTintColor = [self navBackColor];
|
||||
navigationBar.shadowImage = [UIImage new];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onFriendInfoChanged:(NSNotification *)notice {
|
||||
V2TIMFriendInfo *friendInfo = notice.object;
|
||||
if (friendInfo == nil) {
|
||||
return;
|
||||
}
|
||||
for (TUIConversationCellData *cellData in self.dataProvider.conversationList) {
|
||||
if ([cellData.userID isEqualToString:friendInfo.userID]) {
|
||||
NSString *title = friendInfo.friendRemark;
|
||||
if (title.length == 0) {
|
||||
title = friendInfo.userFullInfo.nickName;
|
||||
}
|
||||
if (title.length == 0) {
|
||||
title = friendInfo.userID;
|
||||
}
|
||||
cellData.title = title;
|
||||
[self.tableView reloadData];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupNavigation {
|
||||
UIButton *editButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[editButton setImage:[UIImage imageNamed:TUIConversationImagePath_Minimalist(@"nav_edit")] forState:UIControlStateNormal];
|
||||
[editButton addTarget:self action:@selector(editBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
editButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[editButton setFrame:CGRectMake(0, 0, 18 + 21 * 2, 18)];
|
||||
|
||||
UIButton *moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[moreButton setImage:[UIImage imageNamed:TUIConversationImagePath_Minimalist(@"nav_add")] forState:UIControlStateNormal];
|
||||
[moreButton addTarget:self action:@selector(rightBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
moreButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[moreButton setFrame:CGRectMake(0, 0, 20, 20)];
|
||||
|
||||
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[doneButton setTitle:TIMCommonLocalizableString(TUIKitDone) forState:UIControlStateNormal];
|
||||
[doneButton setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
|
||||
[doneButton addTarget:self action:@selector(doneBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[doneButton setFrame:CGRectMake(0, 0, 30, 30)];
|
||||
|
||||
self.editItem = [[UIBarButtonItem alloc] initWithCustomView:editButton];
|
||||
self.moreItem = [[UIBarButtonItem alloc] initWithCustomView:moreButton];
|
||||
self.doneItem = [[UIBarButtonItem alloc] initWithCustomView:doneButton];
|
||||
|
||||
self.navigationItem.rightBarButtonItems = @[ self.moreItem, self.editItem ];
|
||||
|
||||
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
|
||||
self.navigationController.interactivePopGestureRecognizer.delegate = self;
|
||||
}
|
||||
|
||||
- (void)setupViews {
|
||||
self.view.backgroundColor = [TUIConversationConfig sharedConfig].listBackgroundColor ? : TUIConversationDynamicColor(@"conversation_bg_color", @"#FFFFFF");
|
||||
CGRect rect = self.view.bounds;
|
||||
_tableView = [[UITableView alloc] initWithFrame:rect];
|
||||
_tableView.tableFooterView = [[UIView alloc] init];
|
||||
_tableView.backgroundColor = self.view.backgroundColor;
|
||||
_tableView.contentInset = UIEdgeInsetsMake(0, 0, 8, 0);
|
||||
[_tableView registerClass:[TUIConversationCell_Minimalist class] forCellReuseIdentifier:kConversationCell_Minimalist_ReuseId];
|
||||
_tableView.delegate = self;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.estimatedRowHeight = 0;
|
||||
_tableView.rowHeight = kScale390(64.0);
|
||||
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
_tableView.delaysContentTouches = NO;
|
||||
[self.view addSubview:_tableView];
|
||||
|
||||
if (self.isShowBanner) {
|
||||
CGSize size = CGSizeMake(self.view.bounds.size.width, 60);
|
||||
UIView *bannerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
||||
self.tableView.tableHeaderView = bannerView;
|
||||
NSMutableDictionary *param = [NSMutableDictionary dictionary];
|
||||
param[TUICore_TUIConversationExtension_ConversationListBanner_BannerSize] = NSStringFromCGSize(size);
|
||||
param[TUICore_TUIConversationExtension_ConversationListBanner_ModalVC] = self;
|
||||
BOOL isResponserExist = [TUICore raiseExtension:TUICore_TUIConversationExtension_ConversationListBanner_MinimalistExtensionID
|
||||
parentView:bannerView
|
||||
param:param];
|
||||
if (!isResponserExist) {
|
||||
self.tableView.tableHeaderView = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doneBarButtonClick:(UIBarButtonItem *)doneBarButton {
|
||||
[self openMultiChooseBoard:NO];
|
||||
self.navigationItem.rightBarButtonItems = @[ self.moreItem, self.editItem ];
|
||||
}
|
||||
|
||||
- (void)editBarButtonClick:(UIButton *)editBarButton {
|
||||
[self openMultiChooseBoard:YES];
|
||||
[self enableMultiSelectedMode:YES];
|
||||
self.navigationItem.rightBarButtonItems = @[ self.doneItem ];
|
||||
}
|
||||
|
||||
- (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 = StatusBar_Height + NavBar_Height;
|
||||
CGFloat orginX = Screen_Width - 155;
|
||||
if(isRTL()){
|
||||
orginX = 10;
|
||||
}
|
||||
TUIPopView *popView = [[TUIPopView alloc] initWithFrame:CGRectMake(orginX, 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];
|
||||
}
|
||||
|
||||
#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 {
|
||||
TUIFloatViewController *floatVC = [[TUIFloatViewController alloc] init];
|
||||
|
||||
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 ?: DefaultAvatarImage,
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AvatarUrl : array.firstObject.avatarUrl.absoluteString ?: @""
|
||||
};
|
||||
[self.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Minimalist param:param forResult:nil];
|
||||
} else {
|
||||
@weakify(self);
|
||||
NSString *loginUser = [[V2TIMManager sharedInstance] getLoginUser];
|
||||
[[V2TIMManager sharedInstance]
|
||||
getUsersInfo:@[ loginUser ]
|
||||
succ:^(NSArray<V2TIMUserFullInfo *> *infoList) {
|
||||
@strongify(self);
|
||||
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 *, UIImage *) = ^(BOOL isSuccess, V2TIMGroupInfo *_Nonnull info,
|
||||
UIImage *_Nonnull submitShowImage) {
|
||||
NSDictionary *param = @{
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_Title : info.groupName ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_GroupID : info.groupID ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AvatarUrl : info.faceURL ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AvatarImage : submitShowImage ?: [UIImage new],
|
||||
};
|
||||
[self.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Minimalist 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];
|
||||
}
|
||||
}
|
||||
|
||||
self.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_Minimalist
|
||||
key:TUICore_TUIContactObjectFactory_GetGroupCreateControllerMethod
|
||||
param:param];
|
||||
|
||||
TUIFloatViewController *afloatVC = [[TUIFloatViewController alloc] init];
|
||||
[afloatVC appendChildViewController:groupVC topMargin:kScale390(87.5)];
|
||||
[afloatVC.topGestureView setTitleText:TIMCommonLocalizableString(ChatsNewGroupText)
|
||||
subTitleText:@""
|
||||
leftBtnText:TIMCommonLocalizableString(TUIKitCreateCancel)
|
||||
rightBtnText:TIMCommonLocalizableString(TUIKitCreateFinish)];
|
||||
[self presentViewController:afloatVC animated:YES completion:nil];
|
||||
}
|
||||
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_Minimalist
|
||||
key:TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod
|
||||
param:param];
|
||||
[floatVC appendChildViewController:vc topMargin:kScale390(87.5)];
|
||||
[floatVC.topGestureView setTitleText:((V2TIM_C2C == type)) ? TIMCommonLocalizableString(ChatsNewChatText) : TIMCommonLocalizableString(ChatsNewGroupText)
|
||||
subTitleText:@""
|
||||
leftBtnText:TIMCommonLocalizableString(TUIKitCreateCancel)
|
||||
rightBtnText:(V2TIM_C2C == type) ? @"" : TIMCommonLocalizableString(TUIKitCreateNext)];
|
||||
|
||||
floatVC.topGestureView.rightButton.enabled = NO;
|
||||
|
||||
__weak typeof(floatVC) weakFloatVC = floatVC;
|
||||
floatVC.childVC.floatDataSourceChanged = ^(NSArray *_Nonnull arr) {
|
||||
if (arr.count != 0) {
|
||||
weakFloatVC.topGestureView.rightButton.enabled = YES;
|
||||
} else {
|
||||
weakFloatVC.topGestureView.rightButton.enabled = NO;
|
||||
}
|
||||
};
|
||||
|
||||
[self presentViewController:floatVC animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (TUIConversationListBaseDataProvider *)dataProvider {
|
||||
if (!_dataProvider) {
|
||||
_dataProvider = [[TUIConversationListDataProvider_Minimalist alloc] init];
|
||||
_dataProvider.delegate = self;
|
||||
}
|
||||
return (TUIConversationListDataProvider_Minimalist *)_dataProvider;
|
||||
}
|
||||
|
||||
#pragma mark - edit
|
||||
- (void)openMultiChooseBoard:(BOOL)open {
|
||||
[self.view endEditing:YES];
|
||||
self.showCheckBox = open;
|
||||
|
||||
if (_multiChooseView) {
|
||||
[_multiChooseView removeFromSuperview];
|
||||
}
|
||||
|
||||
if (open) {
|
||||
_multiChooseView = [[TUIConversationMultiChooseView_Minimalist alloc] init];
|
||||
_multiChooseView.frame = UIScreen.mainScreen.bounds;
|
||||
_multiChooseView.titleLabel.text = @"";
|
||||
_multiChooseView.toolView.hidden = YES;
|
||||
|
||||
[_multiChooseView.readButton setTitle:TIMCommonLocalizableString(ReadAll) forState:UIControlStateNormal];
|
||||
[_multiChooseView.hideButton setTitle:TIMCommonLocalizableString(Hide) forState:UIControlStateNormal];
|
||||
[_multiChooseView.deleteButton setTitle:TIMCommonLocalizableString(Delete) forState:UIControlStateNormal];
|
||||
_multiChooseView.readButton.enabled = YES;
|
||||
_multiChooseView.hideButton.enabled = NO;
|
||||
_multiChooseView.deleteButton.enabled = NO;
|
||||
@weakify(self);
|
||||
_multiChooseView.readButton.clickCallBack = ^(id _Nonnull button) {
|
||||
@strongify(self);
|
||||
[self chooseViewReadAll];
|
||||
};
|
||||
_multiChooseView.hideButton.clickCallBack = ^(id _Nonnull button) {
|
||||
@strongify(self);
|
||||
[self choosViewActionHide];
|
||||
};
|
||||
_multiChooseView.deleteButton.clickCallBack = ^(id _Nonnull button) {
|
||||
@strongify(self);
|
||||
[self chooseViewActionDelete];
|
||||
};
|
||||
|
||||
if (@available(iOS 12.0, *)) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// > ios 12
|
||||
[UIApplication.sharedApplication.keyWindow addSubview:_multiChooseView];
|
||||
} else {
|
||||
// ios = 12
|
||||
UIView *view = self.navigationController.view;
|
||||
if (view == nil) {
|
||||
view = self.view;
|
||||
}
|
||||
[view addSubview:_multiChooseView];
|
||||
}
|
||||
} else {
|
||||
// < ios 12
|
||||
[UIApplication.sharedApplication.keyWindow addSubview:_multiChooseView];
|
||||
}
|
||||
} else {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(onCloseConversationMultiChooseBoard)]) {
|
||||
[self.delegate onCloseConversationMultiChooseBoard];
|
||||
}
|
||||
[self enableMultiSelectedMode:NO];
|
||||
self.navigationItem.rightBarButtonItems = @[ self.moreItem, self.editItem ];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)chooseViewReadAll {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(onClearAllConversationUnreadCount)]) {
|
||||
[self.delegate onClearAllConversationUnreadCount];
|
||||
}
|
||||
[self openMultiChooseBoard:NO];
|
||||
}
|
||||
|
||||
- (void)choosViewActionHide {
|
||||
NSArray *uiMsgs = [self getMultiSelectedResult];
|
||||
if (uiMsgs.count == 0) {
|
||||
return;
|
||||
}
|
||||
for (TUIConversationCellData *data in uiMsgs) {
|
||||
[self.dataProvider markConversationHide:data];
|
||||
}
|
||||
|
||||
[self openMultiChooseBoard:NO];
|
||||
}
|
||||
|
||||
- (void)chooseViewActionRead {
|
||||
NSArray *uiMsgs = [self getMultiSelectedResult];
|
||||
if (uiMsgs.count == 0) {
|
||||
return;
|
||||
}
|
||||
for (TUIConversationCellData *data in uiMsgs) {
|
||||
[self.dataProvider markConversationAsRead:data];
|
||||
}
|
||||
|
||||
[self openMultiChooseBoard:NO];
|
||||
}
|
||||
|
||||
- (void)chooseViewActionDelete {
|
||||
NSArray *uiMsgs = [self getMultiSelectedResult];
|
||||
if (uiMsgs.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TUIConversationCellData *data in uiMsgs) {
|
||||
[self.dataProvider removeConversation:data];
|
||||
}
|
||||
|
||||
[self openMultiChooseBoard:NO];
|
||||
}
|
||||
|
||||
#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) {
|
||||
V2TIMUserFullInfo *info = msg.revokerInfo;
|
||||
NSString * revokeReason = msg.revokeReason;
|
||||
BOOL hasRiskContent = msg.hasRiskContent;
|
||||
if (hasRiskContent) {
|
||||
desc = TIMCommonLocalizableString(TUIKitMessageTipsRecallRiskContent);
|
||||
}
|
||||
else if (info) {
|
||||
NSString *userName = info.nickName;
|
||||
desc = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
|
||||
}
|
||||
else if (msg.isSelf) {
|
||||
desc = TIMCommonLocalizableString(TUIKitMessageTipsYouRecallMessage);
|
||||
} else if (msg.userID.length > 0) {
|
||||
desc = TIMCommonLocalizableString(TUIKitMessageTipsOthersRecallMessage);
|
||||
} else if (msg.groupID.length > 0) {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
- (void)insertConversationsAtIndexPaths:(NSArray *)indexPaths {
|
||||
if (!NSThread.isMainThread) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf insertConversationsAtIndexPaths:indexPaths];
|
||||
});
|
||||
return;
|
||||
}
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reloadConversationsAtIndexPaths:(NSArray *)indexPaths {
|
||||
if (!NSThread.isMainThread) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf reloadConversationsAtIndexPaths:indexPaths];
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (self.tableView.isEditing) {
|
||||
self.tableView.editing = NO;
|
||||
}
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)deleteConversationAtIndexPaths:(NSArray *)indexPaths {
|
||||
if (!NSThread.isMainThread) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf deleteConversationAtIndexPaths:indexPaths];
|
||||
});
|
||||
return;
|
||||
}
|
||||
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
- (void)reloadAllConversations {
|
||||
if (!NSThread.isMainThread) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf reloadAllConversations];
|
||||
});
|
||||
return;
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (self.dataSourceChanged) {
|
||||
self.dataSourceChanged(self.dataProvider.conversationList.count);
|
||||
}
|
||||
return self.dataProvider.conversationList.count;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSMutableArray *rowActions = [NSMutableArray array];
|
||||
TUIConversationCellData *cellData = self.dataProvider.conversationList[indexPath.row];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
// Mark as read action
|
||||
UITableViewRowAction *markAsReadAction =
|
||||
[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault
|
||||
title:(cellData.isMarkAsUnread || cellData.unreadCount > 0) ? TIMCommonLocalizableString(MarkAsRead)
|
||||
: TIMCommonLocalizableString(MarkAsUnRead)
|
||||
handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull indexPath) {
|
||||
if (cellData.isMarkAsUnread || cellData.unreadCount > 0) {
|
||||
[weakSelf.dataProvider markConversationAsRead:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_FoldItemIsUnread:NO];
|
||||
}
|
||||
} else {
|
||||
[weakSelf.dataProvider markConversationAsUnRead:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_FoldItemIsUnread:YES];
|
||||
}
|
||||
}
|
||||
}];
|
||||
markAsReadAction.backgroundColor = RGB(20, 122, 255);
|
||||
|
||||
// Mark as hide action
|
||||
UITableViewRowAction *markHideAction =
|
||||
[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault
|
||||
title:TIMCommonLocalizableString(MarkHide)
|
||||
handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull indexPath) {
|
||||
[weakSelf.dataProvider markConversationHide:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_HideFoldItem:YES];
|
||||
}
|
||||
}];
|
||||
markHideAction.backgroundColor = RGB(242, 147, 64);
|
||||
|
||||
// More action
|
||||
UITableViewRowAction *moreAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault
|
||||
title:@"more"
|
||||
handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull indexPath) {
|
||||
weakSelf.tableView.editing = NO;
|
||||
[weakSelf showMoreAction:cellData];
|
||||
}];
|
||||
moreAction.backgroundColor = [UIColor blackColor];
|
||||
|
||||
// config Actions
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[rowActions addObject:markHideAction];
|
||||
} else {
|
||||
[rowActions addObject:markAsReadAction];
|
||||
[rowActions addObject:moreAction];
|
||||
}
|
||||
return rowActions;
|
||||
}
|
||||
|
||||
// available ios 11 +
|
||||
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView
|
||||
trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)) {
|
||||
if (self.showCheckBox) {
|
||||
return nil;
|
||||
}
|
||||
__weak typeof(self) weakSelf = self;
|
||||
TUIConversationCellData *cellData = self.dataProvider.conversationList[indexPath.row];
|
||||
NSMutableArray *arrayM = [NSMutableArray array];
|
||||
NSString *language = [TUIGlobalization tk_localizableLanguageKey];
|
||||
|
||||
// Mark as read action
|
||||
UIContextualAction *markAsReadAction = [UIContextualAction
|
||||
contextualActionWithStyle:UIContextualActionStyleNormal
|
||||
title:@""
|
||||
handler:^(UIContextualAction *_Nonnull action, __kindof UIView *_Nonnull sourceView, void (^_Nonnull completionHandler)(BOOL)) {
|
||||
completionHandler(YES);
|
||||
if (cellData.isMarkAsUnread || cellData.unreadCount > 0) {
|
||||
[weakSelf.dataProvider markConversationAsRead:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_FoldItemIsUnread:NO];
|
||||
}
|
||||
} else {
|
||||
[weakSelf.dataProvider markConversationAsUnRead:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_FoldItemIsUnread:YES];
|
||||
}
|
||||
}
|
||||
}];
|
||||
BOOL read = (cellData.isMarkAsUnread || cellData.unreadCount > 0);
|
||||
markAsReadAction.backgroundColor = read ? RGB(37, 104, 240) : RGB(102, 102, 102);
|
||||
NSString *markAsReadImageName = read ? @"icon_conversation_swipe_read" : @"icon_conversation_swipe_unread";
|
||||
if ([language tui_containsString:@"zh-"]) {
|
||||
markAsReadImageName = [markAsReadImageName stringByAppendingString:@"_zh"];
|
||||
}
|
||||
else if ([language tui_containsString:@"ar"]) {
|
||||
markAsReadImageName = [markAsReadImageName stringByAppendingString:@"_ar"];
|
||||
}
|
||||
markAsReadAction.image =
|
||||
TUIDynamicImage(@"", TUIThemeModuleConversation_Minimalist, [UIImage imageNamed:TUIConversationImagePath_Minimalist(markAsReadImageName)]);
|
||||
|
||||
// Mark as hide action
|
||||
UIContextualAction *markHideAction = [UIContextualAction
|
||||
contextualActionWithStyle:UIContextualActionStyleNormal
|
||||
title:TIMCommonLocalizableString(MarkHide)
|
||||
handler:^(UIContextualAction *_Nonnull action, __kindof UIView *_Nonnull sourceView, void (^_Nonnull completionHandler)(BOOL)) {
|
||||
completionHandler(YES);
|
||||
[weakSelf.dataProvider markConversationHide:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_HideFoldItem:YES];
|
||||
}
|
||||
}];
|
||||
markHideAction.backgroundColor = [UIColor tui_colorWithHex:@"#0365F9"];
|
||||
|
||||
// More action
|
||||
UIContextualAction *moreAction = [UIContextualAction
|
||||
contextualActionWithStyle:UIContextualActionStyleNormal
|
||||
title:@""
|
||||
handler:^(UIContextualAction *_Nonnull action, __kindof UIView *_Nonnull sourceView, void (^_Nonnull completionHandler)(BOOL)) {
|
||||
completionHandler(YES);
|
||||
weakSelf.tableView.editing = NO;
|
||||
[weakSelf showMoreAction:cellData];
|
||||
}];
|
||||
moreAction.backgroundColor = RGB(0, 0, 0);
|
||||
NSString *moreImageName = @"icon_conversation_swipe_more";
|
||||
if ([language tui_containsString:@"zh-"]) {
|
||||
moreImageName = [moreImageName stringByAppendingString:@"_zh"];
|
||||
}
|
||||
else if ([language tui_containsString:@"ar"]) {
|
||||
moreImageName = [moreImageName stringByAppendingString:@"_ar"];
|
||||
}
|
||||
moreAction.image = TUIDynamicImage(@"", TUIThemeModuleConversation_Minimalist, [UIImage imageNamed:TUIConversationImagePath_Minimalist(moreImageName)]);
|
||||
|
||||
// config Actions
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[arrayM addObject:markHideAction];
|
||||
} else {
|
||||
[arrayM addObject:markAsReadAction];
|
||||
[arrayM addObject:moreAction];
|
||||
}
|
||||
UISwipeActionsConfiguration *configuration = [UISwipeActionsConfiguration configurationWithActions:[NSArray arrayWithArray:arrayM]];
|
||||
configuration.performsFirstActionWithFullSwipe = NO;
|
||||
|
||||
// fix bug:
|
||||
// In ios 12, image in SwipeActions will be renderd with template
|
||||
// The method is adding an new image to the origin
|
||||
// The purpose of using async is to ensure UISwipeActionPullView has been renderd in UITableView
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (@available(iOS 12.0, *)) {
|
||||
[self reRenderingSwipeView];
|
||||
}
|
||||
});
|
||||
return configuration;
|
||||
}
|
||||
|
||||
- (void)reRenderingSwipeView API_AVAILABLE(ios(12.0)) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return;
|
||||
}
|
||||
static NSUInteger kSwipeImageViewTag;
|
||||
if (kSwipeImageViewTag == 0) {
|
||||
kSwipeImageViewTag = [NSStringFromClass(self.class) hash];
|
||||
}
|
||||
|
||||
for (UIView *view in self.tableView.subviews) {
|
||||
if (![view isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]) {
|
||||
continue;
|
||||
}
|
||||
for (UIView *subview in view.subviews) {
|
||||
if (![subview isKindOfClass:NSClassFromString(@"UISwipeActionStandardButton")]) {
|
||||
continue;
|
||||
}
|
||||
for (UIView *sub in subview.subviews) {
|
||||
if (![sub isKindOfClass:[UIImageView class]]) {
|
||||
continue;
|
||||
}
|
||||
if ([sub viewWithTag:kSwipeImageViewTag] == nil) {
|
||||
UIImageView *addedImageView = [[UIImageView alloc] initWithFrame:sub.bounds];
|
||||
addedImageView.tag = kSwipeImageViewTag;
|
||||
addedImageView.image = [[(UIImageView *)sub image] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
[sub addSubview:addedImageView];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
TUIConversationCell_Minimalist *cell = [tableView dequeueReusableCellWithIdentifier:kConversationCell_Minimalist_ReuseId forIndexPath:indexPath];
|
||||
TUIConversationCellData *data = [self.dataProvider.conversationList objectAtIndex:indexPath.row];
|
||||
data.showCheckBox = self.showCheckBox;
|
||||
if (data.isLocalConversationFoldList) {
|
||||
data.showCheckBox = NO;
|
||||
}
|
||||
[cell fillWithData:data];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
TUIConversationCell_Minimalist *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
TUIConversationCellData *data = [self.dataProvider.conversationList objectAtIndex:indexPath.row];
|
||||
data.avatarImage = cell.headImageView.image;
|
||||
[self.tableView reloadData];
|
||||
|
||||
if (self.showCheckBox) {
|
||||
if (data.isLocalConversationFoldList) {
|
||||
return;
|
||||
}
|
||||
data.selected = !data.selected;
|
||||
|
||||
NSArray *uiMsgs = [self getMultiSelectedResult];
|
||||
if (uiMsgs.count == 0) {
|
||||
self.multiChooseView.readButton.enabled = NO;
|
||||
self.multiChooseView.deleteButton.enabled = NO;
|
||||
self.multiChooseView.hideButton.enabled = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
@weakify(self);
|
||||
if (uiMsgs.count > 0) {
|
||||
self.multiChooseView.readButton.enabled = NO;
|
||||
self.multiChooseView.hideButton.enabled = YES;
|
||||
self.multiChooseView.deleteButton.enabled = YES;
|
||||
[self.multiChooseView.readButton setTitle:TIMCommonLocalizableString(MarkAsRead) forState:UIControlStateNormal];
|
||||
self.multiChooseView.readButton.clickCallBack = ^(id _Nonnull button) {
|
||||
@strongify(self);
|
||||
[self chooseViewActionRead];
|
||||
};
|
||||
for (TUIConversationCellData *data in uiMsgs) {
|
||||
if (data.unreadCount > 0) {
|
||||
self.multiChooseView.readButton.enabled = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isLocalConversationFoldList) {
|
||||
[TUIConversationListBaseDataProvider cacheConversationFoldListSettings_FoldItemIsUnread:NO];
|
||||
|
||||
TUIFoldListViewController_Minimalist *foldVC = [[TUIFoldListViewController_Minimalist 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_Minimalist cacheConversationFoldListSettings_FoldItemIsUnread:NO];
|
||||
[self.tableView 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_AtTipsStr : data.atTipsStr ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AtMsgSeqs : data.atMsgSeqs ?: @[],
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_Draft : data.draftText ?: @"",
|
||||
};
|
||||
[self.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Minimalist param:param forResult:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// Turn on or off the length of the last line of dividers by controlling this switch
|
||||
BOOL needLastLineFromZeroToMax = NO;
|
||||
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
|
||||
[cell setSeparatorInset:UIEdgeInsetsMake(0, 75, 0, 0)];
|
||||
if (needLastLineFromZeroToMax && indexPath.row == (self.dataProvider.conversationList.count - 1)) {
|
||||
[cell setSeparatorInset:UIEdgeInsetsZero];
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent the cell from inheriting the Table View's margin settings
|
||||
if (needLastLineFromZeroToMax && [cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
|
||||
[cell setPreservesSuperviewLayoutMargins:NO];
|
||||
}
|
||||
|
||||
// Explictly set your cell's layout margins
|
||||
if (needLastLineFromZeroToMax && [cell respondsToSelector:@selector(setLayoutMargins:)]) {
|
||||
[cell setLayoutMargins:UIEdgeInsetsZero];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
|
||||
return UIModalPresentationNone;
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
[self.dataProvider loadNexPageConversations];
|
||||
}
|
||||
|
||||
- (void)enableMultiSelectedMode:(BOOL)enable {
|
||||
self.showCheckBox = enable;
|
||||
if (!enable) {
|
||||
for (TUIConversationCellData_Minimalist *cellData in self.dataProvider.conversationList) {
|
||||
cellData.selected = NO;
|
||||
}
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (NSArray<TUIConversationCellData_Minimalist *> *)getMultiSelectedResult {
|
||||
NSMutableArray *arrayM = [NSMutableArray array];
|
||||
if (!self.showCheckBox) {
|
||||
return [NSArray arrayWithArray:arrayM];
|
||||
}
|
||||
for (TUIConversationCellData_Minimalist *data in self.dataProvider.conversationList) {
|
||||
if (data.selected) {
|
||||
[arrayM addObject:data];
|
||||
}
|
||||
}
|
||||
return [NSArray arrayWithArray:arrayM];
|
||||
}
|
||||
|
||||
// MARK: action
|
||||
- (void)showMoreAction:(TUIConversationCellData *)cellData {
|
||||
id<TUIConversationConfigDataSource> dataSource = [TUIConversationConfig sharedConfig].moreMenuDataSource;
|
||||
BOOL hideHide = NO;
|
||||
BOOL hidePin = NO;
|
||||
BOOL hideClear = NO;
|
||||
BOOL hideDelete = NO;
|
||||
NSArray *customizedItems = @[];
|
||||
if (dataSource && [dataSource respondsToSelector:@selector(conversationShouldHideItemsInMoreMenu:)]) {
|
||||
NSInteger flag = [dataSource conversationShouldHideItemsInMoreMenu:cellData];
|
||||
hideHide = flag & TUIConversationItemInMoreMenu_Hide;
|
||||
hidePin = flag & TUIConversationItemInMoreMenu_Pin;
|
||||
hideClear = flag & TUIConversationItemInMoreMenu_Clear;
|
||||
hideDelete = flag & TUIConversationItemInMoreMenu_Delete;
|
||||
}
|
||||
if (dataSource && [dataSource respondsToSelector:@selector(conversationShouldAddNewItemsToMoreMenu:)]) {
|
||||
customizedItems = [dataSource conversationShouldAddNewItemsToMoreMenu:cellData];
|
||||
}
|
||||
|
||||
UIAlertController *ac = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
if (!hideHide) {
|
||||
[ac tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(MarkHide)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf.dataProvider markConversationHide:cellData];
|
||||
if (cellData.isLocalConversationFoldList) {
|
||||
[TUIConversationListDataProvider_Minimalist cacheConversationFoldListSettings_HideFoldItem:YES];
|
||||
}
|
||||
}]];
|
||||
}
|
||||
|
||||
|
||||
if (!cellData.isMarkAsFolded) {
|
||||
if (!hidePin) {
|
||||
[ac tuitheme_addAction:[UIAlertAction actionWithTitle:cellData.isOnTop ? TIMCommonLocalizableString(UnPin) : TIMCommonLocalizableString(Pin)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf.dataProvider pinConversation:cellData pin:!cellData.isOnTop];
|
||||
}]];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!hideClear) {
|
||||
[ac tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(ClearHistoryChatMessage)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf.dataProvider markConversationAsRead:cellData];
|
||||
[strongSelf.dataProvider clearHistoryMessage:cellData];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (!hideDelete) {
|
||||
[ac tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Delete)
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf.dataProvider removeConversation:cellData];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (customizedItems.count > 0) {
|
||||
for (id action in customizedItems) {
|
||||
if (![action isKindOfClass:UIAlertAction.class]) {
|
||||
continue;
|
||||
}
|
||||
[ac tuitheme_addAction:action];
|
||||
}
|
||||
}
|
||||
|
||||
[ac tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Cancel) style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:ac animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)startCreatGroupNotification:(NSNotification *)noti {
|
||||
[self startConversation:V2TIM_GROUP];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface IUConversationView_Minimalist : UIView
|
||||
@property(nonatomic, strong) UIView *view;
|
||||
@end
|
||||
|
||||
@implementation IUConversationView_Minimalist
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
|
||||
[self addSubview:self.view];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
#import <TIMCommon/TUIFitButton.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationMultiChooseView_Minimalist : UIView
|
||||
#pragma mark - Top toolbar
|
||||
/**
|
||||
* The top toolbar, showing shortcut operations such as cancel
|
||||
*/
|
||||
@property(nonatomic, strong) UIView *toolView;
|
||||
|
||||
/**
|
||||
* Top toolbar element: Cancel button
|
||||
*/
|
||||
@property(nonatomic, strong) UIButton *cancelButton;
|
||||
|
||||
/**
|
||||
* Top toolbar element: title
|
||||
*/
|
||||
@property(nonatomic, strong) UILabel *titleLabel;
|
||||
|
||||
#pragma mark - Bottom menu bar
|
||||
/**
|
||||
* The bottom menu bar, shows the operation menu after multiple selection messages, such as forwarding, deleting, etc.
|
||||
*/
|
||||
@property(nonatomic, strong) UIView *menuView;
|
||||
|
||||
@property(nonatomic, strong) TUIBlockButton *hideButton;
|
||||
@property(nonatomic, strong) TUIBlockButton *readButton;
|
||||
@property(nonatomic, strong) TUIBlockButton *deleteButton;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// TUIConversationMultiChooseView_Minimalist.m
|
||||
// Pods
|
||||
//
|
||||
// Created by harvy on 2020/11/27.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationMultiChooseView_Minimalist.h"
|
||||
#import <TUICore/TUIDarkModel.h>
|
||||
#import <TUICore/TUIGlobalization.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
#import <TUICore/UIView+TUILayout.h>
|
||||
|
||||
@interface TUIConversationMultiChooseView_Minimalist ()
|
||||
|
||||
@property(nonatomic, strong) CALayer *separtorLayer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIConversationMultiChooseView_Minimalist
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setupViews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
id hitView = [super hitTest:point withEvent:event];
|
||||
if (hitView == self) {
|
||||
return nil;
|
||||
} else {
|
||||
return hitView;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
CGFloat toolHeight = 44;
|
||||
CGFloat menuHeight = 54 + 3;
|
||||
CGFloat centerTopOffset = 0;
|
||||
CGFloat centerBottomOffset = 0;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
toolHeight += self.safeAreaInsets.top;
|
||||
menuHeight += self.safeAreaInsets.bottom;
|
||||
centerTopOffset = self.safeAreaInsets.top;
|
||||
centerBottomOffset = self.safeAreaInsets.bottom;
|
||||
}
|
||||
|
||||
self.toolView.frame = CGRectMake(0, 0, self.bounds.size.width, toolHeight);
|
||||
self.menuView.frame = CGRectMake(0, self.bounds.size.height - menuHeight, self.bounds.size.width, menuHeight);
|
||||
// self.separtorLayer.frame = CGRectMake(0, 0, self.menuView.mm_w, 1);
|
||||
|
||||
// toolView
|
||||
{
|
||||
CGFloat centerY = 0.5 * (self.toolView.bounds.size.height - self.cancelButton.bounds.size.height);
|
||||
self.cancelButton.frame = CGRectMake(10, centerY += 0.5 * centerTopOffset, self.cancelButton.bounds.size.width, self.cancelButton.bounds.size.height);
|
||||
|
||||
[self.titleLabel sizeToFit];
|
||||
self.titleLabel.center = self.toolView.center;
|
||||
CGRect titleRect = self.self.titleLabel.frame;
|
||||
titleRect.origin.y += 0.5 * centerTopOffset;
|
||||
self.titleLabel.frame = titleRect;
|
||||
}
|
||||
|
||||
// menuView
|
||||
{
|
||||
NSInteger count = self.menuView.subviews.count;
|
||||
CGFloat width = self.menuView.bounds.size.width / count;
|
||||
CGFloat height = (self.menuView.bounds.size.height - centerBottomOffset);
|
||||
for (int i = 0; i < self.menuView.subviews.count; i++) {
|
||||
UIView *sub = self.menuView.subviews[i];
|
||||
CGFloat centerY = (self.menuView.bounds.size.height - height) * 0.5;
|
||||
sub.frame = CGRectMake(i * width, centerY -= 0.5 * centerBottomOffset, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Views
|
||||
- (void)setupViews {
|
||||
_toolView = [[UIView alloc] init];
|
||||
_toolView.backgroundColor = TIMCommonDynamicColor(@"head_bg_gradient_start_color", @"#EBF0F6");
|
||||
[self addSubview:_toolView];
|
||||
|
||||
_menuView = [[UIView alloc] init];
|
||||
_menuView.backgroundColor = TUIChatDynamicColor(@"chat_controller_bg_color", @"#FFFFFF");
|
||||
[_menuView.layer addSublayer:self.separtorLayer];
|
||||
[self addSubview:_menuView];
|
||||
|
||||
_cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_cancelButton setTitle:TIMCommonLocalizableString(Cancel) forState:UIControlStateNormal];
|
||||
[_cancelButton setTitleColor:TIMCommonDynamicColor(@"form_title_color", @"#000000") forState:UIControlStateNormal];
|
||||
_cancelButton.titleLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
// [_cancelButton addTarget:self action:@selector(onCancel:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_cancelButton sizeToFit];
|
||||
[_toolView addSubview:_cancelButton];
|
||||
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
_titleLabel.text = @"";
|
||||
_titleLabel.font = [UIFont boldSystemFontOfSize:17.0];
|
||||
_titleLabel.textColor = TIMCommonDynamicColor(@"form_title_color", @"#000000");
|
||||
[_toolView addSubview:_titleLabel];
|
||||
|
||||
_hideButton = [TUIBlockButton buttonWithType:UIButtonTypeCustom];
|
||||
[_hideButton setTitle:@"Mark as Hide" forState:UIControlStateNormal];
|
||||
_hideButton.titleLabel.font = [UIFont systemFontOfSize:14.0];
|
||||
TIMCommonDynamicColor(@"common_switch_on_color", @"#147AFF");
|
||||
[_hideButton setTitleColor:TIMCommonDynamicColor(@"primary_theme_color", @"#147AFF") forState:UIControlStateNormal];
|
||||
[_hideButton setTitleColor:[TIMCommonDynamicColor(@"primary_theme_color", @"#147AFF") colorWithAlphaComponent:0.3] forState:UIControlStateDisabled];
|
||||
// [_hideButton addTarget:self action:@selector(onMarkHideAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_menuView addSubview:_hideButton];
|
||||
|
||||
_readButton = [TUIBlockButton buttonWithType:UIButtonTypeCustom];
|
||||
[_readButton setTitle:@"Mark as Read" forState:UIControlStateNormal];
|
||||
_readButton.titleLabel.font = [UIFont systemFontOfSize:14.0];
|
||||
[_readButton setTitleColor:TIMCommonDynamicColor(@"primary_theme_color", @"#147AFF") forState:UIControlStateNormal];
|
||||
[_readButton setTitleColor:[TIMCommonDynamicColor(@"primary_theme_color", @"#147AFF") colorWithAlphaComponent:0.3] forState:UIControlStateDisabled];
|
||||
// [_readButton addTarget:self action:@selector(onMarkReadAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_menuView addSubview:_readButton];
|
||||
|
||||
_deleteButton = [TUIBlockButton buttonWithType:UIButtonTypeCustom];
|
||||
[_deleteButton setTitle:TIMCommonLocalizableString(Delete) forState:UIControlStateNormal];
|
||||
_deleteButton.titleLabel.font = [UIFont systemFontOfSize:14.0];
|
||||
[_deleteButton setTitleColor:TIMCommonDynamicColor(@"primary_theme_color", @"#147AFF") forState:UIControlStateNormal];
|
||||
[_deleteButton setTitleColor:[TIMCommonDynamicColor(@"primary_theme_color", @"#147AFF") colorWithAlphaComponent:0.3] forState:UIControlStateDisabled];
|
||||
// [_deleteButton addTarget:self action:@selector(onDelete:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_menuView addSubview:_deleteButton];
|
||||
}
|
||||
|
||||
#pragma mark - Action
|
||||
|
||||
- (CALayer *)separtorLayer {
|
||||
if (_separtorLayer == nil) {
|
||||
_separtorLayer = [CALayer layer];
|
||||
|
||||
_separtorLayer.backgroundColor = TIMCommonDynamicColor(@"separator_color", @"#DBDBDB").CGColor;
|
||||
}
|
||||
return _separtorLayer;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// TUIConversationSelectController_Minimalist.h
|
||||
// Pods
|
||||
//
|
||||
// Created by harvy on 2020/12/8.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class TUIConversationCellData;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConversationSelectController_Minimalist : UIViewController
|
||||
|
||||
+ (instancetype)showIn:(UIViewController *)presentVC;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,600 @@
|
||||
//
|
||||
// TUIConversationSelectController_Minimalist.m
|
||||
// Pods
|
||||
//
|
||||
// Created by harvy on 2020/12/8.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConversationSelectController_Minimalist.h"
|
||||
#import <TIMCommon/TIMCommonModel.h>
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TUICore/NSDictionary+TUISafe.h>
|
||||
#import <TUICore/TUICore.h>
|
||||
#import "TUIConversationCellData_Minimalist.h"
|
||||
#import "TUIConversationForwardSelectCell_Minimalist.h"
|
||||
#import "TUIConversationSelectDataProvider_Minimalist.h"
|
||||
|
||||
typedef void (^TUIConversationSelectCompletHandler)(BOOL);
|
||||
|
||||
@interface TUIConversationSelectCollectionCell : UICollectionViewCell
|
||||
@property(nonatomic, strong) UILabel *textLabel;
|
||||
@end
|
||||
@implementation TUIConversationSelectCollectionCell
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
_textLabel = [[UILabel alloc] init];
|
||||
_textLabel.font = [UIFont systemFontOfSize:kScale390(14)];
|
||||
_textLabel.textColor = [UIColor tui_colorWithHex:@"#000000"];
|
||||
[self.contentView addSubview:_textLabel];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[_textLabel sizeToFit];
|
||||
_textLabel.frame = CGRectMake(0, kScale390(14), _textLabel.frame.size.width, _textLabel.frame.size.height);
|
||||
}
|
||||
@end
|
||||
@interface TUIConversationSelectListPicker : UIControl <UICollectionViewDelegate, UICollectionViewDataSource>
|
||||
@property(nonatomic, strong) UIView *line;
|
||||
@property(nonatomic, strong) UICollectionView *collectionView;
|
||||
@property(nonatomic, strong) UIButton *accessoryBtn;
|
||||
@property(nonatomic, strong) NSArray<TUICommonContactSelectCellData *> *selectArray;
|
||||
@property(nonatomic, copy) TUIContactListPickerOnCancel onCancel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIConversationSelectListPicker
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
[self initControl];
|
||||
[self setupBinding];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initControl {
|
||||
self.line = [[UIView alloc] init];
|
||||
self.line.backgroundColor = [UIColor tui_colorWithHex:@"#000000" alpha:0.1];
|
||||
[self addSubview:self.line];
|
||||
UICollectionViewFlowLayout *layout = [[TUICollectionRTLFitFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.minimumLineSpacing = 0;
|
||||
layout.minimumInteritemSpacing = 0;
|
||||
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.collectionView.showsHorizontalScrollIndicator = NO;
|
||||
self.collectionView.decelerationRate = UIScrollViewDecelerationRateNormal;
|
||||
|
||||
[self.collectionView registerClass:[TUIConversationSelectCollectionCell class] forCellWithReuseIdentifier:@"PickerIdentifier"];
|
||||
[self.collectionView setBackgroundColor:[UIColor clearColor]];
|
||||
[self.collectionView setDelegate:self];
|
||||
[self.collectionView setDataSource:self];
|
||||
|
||||
[self addSubview:_collectionView];
|
||||
|
||||
self.accessoryBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[self.accessoryBtn setTitle:[NSString stringWithFormat:@" %@ ", TIMCommonLocalizableString(Forward)] forState:UIControlStateNormal];
|
||||
[self.accessoryBtn setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
|
||||
self.accessoryBtn.titleLabel.font = [UIFont boldSystemFontOfSize:kScale390(14)];
|
||||
self.accessoryBtn.enabled = NO;
|
||||
[self addSubview:self.accessoryBtn];
|
||||
}
|
||||
|
||||
- (void)setupBinding {
|
||||
[self addObserver:self forKeyPath:@"selectArray" options:NSKeyValueObservingOptionNew context:nil];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
|
||||
if ([keyPath isEqualToString:@"selectArray"]) {
|
||||
[self.collectionView reloadData];
|
||||
NSArray *newSelectArray = change[NSKeyValueChangeNewKey];
|
||||
if ([newSelectArray isKindOfClass:NSArray.class]) {
|
||||
self.accessoryBtn.enabled = [newSelectArray count];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return [self.selectArray count];
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(nonnull UICollectionView *)collectionView
|
||||
layout:(nonnull UICollectionViewLayout *)collectionViewLayout
|
||||
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
TUICommonContactSelectCellData *model = self.selectArray[indexPath.row];
|
||||
NSString *formatTitle = @"";
|
||||
if (indexPath.row != 0) {
|
||||
formatTitle = [NSString stringWithFormat:@",%@", model.title];
|
||||
} else {
|
||||
formatTitle = model.title;
|
||||
}
|
||||
CGSize size = [formatTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 20)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:kScale390(14)]}
|
||||
context:nil]
|
||||
.size;
|
||||
return CGSizeMake(size.width, self.collectionView.frame.size.height);
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
TUIConversationSelectCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PickerIdentifier" forIndexPath:indexPath];
|
||||
|
||||
TUICommonContactSelectCellData *data = self.selectArray[indexPath.row];
|
||||
|
||||
if (indexPath.row != 0) {
|
||||
cell.textLabel.text = [NSString stringWithFormat:@",%@", data.title];
|
||||
} else {
|
||||
cell.textLabel.text = data.title;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:NO];
|
||||
if (indexPath.item >= self.selectArray.count) {
|
||||
return;
|
||||
}
|
||||
TUICommonContactSelectCellData *data = self.selectArray[indexPath.item];
|
||||
if (self.onCancel) {
|
||||
self.onCancel(data);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
self.line.frame = CGRectMake(0, 0, self.mm_w, kScale390(1));
|
||||
self.accessoryBtn.mm_sizeToFit().mm_height(30).mm_right(15).mm_top(13);
|
||||
self.collectionView.mm_left(kScale390(16)).mm_height(40).mm_width(self.accessoryBtn.mm_x - 30).mm__centerY(self.accessoryBtn.mm_centerY);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIConversationSelectController_Minimalist () <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
@property(nonatomic, strong) UITableView *tableView;
|
||||
@property(nonatomic, strong) TUIConversationSelectListPicker *pickerView;
|
||||
@property(nonatomic, strong) TUICommonTableViewCell *headerView;
|
||||
|
||||
@property(nonatomic, assign) BOOL enableMuliple;
|
||||
@property(nonatomic, strong) NSMutableArray<TUIConversationCellData *> *currentSelectedList;
|
||||
|
||||
@property(nonatomic, strong) TUIConversationSelectDataProvider_Minimalist *dataProvider;
|
||||
|
||||
@property(nonatomic, weak) UIViewController *showContactSelectVC;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIConversationSelectController_Minimalist
|
||||
|
||||
static NSString *const Id = @"con";
|
||||
|
||||
#pragma mark - Life
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
[self setupViews];
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
[super viewWillLayoutSubviews];
|
||||
[self updateLayout];
|
||||
}
|
||||
|
||||
- (TUIConversationSelectDataProvider_Minimalist *)dataProvider {
|
||||
if (!_dataProvider) {
|
||||
_dataProvider = [[TUIConversationSelectDataProvider_Minimalist alloc] init];
|
||||
[_dataProvider loadConversations];
|
||||
}
|
||||
return _dataProvider;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
NSLog(@"%s dealloc", __FUNCTION__);
|
||||
}
|
||||
|
||||
#pragma mark - API
|
||||
+ (instancetype)showIn:(UIViewController *)presentVC {
|
||||
TUIConversationSelectController_Minimalist *vc = [[TUIConversationSelectController_Minimalist alloc] init];
|
||||
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
|
||||
nav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
UIViewController *pVc = presentVC;
|
||||
if (pVc == nil) {
|
||||
pVc = UIApplication.sharedApplication.keyWindow.rootViewController;
|
||||
}
|
||||
[pVc presentViewController:nav animated:YES completion:nil];
|
||||
return vc;
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
- (void)setupViews {
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:TIMCommonLocalizableString(Cancel)
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(doCancel)];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:TIMCommonLocalizableString(Multiple)
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(doMultiple)];
|
||||
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
_headerView = [[TUICommonTableViewCell alloc] init];
|
||||
_headerView.textLabel.text = TIMCommonLocalizableString(TUIKitRelayTargetCreateNewChat);
|
||||
_headerView.textLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
_headerView.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
[_headerView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onCreateSessionOrSelectContact)]];
|
||||
|
||||
_tableView = [[UITableView alloc] init];
|
||||
_tableView.delegate = self;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
// _tableView.tableHeaderView = self.headerView;
|
||||
[_tableView registerClass:TUIConversationForwardSelectCell_Minimalist.class forCellReuseIdentifier:Id];
|
||||
[self.view addSubview:_tableView];
|
||||
|
||||
_pickerView = [[TUIConversationSelectListPicker alloc] init];
|
||||
|
||||
[_pickerView setBackgroundColor:[UIColor whiteColor]];
|
||||
[_pickerView setHidden:YES];
|
||||
[_pickerView.accessoryBtn addTarget:self action:@selector(doPickerDone) forControlEvents:UIControlEventTouchUpInside];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
_pickerView.onCancel = ^(TUICommonContactSelectCellData *data) {
|
||||
TUIConversationCellData *tmp = nil;
|
||||
for (TUIConversationCellData *convCellData in weakSelf.currentSelectedList) {
|
||||
if ([convCellData.conversationID isEqualToString:data.identifier]) {
|
||||
tmp = convCellData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tmp == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
tmp.selected = NO;
|
||||
[weakSelf.currentSelectedList removeObject:tmp];
|
||||
[weakSelf updatePickerView];
|
||||
[weakSelf.tableView reloadData];
|
||||
};
|
||||
[self.view addSubview:_pickerView];
|
||||
|
||||
@weakify(self);
|
||||
[RACObserve(self.dataProvider, dataList) subscribeNext:^(id _Nullable x) {
|
||||
@strongify(self);
|
||||
[self.tableView reloadData];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateLayout {
|
||||
[self.pickerView setHidden:!self.enableMuliple];
|
||||
self.headerView.frame = CGRectMake(0, 0, self.view.bounds.size.width, 55);
|
||||
_headerView.textLabel.text =
|
||||
self.enableMuliple ? TIMCommonLocalizableString(TUIKitRelayTargetSelectFromContacts) : TIMCommonLocalizableString(TUIKitRelayTargetCreateNewChat);
|
||||
|
||||
if (!self.enableMuliple) {
|
||||
self.tableView.frame = self.view.bounds;
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat pH = 55;
|
||||
CGFloat pMargin = 0;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
pMargin = self.view.safeAreaInsets.bottom;
|
||||
}
|
||||
[self.pickerView setFrame:CGRectMake(0, self.view.bounds.size.height - pH - pMargin, self.view.bounds.size.width, pH + pMargin)];
|
||||
self.tableView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - pH - pMargin);
|
||||
}
|
||||
|
||||
- (void)updatePickerView {
|
||||
NSMutableArray *arrayM = [NSMutableArray array];
|
||||
for (TUIConversationCellData *convCellData in self.currentSelectedList) {
|
||||
TUICommonContactSelectCellData *data = [[TUICommonContactSelectCellData alloc] init];
|
||||
data.avatarUrl = [NSURL URLWithString:convCellData.faceUrl];
|
||||
data.avatarImage = convCellData.avatarImage;
|
||||
data.title = convCellData.title;
|
||||
data.identifier = convCellData.conversationID;
|
||||
[arrayM addObject:data];
|
||||
}
|
||||
self.pickerView.selectArray = [NSArray arrayWithArray:arrayM];
|
||||
}
|
||||
|
||||
#pragma mark - Action
|
||||
- (void)doCancel {
|
||||
if (self.enableMuliple) {
|
||||
self.enableMuliple = NO;
|
||||
|
||||
for (TUIConversationCellData *cellData in self.dataProvider.dataList) {
|
||||
cellData.selected = NO;
|
||||
}
|
||||
|
||||
[self.currentSelectedList removeAllObjects];
|
||||
self.pickerView.selectArray = @[];
|
||||
[self updatePickerView];
|
||||
[self updateLayout];
|
||||
[self.tableView reloadData];
|
||||
} else {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doMultiple {
|
||||
self.enableMuliple = YES;
|
||||
[self updateLayout];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)onCreateSessionOrSelectContact {
|
||||
NSMutableArray *ids = NSMutableArray.new;
|
||||
for (TUIConversationCellData *cd in self.currentSelectedList) {
|
||||
if (![cd.userID isEqualToString:[[V2TIMManager sharedInstance] getLoginUser]]) {
|
||||
if (cd.userID.length > 0) {
|
||||
[ids addObject:cd.userID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@weakify(self);
|
||||
void (^selectContactCompletion)(NSArray<TUICommonContactSelectCellData *> *) = ^(NSArray<TUICommonContactSelectCellData *> *array) {
|
||||
@strongify(self);
|
||||
[self dealSelectBlock:array];
|
||||
};
|
||||
|
||||
UIViewController *vc = [TUICore createObject:TUICore_TUIContactObjectFactory
|
||||
key:TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod
|
||||
param:@{
|
||||
TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod_DisableIdsKey : ids,
|
||||
TUICore_TUIContactObjectFactory_GetContactSelectControllerMethod_CompletionKey : selectContactCompletion,
|
||||
}];
|
||||
|
||||
[self.navigationController pushViewController:(UIViewController *)vc animated:YES];
|
||||
self.showContactSelectVC = vc;
|
||||
}
|
||||
|
||||
- (void)dealSelectBlock:(NSArray<TUICommonContactSelectCellData *> *)array {
|
||||
NSArray<TUICommonContactSelectCellData *> *selectArray = array;
|
||||
if (![selectArray.firstObject isKindOfClass:TUICommonContactSelectCellData.class]) {
|
||||
NSAssert(NO, @"Error value type");
|
||||
}
|
||||
if (self.enableMuliple) {
|
||||
/**
|
||||
* Multiple selection: Select from address book -> Create conversation for each contact -> Every contact will be displayed in pickerView
|
||||
*/
|
||||
for (TUICommonContactSelectCellData *contact in selectArray) {
|
||||
if ([self existInSelectedArray:contact.identifier]) {
|
||||
continue;
|
||||
}
|
||||
TUIConversationCellData *conv = [self findItemInDataListArray:contact.identifier];
|
||||
if (!conv) {
|
||||
conv = [[TUIConversationCellData alloc] init];
|
||||
conv.conversationID = contact.identifier;
|
||||
conv.userID = contact.identifier;
|
||||
conv.groupID = @"";
|
||||
conv.avatarImage = contact.avatarImage;
|
||||
conv.faceUrl = contact.avatarUrl.absoluteString;
|
||||
} else {
|
||||
conv.selected = !conv.selected;
|
||||
}
|
||||
|
||||
[self.currentSelectedList addObject:conv];
|
||||
}
|
||||
|
||||
[self updatePickerView];
|
||||
[self.tableView reloadData];
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
} else {
|
||||
/**
|
||||
* Single Choice: Create a new chat (or a group chat if there are multiple people) -> Create a group chat for the selected contact -> Forward directly
|
||||
*/
|
||||
if (selectArray.count <= 1) {
|
||||
TUICommonContactSelectCellData *contact = selectArray.firstObject;
|
||||
if (contact) {
|
||||
TUIConversationCellData *conv = [[TUIConversationCellData alloc] init];
|
||||
conv.conversationID = contact.identifier;
|
||||
conv.userID = contact.identifier;
|
||||
conv.groupID = @"";
|
||||
conv.avatarImage = contact.avatarImage;
|
||||
conv.faceUrl = contact.avatarUrl.absoluteString;
|
||||
self.currentSelectedList = [NSMutableArray arrayWithArray:@[ conv ]];
|
||||
[self tryFinishSelected:^(BOOL finished) {
|
||||
if (finished) {
|
||||
[self notifyFinishSelecting];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}];
|
||||
}
|
||||
return;
|
||||
}
|
||||
[self tryFinishSelected:^(BOOL finished) {
|
||||
if (finished) {
|
||||
[self createGroupWithContacts:selectArray
|
||||
completion:^(BOOL success) {
|
||||
if (success) {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)existInSelectedArray:(NSString *)identifier {
|
||||
for (TUIConversationCellData *cellData in self.currentSelectedList) {
|
||||
if (cellData.userID.length && [cellData.userID isEqualToString:identifier]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (TUIConversationCellData *)findItemInDataListArray:(NSString *)identifier {
|
||||
for (TUIConversationCellData *cellData in self.dataProvider.dataList) {
|
||||
if (cellData.userID.length && [cellData.userID isEqualToString:identifier]) {
|
||||
return cellData;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)doPickerDone {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self tryFinishSelected:^(BOOL finished) {
|
||||
if (finished) {
|
||||
[self notifyFinishSelecting];
|
||||
[weakSelf dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// confirm whether to forward or not
|
||||
- (void)tryFinishSelected:(TUIConversationSelectCompletHandler)handler {
|
||||
UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:TIMCommonLocalizableString(TUIKitRelayConfirmForward)
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertVc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Cancel)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
if (handler) {
|
||||
handler(NO);
|
||||
}
|
||||
}]];
|
||||
[alertVc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Confirm)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
if (handler) {
|
||||
handler(YES);
|
||||
}
|
||||
}]];
|
||||
[self presentViewController:alertVc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
// notify others that the user has finished selecting conversations
|
||||
- (void)notifyFinishSelecting {
|
||||
if (self.navigateValueCallback) {
|
||||
NSMutableArray *temMArr = [NSMutableArray arrayWithCapacity:self.currentSelectedList.count];
|
||||
for (TUIConversationCellData *cellData in self.currentSelectedList) {
|
||||
[temMArr addObject:@{
|
||||
TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_ConversationID : cellData.conversationID ?: @"",
|
||||
TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_Title : cellData.title ?: @"",
|
||||
TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_UserID : cellData.userID ?: @"",
|
||||
TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_GroupID : cellData.groupID ?: @"",
|
||||
}];
|
||||
}
|
||||
self.navigateValueCallback(@{TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList : temMArr});
|
||||
}
|
||||
}
|
||||
|
||||
// create a new group to receive the forwarding messages
|
||||
- (void)createGroupWithContacts:(NSArray *)contacts completion:(void (^)(BOOL success))completion {
|
||||
@weakify(self);
|
||||
void (^createGroupCompletion)(BOOL, NSString *, NSString *) = ^(BOOL success, NSString *groupID, NSString *groupName) {
|
||||
@strongify(self);
|
||||
if (!success) {
|
||||
[TUITool makeToast:TIMCommonLocalizableString(TUIKitRelayTargetCrateGroupError)];
|
||||
if (completion) {
|
||||
completion(NO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
TUIConversationCellData *cellData = [[TUIConversationCellData alloc] init];
|
||||
cellData.groupID = groupID;
|
||||
cellData.title = groupName;
|
||||
self.currentSelectedList = [NSMutableArray arrayWithArray:@[ cellData ]];
|
||||
[self notifyFinishSelecting];
|
||||
if (completion) {
|
||||
completion(YES);
|
||||
}
|
||||
};
|
||||
NSDictionary *param = @{
|
||||
TUICore_TUIContactService_CreateGroupMethod_GroupTypeKey : GroupType_Meeting,
|
||||
TUICore_TUIContactService_CreateGroupMethod_OptionKey : @(V2TIM_GROUP_ADD_ANY),
|
||||
TUICore_TUIContactService_CreateGroupMethod_ContactsKey : contacts,
|
||||
TUICore_TUIContactService_CreateGroupMethod_CompletionKey : createGroupCompletion
|
||||
};
|
||||
[TUICore callService:TUICore_TUIContactService_Minimalist method:TUICore_TUIContactService_CreateGroupMethod param:param];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate, UITableViewDataSource
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.dataProvider.dataList.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
TUIConversationForwardSelectCell_Minimalist *cell = [tableView dequeueReusableCellWithIdentifier:Id forIndexPath:indexPath];
|
||||
if (indexPath.row < 0 || indexPath.row >= self.dataProvider.dataList.count) {
|
||||
return cell;
|
||||
}
|
||||
TUIConversationCellData *cellData = self.dataProvider.dataList[indexPath.row];
|
||||
cellData.showCheckBox = self.enableMuliple;
|
||||
[cell fillWithData:cellData];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
TUIConversationCellData *cellData = self.dataProvider.dataList[indexPath.row];
|
||||
cellData.selected = !cellData.selected;
|
||||
if (!self.enableMuliple) {
|
||||
self.currentSelectedList = [NSMutableArray arrayWithArray:@[ cellData ]];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self tryFinishSelected:^(BOOL finished) {
|
||||
if (finished) {
|
||||
[self notifyFinishSelecting];
|
||||
[weakSelf dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self.currentSelectedList containsObject:cellData]) {
|
||||
[self.currentSelectedList removeObject:cellData];
|
||||
} else {
|
||||
[self.currentSelectedList addObject:cellData];
|
||||
}
|
||||
|
||||
[self updatePickerView];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return 56.0;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
||||
UIView *titleView = [[UIView alloc] init];
|
||||
titleView.backgroundColor = [UIColor whiteColor];
|
||||
titleView.bounds = CGRectMake(0, 0, self.tableView.bounds.size.width, 30);
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
label.text = TIMCommonLocalizableString(TUIKitRelayRecentMessages);
|
||||
label.font = [UIFont boldSystemFontOfSize:kScale390(14)];
|
||||
label.textColor = [UIColor tui_colorWithHex:@"#000000"];
|
||||
label.textAlignment = NSTextAlignmentLeft;
|
||||
[titleView addSubview:label];
|
||||
label.frame = CGRectMake(kScale390(14), 0, self.tableView.bounds.size.width - 10, 30);
|
||||
return titleView;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (NSMutableArray<TUIConversationCellData *> *)currentSelectedList {
|
||||
if (_currentSelectedList == nil) {
|
||||
_currentSelectedList = [NSMutableArray array];
|
||||
}
|
||||
return _currentSelectedList;
|
||||
}
|
||||
|
||||
#pragma mark - TUIChatFloatSubViewControllerProtocol
|
||||
- (void)floatControllerLeftButtonClick {
|
||||
[self doCancel];
|
||||
}
|
||||
|
||||
- (void)floatControllerRightButtonClick {
|
||||
[self doMultiple];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// TUIFoldListViewController_Minimalist.h
|
||||
// TUIKitDemo
|
||||
//
|
||||
// Created by wyl on 2022/11/4.
|
||||
// Copyright © 2022 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIFoldListViewController_Minimalist : UIViewController
|
||||
|
||||
@property(nonatomic, copy) void (^dismissCallback)(NSMutableAttributedString *foldStr, NSArray *sortArr, NSArray *needRemoveFromCacheMapArray);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// TUIFoldListViewController_Minimalist.m
|
||||
// TUIKitDemo
|
||||
//
|
||||
// Created by wyl on 2022/11/4.
|
||||
// Copyright © 2022 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIFoldListViewController_Minimalist.h"
|
||||
#import <TUICore/TUICore.h>
|
||||
#import "TUIConversationListController_Minimalist.h"
|
||||
#import "TUIFoldConversationListDataProvider_Minimalist.h"
|
||||
|
||||
@interface TUIFoldListViewController_Minimalist () <TUINavigationControllerDelegate, TUIConversationListControllerListener>
|
||||
|
||||
@property(nonatomic, strong) TUINaviBarIndicatorView *titleView;
|
||||
@property(nonatomic, copy) NSString *mainTitle;
|
||||
@property(nonatomic, strong) TUIConversationListController_Minimalist *conv;
|
||||
@property(nonatomic, strong) UILabel *noDataTipsLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIFoldListViewController_Minimalist
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.conv = [[TUIConversationListController_Minimalist alloc] init];
|
||||
|
||||
self.conv.dataProvider = [[TUIFoldConversationListDataProvider_Minimalist alloc] init];
|
||||
self.conv.dataProvider.delegate = (id)self.conv;
|
||||
self.conv.isShowBanner = NO;
|
||||
self.conv.delegate = self;
|
||||
|
||||
@weakify(self);
|
||||
self.conv.dataSourceChanged = ^(NSInteger count) {
|
||||
@strongify(self);
|
||||
self.noDataTipsLabel.hidden = count > 0;
|
||||
};
|
||||
[self addChildViewController:self.conv];
|
||||
[self.view addSubview:self.conv.view];
|
||||
|
||||
[self setupNavigator];
|
||||
[self.view addSubview:self.noDataTipsLabel];
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString *)title {
|
||||
self.mainTitle = title;
|
||||
}
|
||||
|
||||
- (void)setupNavigator {
|
||||
TUINavigationController *naviController = (TUINavigationController *)self.navigationController;
|
||||
naviController.uiNaviDelegate = self;
|
||||
_titleView = [[TUINaviBarIndicatorView alloc] init];
|
||||
self.navigationItem.titleView = _titleView;
|
||||
[self.titleView setTitle:TIMCommonLocalizableString(TUIKitConversationMarkFoldGroups)];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.noDataTipsLabel.frame = CGRectMake(10, 120, self.view.bounds.size.width - 20, 40);
|
||||
}
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
TUINavigationController *naviController = (TUINavigationController *)self.navigationController;
|
||||
naviController.uiNaviDelegate = self;
|
||||
}
|
||||
|
||||
#pragma mark - TUINavigationControllerDelegate
|
||||
- (void)navigationControllerDidClickLeftButton:(TUINavigationController *)controller {
|
||||
[self excuteDismissCallback];
|
||||
}
|
||||
|
||||
- (void)navigationControllerDidSideSlideReturn:(TUINavigationController *)controller fromViewController:(UIViewController *)fromViewController {
|
||||
[self excuteDismissCallback];
|
||||
}
|
||||
|
||||
- (void)excuteDismissCallback {
|
||||
if (self.dismissCallback) {
|
||||
NSMutableAttributedString *foldSubTitle = [[NSMutableAttributedString alloc] initWithString:@""];
|
||||
TUIFoldConversationListDataProvider_Minimalist *foldProvider = (TUIFoldConversationListDataProvider_Minimalist *)self.conv.dataProvider;
|
||||
NSArray *needRemoveFromCacheMapArray = foldProvider.needRemoveConversationList;
|
||||
if (self.conv.dataProvider.conversationList.count > 0) {
|
||||
NSMutableArray *sortArray = [NSMutableArray arrayWithArray:self.conv.dataProvider.conversationList];
|
||||
[self sortDataList:sortArray];
|
||||
TUIConversationCellData *lastItem = sortArray[0];
|
||||
if (lastItem && [lastItem isKindOfClass:TUIConversationCellData.class]) {
|
||||
foldSubTitle = lastItem.foldSubTitle;
|
||||
}
|
||||
self.dismissCallback(foldSubTitle, sortArray, needRemoveFromCacheMapArray);
|
||||
} else {
|
||||
self.dismissCallback(foldSubTitle, @[], needRemoveFromCacheMapArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sortDataList:(NSMutableArray<TUIConversationCellData *> *)dataList {
|
||||
[dataList sortUsingComparator:^NSComparisonResult(TUIConversationCellData *obj1, TUIConversationCellData *obj2) {
|
||||
return obj1.orderKey < obj2.orderKey;
|
||||
}];
|
||||
}
|
||||
#pragma mark TUIConversationListControllerListener
|
||||
|
||||
- (NSString *)getConversationDisplayString:(V2TIMConversation *)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;
|
||||
}
|
||||
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) {
|
||||
|
||||
V2TIMUserFullInfo *info = msg.revokerInfo;
|
||||
NSString * revokeReason = msg.revokeReason;
|
||||
BOOL hasRiskContent = msg.hasRiskContent;
|
||||
if (hasRiskContent) {
|
||||
desc = TIMCommonLocalizableString(TUIKitMessageTipsRecallRiskContent);
|
||||
}
|
||||
else if (info) {
|
||||
NSString *userName = info.nickName;
|
||||
desc = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
|
||||
}
|
||||
else if (msg.isSelf) {
|
||||
desc = TIMCommonLocalizableString(TUIKitMessageTipsYouRecallMessage);
|
||||
} else if (msg.userID.length > 0) {
|
||||
desc = TIMCommonLocalizableString(TUIKitMessageTipsOthersRecallMessage);
|
||||
} else if (msg.groupID.length > 0) {
|
||||
NSString *userName = msg.nameCard;
|
||||
if (userName.length == 0) {
|
||||
userName = msg.nickName ?: msg.sender;
|
||||
}
|
||||
desc = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitMessageTipsRecallMessageFormat), userName];
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)conversationListController:(TUIConversationListController_Minimalist *)conversationController
|
||||
didSelectConversation:(TUIConversationCellData *)conversation {
|
||||
NSDictionary *param = @{
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_ConversationID : conversation.conversationID ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_UserID : conversation.userID ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_GroupID : conversation.groupID ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_Title : conversation.title ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AvatarUrl : conversation.faceUrl ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AvatarImage : conversation.avatarImage ?: [UIImage new],
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_Draft : conversation.draftText ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AtTipsStr : conversation.atTipsStr ?: @"",
|
||||
TUICore_TUIChatObjectFactory_ChatViewController_AtMsgSeqs : conversation.atMsgSeqs ?: @[]
|
||||
};
|
||||
[self.navigationController pushViewController:TUICore_TUIChatObjectFactory_ChatViewController_Minimalist param:param forResult:nil];
|
||||
}
|
||||
|
||||
- (UILabel *)noDataTipsLabel {
|
||||
if (_noDataTipsLabel == nil) {
|
||||
_noDataTipsLabel = [[UILabel alloc] init];
|
||||
_noDataTipsLabel.textColor = [UIColor tui_colorWithHex:@"#999999"];
|
||||
_noDataTipsLabel.font = [UIFont systemFontOfSize:14.0];
|
||||
_noDataTipsLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_noDataTipsLabel.text = TIMCommonLocalizableString(TUIKitContactNoGroupChats);
|
||||
_noDataTipsLabel.hidden = YES;
|
||||
}
|
||||
return _noDataTipsLabel;
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user