增加换肤功能
This commit is contained in:
102
TUIKit/TIMCommon/UI_Minimalist/TUIBubbleMessageCell_Minimalist.h
Normal file
102
TUIKit/TIMCommon/UI_Minimalist/TUIBubbleMessageCell_Minimalist.h
Normal file
@@ -0,0 +1,102 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This document declares the TUIBubbleMessageCell_Minimalist class.
|
||||
* Bubble messages, the most common type of messages that contain strings and emoticons.
|
||||
* Both TUIFileMessageCell_Minimalist and TUIVoiceMessageCell_Minimalist inherit from this class and implement the userinterface of bubble messages.
|
||||
* If developers want to customize the bubble message, they can also refer to the implementation methods of the above two message units to implement their own
|
||||
* bubble message unit.
|
||||
*/
|
||||
#import "TUIBubbleMessageCellData.h"
|
||||
#import "TUIMessageCell_Minimalist.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIBubbleMessageCell_Minimalist : TUIMessageCell_Minimalist
|
||||
|
||||
/**
|
||||
* The bubble image view, the message's bubble icon, wraps the message's content on the UI as a background panel for the bubble.
|
||||
*/
|
||||
@property(nonatomic, strong) UIImageView *bubbleView;
|
||||
@property(nonatomic, strong) TUIBubbleMessageCellData *bubbleData;
|
||||
|
||||
- (void)fillWithData:(TUIBubbleMessageCellData *)data;
|
||||
|
||||
+ (CGFloat)getBubbleTop:(TUIBubbleMessageCellData *)data;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUILayoutConfiguration
|
||||
|
||||
@interface TUIBubbleMessageCell_Minimalist (TUILayoutConfiguration)
|
||||
|
||||
/**
|
||||
* Send bubble icon (normal state)
|
||||
* - The send icon of the bubble, assigned to the @bubble when the bubble message was sent.
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *outgoingBubble;
|
||||
|
||||
/**
|
||||
* Send bubble icon (normal state)
|
||||
* - The send icon of the bubble, assigned to the @bubble when the bubble message was sent.
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *outgoingSameBubble;
|
||||
|
||||
/**
|
||||
* Send bubble icon (highlighted state)
|
||||
* - The send icon (highlighted state) of the bubble, assigned to @highlightedBubble when the bubble message was sent.
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *outgoingHighlightedBubble;
|
||||
|
||||
/**
|
||||
* Send bubble icon (highlighted state)
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *outgoingAnimatedHighlightedAlpha20;
|
||||
@property(nonatomic, class) UIImage *outgoingAnimatedHighlightedAlpha50;
|
||||
|
||||
/**
|
||||
*
|
||||
* Receive bubble icon (normal state)
|
||||
* - The receive icon of the bubble, assigned to the @bubble when the bubble message was received.
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *incommingBubble;
|
||||
|
||||
/**
|
||||
*
|
||||
* Receive bubble icon (normal state)
|
||||
* - The receive icon of the bubble, assigned to the @bubble when the bubble message was received.
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *incommingSameBubble;
|
||||
|
||||
/**
|
||||
*
|
||||
* Receive bubble icon (highlighted state)
|
||||
* - The receive icon of the bubble, assigned to @highlightedBubble when the bubble message was received.
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *incommingHighlightedBubble;
|
||||
|
||||
/**
|
||||
*
|
||||
* Receive bubble icon (highlighted state)
|
||||
*/
|
||||
@property(nonatomic, class) UIImage *incommingAnimatedHighlightedAlpha20;
|
||||
@property(nonatomic, class) UIImage *incommingAnimatedHighlightedAlpha50;
|
||||
|
||||
/**
|
||||
* Spacing at the top of the send bubble
|
||||
* - It is used to locate the top of the sent bubble, and is assigned to @bubbleTop when the bubble message was sent.
|
||||
*/
|
||||
@property(nonatomic, class) CGFloat outgoingBubbleTop;
|
||||
|
||||
/**
|
||||
* Spacing at the top of the receiving bubble
|
||||
* - It is used to locate the top of the receive bubble, and is assigned to @bubbleTop when the bubble message was received.
|
||||
*/
|
||||
@property(nonatomic, class) CGFloat incommingBubbleTop;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
356
TUIKit/TIMCommon/UI_Minimalist/TUIBubbleMessageCell_Minimalist.m
Normal file
356
TUIKit/TIMCommon/UI_Minimalist/TUIBubbleMessageCell_Minimalist.m
Normal file
@@ -0,0 +1,356 @@
|
||||
//
|
||||
// TUIBubbleMessageCell_Minimalist.m
|
||||
// TXIMSDK_TUIKit_iOS
|
||||
//
|
||||
// Created by annidyfeng on 2019/5/22.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIBubbleMessageCell_Minimalist.h"
|
||||
#import <TIMCommon/TIMCommonModel.h>
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
|
||||
@implementation TUIBubbleMessageCell_Minimalist
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
if (self) {
|
||||
_bubbleView = [[UIImageView alloc] initWithFrame:self.container.bounds];
|
||||
_bubbleView.userInteractionEnabled = YES;
|
||||
[self.container addSubview:_bubbleView];
|
||||
_bubbleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)fillWithData:(TUIBubbleMessageCellData *)data {
|
||||
[super fillWithData:data];
|
||||
_bubbleData = data;
|
||||
|
||||
if (self.bubbleData.sameToNextMsgSender) {
|
||||
self.bubbleView.image = self.getSameMessageBubble;
|
||||
self.bubbleView.highlightedImage = self.getHighlightSameMessageBubble;
|
||||
} else {
|
||||
self.bubbleView.image = self.getBubble;
|
||||
self.bubbleView.highlightedImage = self.getHighlightBubble;
|
||||
}
|
||||
// tell constraints they need updating
|
||||
[self setNeedsUpdateConstraints];
|
||||
|
||||
// update constraints now so we can animate the change
|
||||
[self updateConstraintsIfNeeded];
|
||||
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// this is Apple's recommended place for adding/updating constraints
|
||||
- (void)updateConstraints {
|
||||
|
||||
[super updateConstraints];
|
||||
[self.bubbleView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(0);
|
||||
make.size.mas_equalTo(self.container);
|
||||
make.top.mas_equalTo(self.container);
|
||||
}];
|
||||
|
||||
CGPoint center = self.retryView.center;
|
||||
center.y = self.bubbleView.center.y;
|
||||
self.retryView.center = center;
|
||||
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)highlightWhenMatchKeyword:(NSString *)keyword {
|
||||
/**
|
||||
* The parent class implements the default highlighting effect - flickering
|
||||
*/
|
||||
if (keyword) {
|
||||
if (self.highlightAnimating) {
|
||||
return;
|
||||
}
|
||||
[self animate:3];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)animate:(int)times {
|
||||
times--;
|
||||
if (times < 0) {
|
||||
if (self.bubbleData.sameToNextMsgSender) {
|
||||
self.bubbleView.image = self.getSameMessageBubble;
|
||||
} else {
|
||||
self.bubbleView.image = self.getBubble;
|
||||
}
|
||||
self.bubbleView.layer.cornerRadius = 0;
|
||||
self.bubbleView.layer.masksToBounds = YES;
|
||||
self.highlightAnimating = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
self.bubbleView.image = self.getAnimateHighlightBubble_alpha50;
|
||||
self.bubbleView.layer.cornerRadius = 12;
|
||||
self.bubbleView.layer.masksToBounds = YES;
|
||||
self.highlightAnimating = YES;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
self.bubbleView.image = self.getAnimateHighlightBubble_alpha20;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (!self.bubbleData.highlightKeyword) {
|
||||
[self animate:0];
|
||||
return;
|
||||
}
|
||||
[self animate:times];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
- (CGFloat)getBubbleTop {
|
||||
return [self.class getBubbleTop:self.bubbleData];
|
||||
}
|
||||
|
||||
- (UIImage *)getBubble {
|
||||
if (!TIMConfig.defaultConfig.enableMessageBubble) {
|
||||
return nil;
|
||||
}
|
||||
if (self.bubbleData.direction == MsgDirectionIncoming) {
|
||||
return self.class.incommingBubble;
|
||||
} else {
|
||||
return self.class.outgoingBubble;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)getHighlightBubble {
|
||||
if (!TIMConfig.defaultConfig.enableMessageBubble) {
|
||||
return nil;
|
||||
}
|
||||
if (self.bubbleData.direction == MsgDirectionIncoming) {
|
||||
return self.class.incommingHighlightedBubble;
|
||||
} else {
|
||||
return self.class.outgoingHighlightedBubble;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)getAnimateHighlightBubble_alpha50 {
|
||||
if (!TIMConfig.defaultConfig.enableMessageBubble) {
|
||||
return nil;
|
||||
}
|
||||
if (self.bubbleData.direction == MsgDirectionIncoming) {
|
||||
return self.class.incommingAnimatedHighlightedAlpha50;
|
||||
} else {
|
||||
return self.class.outgoingAnimatedHighlightedAlpha50;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)getAnimateHighlightBubble_alpha20 {
|
||||
if (!TIMConfig.defaultConfig.enableMessageBubble) {
|
||||
return nil;
|
||||
}
|
||||
if (self.bubbleData.direction == MsgDirectionIncoming) {
|
||||
return self.class.incommingAnimatedHighlightedAlpha20;
|
||||
} else {
|
||||
return self.class.outgoingAnimatedHighlightedAlpha20;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)getSameMessageBubble {
|
||||
if (!TIMConfig.defaultConfig.enableMessageBubble) {
|
||||
return nil;
|
||||
}
|
||||
return self.bubbleData.direction == MsgDirectionIncoming ? self.class.incommingSameBubble : self.class.outgoingSameBubble;
|
||||
}
|
||||
|
||||
- (UIImage *)getHighlightSameMessageBubble {
|
||||
if (!TIMConfig.defaultConfig.enableMessageBubble) {
|
||||
return nil;
|
||||
}
|
||||
return self.getSameMessageBubble;
|
||||
}
|
||||
|
||||
+ (CGFloat)getBubbleTop:(TUIBubbleMessageCellData *)data {
|
||||
if (data.direction == MsgDirectionIncoming) {
|
||||
return self.class.incommingBubbleTop;
|
||||
} else {
|
||||
return self.class.outgoingBubbleTop;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIBubbleMessageCell_Minimalist (TUILayoutConfiguration)
|
||||
|
||||
+ (void)initialize {
|
||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(onThemeChanged:) name:TUIDidApplyingThemeChangedNotfication object:nil];
|
||||
}
|
||||
|
||||
#pragma mark - gOutgoingBubble
|
||||
static UIImage *gOutgoingBubble;
|
||||
+ (UIImage *)outgoingBubble {
|
||||
if (!gOutgoingBubble) {
|
||||
UIImage *defaultImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"SenderTextNodeBkg")];
|
||||
[self setOutgoingBubble:defaultImage];
|
||||
}
|
||||
return gOutgoingBubble;
|
||||
}
|
||||
+ (void)setOutgoingBubble:(UIImage *)outgoingBubble {
|
||||
gOutgoingBubble = [self stretchImage:outgoingBubble];
|
||||
}
|
||||
|
||||
#pragma mark - gOutgoingSameBubble
|
||||
static UIImage *gOutgoingSameBubble;
|
||||
+ (UIImage *)outgoingSameBubble {
|
||||
if (!gOutgoingSameBubble) {
|
||||
UIImage *defaultImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"SenderTextNodeBkg_Same")];
|
||||
[self setOutgoingSameBubble:defaultImage];
|
||||
}
|
||||
return gOutgoingSameBubble;
|
||||
}
|
||||
+ (void)setOutgoingSameBubble:(UIImage *)outgoingSameBubble {
|
||||
gOutgoingSameBubble = [self stretchImage:outgoingSameBubble];
|
||||
}
|
||||
|
||||
#pragma mark - gOutgoingHighlightedBubble
|
||||
static UIImage *gOutgoingHighlightedBubble;
|
||||
+ (UIImage *)outgoingHighlightedBubble {
|
||||
if (!gOutgoingHighlightedBubble) {
|
||||
UIImage *defaultImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"SenderTextNodeBkg")];
|
||||
[self setOutgoingHighlightedBubble:defaultImage];
|
||||
}
|
||||
return gOutgoingHighlightedBubble;
|
||||
}
|
||||
+ (void)setOutgoingHighlightedBubble:(UIImage *)outgoingHighlightedBubble {
|
||||
gOutgoingHighlightedBubble = [self stretchImage:outgoingHighlightedBubble];
|
||||
}
|
||||
|
||||
#pragma mark - gOutgoingAnimatedHighlightedAlpha20
|
||||
static UIImage *gOutgoingAnimatedHighlightedAlpha20;
|
||||
+ (UIImage *)outgoingAnimatedHighlightedAlpha20 {
|
||||
if (!gOutgoingAnimatedHighlightedAlpha20) {
|
||||
UIImage *alpha20 = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"SenderTextNodeBkg_alpha20")];
|
||||
[self setOutgoingAnimatedHighlightedAlpha20:TUIChatDynamicImage(@"chat_bubble_send_alpha20_img", alpha20)];
|
||||
}
|
||||
return gOutgoingAnimatedHighlightedAlpha20;
|
||||
}
|
||||
+ (void)setOutgoingAnimatedHighlightedAlpha20:(UIImage *)outgoingAnimatedHighlightedAlpha20 {
|
||||
gOutgoingAnimatedHighlightedAlpha20 = [self stretchImage:outgoingAnimatedHighlightedAlpha20];
|
||||
}
|
||||
|
||||
#pragma mark - gOutgoingAnimatedHighlightedAlpha50
|
||||
static UIImage *gOutgoingAnimatedHighlightedAlpha50;
|
||||
+ (UIImage *)outgoingAnimatedHighlightedAlpha50 {
|
||||
if (!gOutgoingAnimatedHighlightedAlpha50) {
|
||||
UIImage *alpha50 = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"SenderTextNodeBkg_alpha50")];
|
||||
[self setOutgoingAnimatedHighlightedAlpha50:TUIChatDynamicImage(@"chat_bubble_send_alpha50_img", alpha50)];
|
||||
}
|
||||
return gOutgoingAnimatedHighlightedAlpha50;
|
||||
}
|
||||
+ (void)setOutgoingAnimatedHighlightedAlpha50:(UIImage *)outgoingAnimatedHighlightedAlpha50 {
|
||||
gOutgoingAnimatedHighlightedAlpha50 = [self stretchImage:outgoingAnimatedHighlightedAlpha50];
|
||||
}
|
||||
|
||||
#pragma mark - gIncommingBubble
|
||||
static UIImage *gIncommingBubble;
|
||||
+ (UIImage *)incommingBubble {
|
||||
if (!gIncommingBubble) {
|
||||
UIImage *defaultImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"ReceiverTextNodeBkg")];
|
||||
[self setIncommingBubble:defaultImage];
|
||||
}
|
||||
return gIncommingBubble;
|
||||
}
|
||||
+ (void)setIncommingBubble:(UIImage *)incommingBubble {
|
||||
gIncommingBubble = [self stretchImage:incommingBubble];
|
||||
}
|
||||
|
||||
#pragma mark - gIncommingSameBubble
|
||||
static UIImage *gIncommingSameBubble;
|
||||
+ (UIImage *)incommingSameBubble {
|
||||
if (!gIncommingSameBubble) {
|
||||
UIImage *defaultImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"ReceiverTextNodeBkg_Same")];
|
||||
[self setIncommingSameBubble:defaultImage];
|
||||
}
|
||||
return gIncommingSameBubble;
|
||||
}
|
||||
+ (void)setIncommingSameBubble:(UIImage *)incommingSameBubble {
|
||||
gIncommingSameBubble = [self stretchImage:incommingSameBubble];
|
||||
}
|
||||
|
||||
#pragma mark - gIncommingHighlightedBubble
|
||||
static UIImage *gIncommingHighlightedBubble;
|
||||
+ (UIImage *)incommingHighlightedBubble {
|
||||
if (!gIncommingHighlightedBubble) {
|
||||
UIImage *defaultImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"ReceiverTextNodeBkg")];
|
||||
[self setIncommingHighlightedBubble:defaultImage];
|
||||
}
|
||||
return gIncommingHighlightedBubble;
|
||||
}
|
||||
+ (void)setIncommingHighlightedBubble:(UIImage *)incommingHighlightedBubble {
|
||||
gIncommingHighlightedBubble = [self stretchImage:incommingHighlightedBubble];
|
||||
}
|
||||
|
||||
#pragma mark - gIncommingAnimatedHighlightedAlpha20
|
||||
static UIImage *gIncommingAnimatedHighlightedAlpha20;
|
||||
+ (UIImage *)incommingAnimatedHighlightedAlpha20 {
|
||||
if (!gIncommingAnimatedHighlightedAlpha20) {
|
||||
UIImage *alpha20 = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"ReceiverTextNodeBkg_alpha20")];
|
||||
[self setIncommingAnimatedHighlightedAlpha20:TUIChatDynamicImage(@"chat_bubble_receive_alpha20_img", alpha20)];
|
||||
}
|
||||
return gIncommingAnimatedHighlightedAlpha20;
|
||||
}
|
||||
+ (void)setIncommingAnimatedHighlightedAlpha20:(UIImage *)incommingAnimatedHighlightedAlpha20 {
|
||||
gIncommingAnimatedHighlightedAlpha20 = [self stretchImage:incommingAnimatedHighlightedAlpha20];
|
||||
}
|
||||
|
||||
#pragma mark - gIncommingAnimatedHighlightedAlpha50
|
||||
static UIImage *gIncommingAnimatedHighlightedAlpha50;
|
||||
+ (UIImage *)incommingAnimatedHighlightedAlpha50 {
|
||||
if (!gIncommingAnimatedHighlightedAlpha50) {
|
||||
UIImage *alpha50 = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"ReceiverTextNodeBkg_alpha50")];
|
||||
[self setIncommingAnimatedHighlightedAlpha50:TUIChatDynamicImage(@"chat_bubble_receive_alpha50_img", alpha50)];
|
||||
}
|
||||
return gIncommingAnimatedHighlightedAlpha50;
|
||||
}
|
||||
+ (void)setIncommingAnimatedHighlightedAlpha50:(UIImage *)incommingAnimatedHighlightedAlpha50 {
|
||||
gIncommingAnimatedHighlightedAlpha50 = [self stretchImage:incommingAnimatedHighlightedAlpha50];
|
||||
}
|
||||
|
||||
+ (UIImage *)stretchImage:(UIImage *)oldImage {
|
||||
UIImage *image = [oldImage rtl_imageFlippedForRightToLeftLayoutDirection];
|
||||
UIEdgeInsets insets = rtlEdgeInsetsWithInsets(UIEdgeInsetsFromString(@"{12,12,12,12}"));
|
||||
return [image resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch];
|
||||
}
|
||||
|
||||
static CGFloat gOutgoingBubbleTop = 0;
|
||||
+ (CGFloat)outgoingBubbleTop {
|
||||
return gOutgoingBubbleTop;
|
||||
}
|
||||
|
||||
+ (void)setOutgoingBubbleTop:(CGFloat)outgoingBubble {
|
||||
gOutgoingBubbleTop = outgoingBubble;
|
||||
}
|
||||
|
||||
static CGFloat gIncommingBubbleTop = 0;
|
||||
+ (CGFloat)incommingBubbleTop {
|
||||
return gIncommingBubbleTop;
|
||||
}
|
||||
|
||||
+ (void)setIncommingBubbleTop:(CGFloat)incommingBubbleTop {
|
||||
gIncommingBubbleTop = incommingBubbleTop;
|
||||
}
|
||||
|
||||
+ (void)onThemeChanged:(NSNotification *)notice {
|
||||
gOutgoingBubble = nil;
|
||||
gOutgoingHighlightedBubble = nil;
|
||||
gOutgoingAnimatedHighlightedAlpha50 = nil;
|
||||
gOutgoingAnimatedHighlightedAlpha20 = nil;
|
||||
|
||||
gIncommingBubble = nil;
|
||||
gIncommingHighlightedBubble = nil;
|
||||
gIncommingAnimatedHighlightedAlpha50 = nil;
|
||||
gIncommingAnimatedHighlightedAlpha20 = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// TUICommonGroupInfoCellData_Minimalist.h
|
||||
// TIMCommon
|
||||
//
|
||||
// Created by yiliangwang on 2024/12/26.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TIMCommon/TIMCommonModel.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIGroupButtonCellData_Minimalist : TUICommonCellData
|
||||
@property(nonatomic, strong) NSString *title;
|
||||
@property SEL cbuttonSelector;
|
||||
@property TUIButtonStyle style;
|
||||
@property(nonatomic, strong) UIColor *textColor;
|
||||
@property(nonatomic, assign) BOOL hideSeparatorLine;
|
||||
@property(nonatomic, assign) BOOL isInfoPageLeftButton;
|
||||
@end
|
||||
|
||||
@interface TUIGroupMemberCellData_Minimalist : TUICommonCellData
|
||||
@property(nonatomic, strong) NSString *identifier;
|
||||
|
||||
@property(nonatomic, strong) NSString *name;
|
||||
|
||||
@property(nonatomic, strong) UIImage *avatarImage;
|
||||
|
||||
@property(nonatomic, strong) NSString *avatarUrl;
|
||||
|
||||
@property(nonatomic, assign) BOOL showAccessory;
|
||||
|
||||
@property(nonatomic, copy) NSString *detailName;
|
||||
|
||||
@property NSInteger tag;
|
||||
@end
|
||||
|
||||
@interface TUICommonGroupInfoCellData_Minimalist : NSObject
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// TUICommonGroupInfoCellData_Minimalist.m
|
||||
// TIMCommon
|
||||
//
|
||||
// Created by yiliangwang on 2024/12/26.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import "TUICommonGroupInfoCellData_Minimalist.h"
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
@implementation TUIGroupButtonCellData_Minimalist
|
||||
- (CGFloat)heightOfWidth:(CGFloat)width {
|
||||
return 56;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUIGroupMemberCellData_Minimalist
|
||||
- (CGFloat)heightOfWidth:(CGFloat)width {
|
||||
return kScale390(48);
|
||||
}
|
||||
@end
|
||||
@implementation TUICommonGroupInfoCellData_Minimalist
|
||||
|
||||
@end
|
||||
28
TUIKit/TIMCommon/UI_Minimalist/TUIConfig_Minimalist.h
Normal file
28
TUIKit/TIMCommon/UI_Minimalist/TUIConfig_Minimalist.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// TUIConfig_Minimalist.h
|
||||
// TIMCommon
|
||||
//
|
||||
// Created by Tencent on 2024/7/16.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIConfig_Minimalist : NSObject
|
||||
/**
|
||||
* Show the toast prompt built in TUIKit.
|
||||
* The default value is YES.
|
||||
*/
|
||||
+ (void)enableToast:(BOOL)enable;
|
||||
|
||||
/**
|
||||
* Switch the language of TUIKit.
|
||||
* The currently supported languages are "en", "zh-Hans", and "ar".
|
||||
*/
|
||||
+ (void)switchLanguageToTarget:(NSString *)targetLanguage;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
22
TUIKit/TIMCommon/UI_Minimalist/TUIConfig_Minimalist.m
Normal file
22
TUIKit/TIMCommon/UI_Minimalist/TUIConfig_Minimalist.m
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// TUIConfig_Minimalist.m
|
||||
// TIMCommon
|
||||
//
|
||||
// Created by Tencent on 2024/7/16.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import "TUIConfig_Minimalist.h"
|
||||
#import <TUICore/TUIConfig.h>
|
||||
#import <TUICore/TUIGlobalization.h>
|
||||
|
||||
@implementation TUIConfig_Minimalist
|
||||
|
||||
+ (void)enableToast:(BOOL)enable {
|
||||
[TUIConfig defaultConfig].enableToast = enable;
|
||||
}
|
||||
|
||||
+ (void)switchLanguageToTarget:(NSString *)targetLanguage {
|
||||
[TUIGlobalization setPreferredLanguage:targetLanguage];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// TUIGroupButtonCell_Minimalist.h
|
||||
// TUIGroup
|
||||
//
|
||||
// Created by wyl on 2023/1/4.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <TIMCommon/TIMCommonModel.h>
|
||||
#import <TIMCommon/TUICommonGroupInfoCellData_Minimalist.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIGroupButtonCell_Minimalist : TUICommonTableViewCell
|
||||
@property(nonatomic, strong) UIButton *button;
|
||||
@property(nonatomic, strong) TUIGroupButtonCellData_Minimalist *buttonData;
|
||||
|
||||
- (void)fillWithData:(TUIGroupButtonCellData_Minimalist *)data;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
168
TUIKit/TIMCommon/UI_Minimalist/TUIGroupButtonCell_Minimalist.m
Normal file
168
TUIKit/TIMCommon/UI_Minimalist/TUIGroupButtonCell_Minimalist.m
Normal file
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// TUIGroupButtonCell_Minimalist.m
|
||||
// TUIGroup
|
||||
//
|
||||
// Created by wyl on 2023/1/4.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIGroupButtonCell_Minimalist.h"
|
||||
|
||||
#import <TUICore/TUIThemeManager.h>
|
||||
|
||||
@implementation TUIGroupButtonCell_Minimalist {
|
||||
UIView *_line;
|
||||
}
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
if (self) {
|
||||
[self setupViews];
|
||||
self.changeColorWhenTouched = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupViews {
|
||||
self.backgroundColor = [UIColor tui_colorWithHex:@"#f9f9f9"];
|
||||
self.contentView.backgroundColor = [UIColor tui_colorWithHex:@"#f9f9f9"];
|
||||
|
||||
_button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_button.titleLabel setFont:[UIFont systemFontOfSize:16]];
|
||||
|
||||
[_button addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[self.contentView addSubview:_button];
|
||||
|
||||
[self setSeparatorInset:UIEdgeInsetsMake(0, Screen_Width, 0, 0)];
|
||||
[self setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
self.changeColorWhenTouched = YES;
|
||||
|
||||
_line = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[self.contentView addSubview:_line];
|
||||
_line.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
|
||||
- (void)fillWithData:(TUIGroupButtonCellData_Minimalist *)data {
|
||||
[super fillWithData:data];
|
||||
self.buttonData = data;
|
||||
[_button setTitle:data.title forState:UIControlStateNormal];
|
||||
if(isRTL()) {
|
||||
_button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
||||
}
|
||||
else {
|
||||
_button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||||
}
|
||||
_button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
switch (data.style) {
|
||||
case ButtonGreen: {
|
||||
[_button setTitleColor:TIMCommonDynamicColor(@"form_green_button_text_color", @"#FFFFFF") forState:UIControlStateNormal];
|
||||
_button.backgroundColor = TIMCommonDynamicColor(@"", @"#f9f9f9");
|
||||
[_button setBackgroundImage:[self imageWithColor:TIMCommonDynamicColor(@"", @"#f9f9f9")] forState:UIControlStateHighlighted];
|
||||
} break;
|
||||
case ButtonWhite: {
|
||||
[_button setTitleColor:TIMCommonDynamicColor(@"form_white_button_text_color", @"#000000") forState:UIControlStateNormal];
|
||||
_button.backgroundColor = TIMCommonDynamicColor(@"", @"#f9f9f9");
|
||||
} break;
|
||||
case ButtonRedText: {
|
||||
[_button setTitleColor:TIMCommonDynamicColor(@"form_redtext_button_text_color", @"#FF0000") forState:UIControlStateNormal];
|
||||
_button.backgroundColor = TIMCommonDynamicColor(@"", @"#f9f9f9");
|
||||
|
||||
break;
|
||||
}
|
||||
case ButtonBule: {
|
||||
if (data.isInfoPageLeftButton) {
|
||||
[_button setTitleColor:TIMCommonDynamicColor(@"", @"#0365F9") forState:UIControlStateNormal];
|
||||
_button.backgroundColor = TIMCommonDynamicColor(@"", @"#f9f9f9");
|
||||
} else {
|
||||
[_button.titleLabel setTextColor:[UIColor tui_colorWithHex:@"147AFF"]];
|
||||
_button.backgroundColor = [UIColor tui_colorWithHex:@"#f9f9f9"];
|
||||
_button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
|
||||
_button.layer.cornerRadius = kScale390(10);
|
||||
_button.layer.masksToBounds = YES;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.contentView.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (data.textColor) {
|
||||
[_button setTitleColor:data.textColor forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
_line.hidden = data.hideSeparatorLine;
|
||||
|
||||
// tell constraints they need updating
|
||||
[self setNeedsUpdateConstraints];
|
||||
|
||||
// update constraints now so we can animate the change
|
||||
[self updateConstraintsIfNeeded];
|
||||
|
||||
[self layoutIfNeeded];
|
||||
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// this is Apple's recommended place for adding/updating constraints
|
||||
- (void)updateConstraints {
|
||||
|
||||
[super updateConstraints];
|
||||
[self.button mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(kScale390(20));
|
||||
make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(- kScale390(20));
|
||||
make.top.mas_equalTo(self.contentView);
|
||||
make.bottom.mas_equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
[_line mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(20);
|
||||
make.trailing.mas_equalTo(self.contentView.mas_trailing);
|
||||
make.height.mas_equalTo(0.2);
|
||||
make.bottom.mas_equalTo(self.contentView);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
}
|
||||
|
||||
- (void)onClick:(UIButton *)sender {
|
||||
if (self.buttonData.cbuttonSelector) {
|
||||
UIViewController *vc = self.mm_viewController;
|
||||
if ([vc respondsToSelector:self.buttonData.cbuttonSelector]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[vc performSelector:self.buttonData.cbuttonSelector withObject:self];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didAddSubview:(UIView *)subview {
|
||||
[super didAddSubview:subview];
|
||||
if (subview != self.contentView) {
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)imageWithColor:(UIColor *)color {
|
||||
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
UIGraphicsBeginImageContext(rect.size);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextSetFillColorWithColor(context, [color CGColor]);
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@end
|
||||
33
TUIKit/TIMCommon/UI_Minimalist/TUIMessageCell_Minimalist.h
Normal file
33
TUIKit/TIMCommon/UI_Minimalist/TUIMessageCell_Minimalist.h
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
/**
|
||||
* This document declares the TUIBubbleMessageCell_Minimalist class.
|
||||
* Bubble messages, the most common type of messages that contain strings and emoticons.
|
||||
* Both TUIFileMessageCell_Minimalist and TUIVoiceMessageCell_Minimalist inherit from this class and implement the userinterface of bubble messages.
|
||||
* If developers want to customize the bubble message, they can also refer to the implementation methods of the above two message units to implement their own
|
||||
* bubble message unit.
|
||||
*/
|
||||
#import "TUIMessageCell.h"
|
||||
#import "TUIMessageCellData.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, TUIMessageStatus) {
|
||||
TUIMessageStatus_Unkown,
|
||||
TUIMessageStatus_Sending,
|
||||
TUIMessageStatus_Send_Succ,
|
||||
TUIMessageStatus_Some_People_Read,
|
||||
TUIMessageStatus_All_People_Read,
|
||||
};
|
||||
|
||||
@interface TUIMessageCell_Minimalist : TUIMessageCell
|
||||
@property(nonatomic, strong) UIImageView *replyLineView;
|
||||
@property(nonatomic, strong) NSMutableArray *replyAvatarImageViews;
|
||||
@property(nonatomic, strong) UIImageView *msgStatusView;
|
||||
@property(nonatomic, strong) UILabel *msgTimeLabel;
|
||||
|
||||
- (void)fillWithData:(TUIMessageCellData *)data;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
461
TUIKit/TIMCommon/UI_Minimalist/TUIMessageCell_Minimalist.m
Normal file
461
TUIKit/TIMCommon/UI_Minimalist/TUIMessageCell_Minimalist.m
Normal file
@@ -0,0 +1,461 @@
|
||||
//
|
||||
// TUIMessageCell_Minimalist.m
|
||||
// TXIMSDK_TUIKit_iOS
|
||||
//
|
||||
// Created by annidyfeng on 2019/5/22.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIMessageCell_Minimalist.h"
|
||||
#import <TIMCommon/TIMCommonModel.h>
|
||||
#import <TIMCommon/TIMDefine.h>
|
||||
#import "NSString+TUIEmoji.h"
|
||||
#import <TUICore/TUICore.h>
|
||||
#import <TIMCommon/TUIRelationUserModel.h>
|
||||
|
||||
@interface TUIMessageCell_Minimalist ()
|
||||
@property(nonatomic, assign) TUIMessageStatus status;
|
||||
@property(nonatomic, strong) NSMutableArray *animationImages;
|
||||
@end
|
||||
|
||||
@implementation TUIMessageCell_Minimalist
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
if (self) {
|
||||
_replyLineView = [[UIImageView alloc] initWithFrame:CGRectZero];
|
||||
_replyLineView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self.contentView addSubview:_replyLineView];
|
||||
[self.messageModifyRepliesButton.titleLabel setFont:[UIFont systemFontOfSize:12]];
|
||||
if(isRTL()) {
|
||||
self.messageModifyRepliesButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
||||
}
|
||||
else {
|
||||
self.messageModifyRepliesButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||||
}
|
||||
[self.messageModifyRepliesButton setTitleColor:RGBA(0, 95, 255, 1) forState:UIControlStateNormal];
|
||||
|
||||
_msgStatusView = [[UIImageView alloc] initWithFrame:CGRectZero];
|
||||
_msgStatusView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_msgStatusView.layer.zPosition = FLT_MAX;
|
||||
UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onJumpToMessageInfoPage)];
|
||||
[_msgStatusView addGestureRecognizer:tap2];
|
||||
_msgStatusView.userInteractionEnabled = YES;
|
||||
[self.container addSubview:_msgStatusView];
|
||||
|
||||
_msgTimeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||
_msgTimeLabel.textColor = RGB(102, 102, 102);
|
||||
_msgTimeLabel.font = [UIFont systemFontOfSize:12];
|
||||
_msgTimeLabel.rtlAlignment = TUITextRTLAlignmentTrailing;
|
||||
_msgTimeLabel.layer.zPosition = FLT_MAX;
|
||||
[self.container addSubview:_msgTimeLabel];
|
||||
|
||||
self.animationImages = [NSMutableArray array];
|
||||
for (int i = 1; i <= 45; ++i) {
|
||||
NSString *imageName = [NSString stringWithFormat:@"msg_status_sending_%d", i];
|
||||
NSString *imagePath = TUIChatImagePath_Minimalist(imageName);
|
||||
UIImage *image = [[TUIImageCache sharedInstance] getResourceFromCache:imagePath];
|
||||
[self.animationImages addObject:image];
|
||||
}
|
||||
_replyAvatarImageViews = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)prepareReactTagUI:(UIView *)containerView {
|
||||
NSDictionary *param = @{TUICore_TUIChatExtension_ChatMessageReactPreview_Delegate: self};
|
||||
[TUICore raiseExtension:TUICore_TUIChatExtension_ChatMessageReactPreview_MinimalistExtensionID parentView:containerView param:param];
|
||||
}
|
||||
|
||||
|
||||
- (void)onJumpToMessageInfoPage {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(onJumpToMessageInfoPage:selectCell:)]) {
|
||||
[self.delegate onJumpToMessageInfoPage:self.messageData selectCell:self];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// this is Apple's recommended place for adding/updating constraints
|
||||
- (void)updateConstraints {
|
||||
|
||||
[super updateConstraints];
|
||||
TUIMessageCellLayout *cellLayout = self.messageData.cellLayout;
|
||||
BOOL isInComing = (self.messageData.direction == MsgDirectionIncoming);
|
||||
|
||||
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (isInComing) {
|
||||
make.leading.mas_equalTo(self.container.mas_leading).mas_offset(7);
|
||||
} else {
|
||||
make.trailing.mas_equalTo(self.container.mas_trailing);
|
||||
}
|
||||
if (self.messageData.showName) {
|
||||
make.width.mas_greaterThanOrEqualTo(20);
|
||||
make.height.mas_greaterThanOrEqualTo(20);
|
||||
} else {
|
||||
make.height.mas_equalTo(0);
|
||||
}
|
||||
make.top.mas_equalTo(self.avatarView.mas_top);
|
||||
}];
|
||||
|
||||
[self.selectedIcon mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(3);
|
||||
make.centerY.mas_equalTo(self.container.mas_centerY);
|
||||
if (self.messageData.showCheckBox) {
|
||||
make.width.mas_equalTo(20);
|
||||
make.height.mas_equalTo(20);
|
||||
} else {
|
||||
make.size.mas_equalTo(CGSizeZero);
|
||||
}
|
||||
}];
|
||||
|
||||
[self.timeLabel sizeToFit];
|
||||
[self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.messageData.showMessageTime) {
|
||||
make.width.mas_equalTo(self.timeLabel.frame.size.width);
|
||||
make.height.mas_equalTo(self.timeLabel.frame.size.height);
|
||||
} else {
|
||||
make.width.mas_equalTo(0);
|
||||
make.height.mas_equalTo(0);
|
||||
}
|
||||
}];
|
||||
|
||||
CGSize csize = [self.class getContentSize:self.messageData];
|
||||
CGFloat contentWidth = csize.width;
|
||||
CGFloat contentHeight = csize.height;
|
||||
|
||||
if (self.messageData.direction == MsgDirectionIncoming) {
|
||||
self.avatarView.hidden = !self.messageData.showAvatar;
|
||||
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.messageData.showCheckBox) {
|
||||
make.leading.mas_equalTo(self.selectedIcon.mas_trailing).mas_offset(cellLayout.avatarInsets.left);
|
||||
} else {
|
||||
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(cellLayout.avatarInsets.left);
|
||||
}
|
||||
make.top.mas_equalTo(cellLayout.avatarInsets.top);
|
||||
make.size.mas_equalTo(cellLayout.avatarSize);
|
||||
}];
|
||||
|
||||
[self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.avatarView.mas_trailing).mas_offset(cellLayout.messageInsets.left);
|
||||
make.top.mas_equalTo(self.nameLabel.mas_bottom).mas_offset(cellLayout.messageInsets.top);
|
||||
make.width.mas_equalTo(contentWidth);
|
||||
make.height.mas_equalTo(contentHeight);
|
||||
}];
|
||||
|
||||
CGRect indicatorFrame = self.indicator.frame;
|
||||
[self.indicator mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.container.mas_trailing).mas_offset(8);
|
||||
make.centerY.mas_equalTo(self.container.mas_centerY);
|
||||
make.size.mas_equalTo(indicatorFrame.size);
|
||||
}];
|
||||
self.retryView.frame = self.indicator.frame;
|
||||
self.readReceiptLabel.hidden = YES;
|
||||
} else {
|
||||
if (!self.messageData.showAvatar) {
|
||||
cellLayout.avatarSize = CGSizeZero;
|
||||
}
|
||||
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-cellLayout.avatarInsets.right);
|
||||
make.top.mas_equalTo(cellLayout.avatarInsets.top);
|
||||
make.size.mas_equalTo(cellLayout.avatarSize);
|
||||
}];
|
||||
[self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.avatarView.mas_leading).mas_offset(-cellLayout.messageInsets.right);
|
||||
make.top.mas_equalTo(self.nameLabel.mas_bottom).mas_offset(cellLayout.messageInsets.top);
|
||||
make.width.mas_equalTo(contentWidth);
|
||||
make.height.mas_equalTo(contentHeight);
|
||||
}];
|
||||
|
||||
CGRect indicatorFrame = self.indicator.frame;
|
||||
[self.indicator mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.container.mas_leading).mas_offset(-8);
|
||||
make.centerY.mas_equalTo(self.container.mas_centerY);
|
||||
make.size.mas_equalTo(indicatorFrame.size);
|
||||
}];
|
||||
|
||||
self.retryView.frame = self.indicator.frame;
|
||||
|
||||
[self.readReceiptLabel sizeToFit];
|
||||
[self.readReceiptLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.container.mas_bottom);
|
||||
make.trailing.mas_equalTo(self.container.mas_leading).mas_offset(-8);
|
||||
make.size.mas_equalTo(self.readReceiptLabel.frame.size);
|
||||
}];
|
||||
}
|
||||
|
||||
if (!self.messageModifyRepliesButton.isHidden) {
|
||||
self.messageModifyRepliesButton.mm_sizeToFit();
|
||||
CGFloat repliesBtnTextWidth = self.messageModifyRepliesButton.frame.size.width;
|
||||
[self.messageModifyRepliesButton mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (isInComing) {
|
||||
make.leading.mas_equalTo(self.container.mas_leading);
|
||||
} else {
|
||||
make.trailing.mas_equalTo(self.container.mas_trailing);
|
||||
}
|
||||
make.top.mas_equalTo(self.container.mas_bottom);
|
||||
make.size.mas_equalTo(CGSizeMake(repliesBtnTextWidth + 10, 30));
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
if (self.messageData.showMessageModifyReplies && _replyAvatarImageViews.count > 0) {
|
||||
CGFloat lineViewW = 17;
|
||||
CGFloat avatarSize = 16;
|
||||
CGFloat repliesBtnW = kScale390(50);
|
||||
CGFloat avatarY = self.contentView.mm_h - (self.messageData.sameToNextMsgSender ? avatarSize : avatarSize * 2);
|
||||
if (self.messageData.direction == MsgDirectionIncoming) {
|
||||
UIImageView *preAvatarImageView = nil;
|
||||
for (int i = 0; i < _replyAvatarImageViews.count; ++i) {
|
||||
UIImageView *avatarView = _replyAvatarImageViews[i];
|
||||
if (i == 0) {
|
||||
preAvatarImageView = nil;
|
||||
}
|
||||
else {
|
||||
preAvatarImageView = _replyAvatarImageViews[i-1];
|
||||
}
|
||||
[avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (i == 0) {
|
||||
make.leading.mas_equalTo(_replyLineView.mas_trailing);
|
||||
}
|
||||
else {
|
||||
make.leading.mas_equalTo(preAvatarImageView.mas_centerX);
|
||||
}
|
||||
make.top.mas_equalTo(avatarY);
|
||||
make.width.height.mas_equalTo(avatarSize);
|
||||
|
||||
}];
|
||||
avatarView.layer.masksToBounds = YES;
|
||||
avatarView.layer.cornerRadius = avatarSize / 2.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
__block UIImageView *preAvatarImageView = nil;
|
||||
NSInteger count = _replyAvatarImageViews.count;
|
||||
for (NSInteger i = (count - 1); i >=0; i--) {
|
||||
UIImageView *avatarView = _replyAvatarImageViews[i];
|
||||
[avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (!preAvatarImageView) {
|
||||
make.trailing.mas_equalTo(self.messageModifyRepliesButton.mas_leading);
|
||||
}
|
||||
else {
|
||||
make.trailing.mas_equalTo(preAvatarImageView.mas_centerX);
|
||||
}
|
||||
make.top.mas_equalTo(avatarY);
|
||||
make.width.height.mas_equalTo(avatarSize);
|
||||
}];
|
||||
avatarView.layer.masksToBounds = YES;
|
||||
avatarView.layer.cornerRadius = avatarSize / 2.0;
|
||||
preAvatarImageView = avatarView;
|
||||
}
|
||||
}
|
||||
|
||||
UIImageView *lastAvatarImageView = _replyAvatarImageViews.lastObject;
|
||||
|
||||
[self.messageModifyRepliesButton mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.messageData.direction == MsgDirectionIncoming) {
|
||||
make.leading.mas_equalTo(lastAvatarImageView.mas_trailing);
|
||||
}
|
||||
else {
|
||||
make.trailing.mas_equalTo(_replyLineView.mas_leading);
|
||||
}
|
||||
|
||||
make.top.mas_equalTo(avatarY);
|
||||
make.width.mas_equalTo(repliesBtnW);
|
||||
make.height.mas_equalTo(avatarSize);
|
||||
}];
|
||||
|
||||
[_replyLineView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.messageData.direction == MsgDirectionIncoming) {
|
||||
make.leading.mas_equalTo(self.container.mas_leading).mas_offset(- 1);
|
||||
}
|
||||
else {
|
||||
make.trailing.mas_equalTo(self.container.mas_trailing);
|
||||
}
|
||||
make.top.mas_equalTo(CGRectGetMaxY(self.container.frame) - 14);
|
||||
make.width.mas_equalTo(lineViewW);
|
||||
make.bottom.mas_equalTo(self.messageModifyRepliesButton.mas_centerY);
|
||||
}];
|
||||
} else {
|
||||
_replyLineView.frame = CGRectZero;
|
||||
self.messageModifyRepliesButton.frame = CGRectZero;
|
||||
}
|
||||
|
||||
[_msgTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(38);
|
||||
make.height.mas_equalTo(self.messageData.msgStatusSize.height);
|
||||
make.bottom.mas_equalTo(self.container).mas_offset(-kScale390(9));
|
||||
make.trailing.mas_equalTo(self.container).mas_offset(-kScale390(16));
|
||||
}];
|
||||
[_msgStatusView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(16);
|
||||
make.height.mas_equalTo(self.messageData.msgStatusSize.height);
|
||||
make.bottom.mas_equalTo(self.msgTimeLabel);
|
||||
make.trailing.mas_equalTo(_msgTimeLabel.mas_leading);
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (void)fillWithData:(TUIMessageCellData *)data {
|
||||
[super fillWithData:data];
|
||||
self.readReceiptLabel.hidden = YES;
|
||||
self.messageModifyRepliesButton.hidden = YES;
|
||||
[self.messageModifyRepliesButton setImage:nil forState:UIControlStateNormal];
|
||||
//react
|
||||
[self prepareReactTagUI:self.contentView];
|
||||
|
||||
if (_replyAvatarImageViews.count > 0) {
|
||||
for (UIImageView *imageView in _replyAvatarImageViews) {
|
||||
[imageView removeFromSuperview];
|
||||
}
|
||||
[_replyAvatarImageViews removeAllObjects];
|
||||
}
|
||||
_replyLineView.hidden = YES;
|
||||
if (data.showMessageModifyReplies) {
|
||||
_replyLineView.hidden = NO;
|
||||
self.messageModifyRepliesButton.hidden = NO;
|
||||
|
||||
// line
|
||||
UIImage *lineImage = nil;
|
||||
if (self.messageData.direction == MsgDirectionIncoming) {
|
||||
lineImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_reply_line_income")];
|
||||
} else {
|
||||
lineImage = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_reply_line_outcome")];
|
||||
}
|
||||
lineImage = [lineImage rtl_imageFlippedForRightToLeftLayoutDirection];
|
||||
UIEdgeInsets ei = UIEdgeInsetsFromString(@"{10,0,20,0}");
|
||||
ei = rtlEdgeInsetsWithInsets(ei);
|
||||
_replyLineView.image = [lineImage resizableImageWithCapInsets:ei resizingMode:UIImageResizingModeStretch];
|
||||
|
||||
// avtar
|
||||
NSInteger avatarCount = 0;
|
||||
NSInteger avatarMaxCount = 4;
|
||||
NSMutableDictionary *existSenderMap = [NSMutableDictionary dictionary];
|
||||
for (NSDictionary *senderMap in self.messageData.messageModifyReplies) {
|
||||
NSString *sender = senderMap[@"messageSender"];
|
||||
|
||||
TUIRelationUserModel *userModel = self.messageData.additionalUserInfoResult[sender];
|
||||
NSURL *headUrl = [NSURL URLWithString:userModel.faceURL];
|
||||
|
||||
NSString *existSender = existSenderMap[@"messageSender"];
|
||||
if (!sender || [sender isEqualToString:existSender]) {
|
||||
//exist sender head not add again
|
||||
continue;
|
||||
}
|
||||
UIImageView *avatarView = [[UIImageView alloc] init];
|
||||
if (avatarCount < avatarMaxCount - 1) {
|
||||
existSenderMap[@"messageSender"] = sender;
|
||||
[avatarView sd_setImageWithURL:headUrl placeholderImage:DefaultAvatarImage];
|
||||
} else {
|
||||
[avatarView setImage:[[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_reply_more_icon")]];
|
||||
}
|
||||
[_replyAvatarImageViews addObject:avatarView];
|
||||
[self.contentView addSubview:avatarView];
|
||||
|
||||
if (++avatarCount >= avatarMaxCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_msgTimeLabel.text = [TUITool convertDateToHMStr:self.messageData.innerMessage.timestamp];
|
||||
|
||||
self.indicator.hidden = YES;
|
||||
_msgStatusView.hidden = YES;
|
||||
self.readReceiptLabel.hidden = YES;
|
||||
if (self.messageData.direction == MsgDirectionOutgoing) {
|
||||
self.status = TUIMessageStatus_Unkown;
|
||||
if (self.messageData.status == Msg_Status_Sending || self.messageData.status == Msg_Status_Sending_2) {
|
||||
[self updateMessageStatus:TUIMessageStatus_Sending];
|
||||
} else if (self.messageData.status == Msg_Status_Succ) {
|
||||
[self updateMessageStatus:TUIMessageStatus_Send_Succ];
|
||||
}
|
||||
[self updateReadLabelText];
|
||||
}
|
||||
// tell constraints they need updating
|
||||
[self setNeedsUpdateConstraints];
|
||||
|
||||
// update constraints now so we can animate the change
|
||||
[self updateConstraintsIfNeeded];
|
||||
|
||||
[self layoutIfNeeded];
|
||||
|
||||
}
|
||||
|
||||
- (void)updateReadLabelText {
|
||||
if (self.messageData.innerMessage.groupID.length > 0) {
|
||||
// group message
|
||||
if (self.messageData.messageReceipt == nil) {
|
||||
// haven't received the message receipt yet
|
||||
return;
|
||||
}
|
||||
NSInteger readCount = self.messageData.messageReceipt.readCount;
|
||||
NSInteger unreadCount = self.messageData.messageReceipt.unreadCount;
|
||||
if (unreadCount == 0) {
|
||||
// All read
|
||||
[self updateMessageStatus:TUIMessageStatus_All_People_Read];
|
||||
} else if (readCount > 0) {
|
||||
// Some read
|
||||
[self updateMessageStatus:TUIMessageStatus_Some_People_Read];
|
||||
}
|
||||
} else {
|
||||
// c2c message
|
||||
BOOL isPeerRead = self.messageData.messageReceipt.isPeerRead;
|
||||
if (isPeerRead) {
|
||||
[self updateMessageStatus:TUIMessageStatus_All_People_Read];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateMessageStatus:(TUIMessageStatus)status {
|
||||
if (status <= self.status) {
|
||||
return;
|
||||
}
|
||||
if (self.messageData.showReadReceipt && self.messageData.direction == MsgDirectionOutgoing && self.messageData.innerMessage.needReadReceipt &&
|
||||
(self.messageData.innerMessage.userID || self.messageData.innerMessage.groupID)) {
|
||||
_msgStatusView.hidden = NO;
|
||||
_msgStatusView.image = nil;
|
||||
}
|
||||
if (_msgStatusView.isAnimating) {
|
||||
[_msgStatusView stopAnimating];
|
||||
_msgStatusView.animationImages = nil;
|
||||
}
|
||||
switch (status) {
|
||||
case TUIMessageStatus_Sending: {
|
||||
_msgStatusView.animationImages = self.animationImages;
|
||||
[_msgStatusView startAnimating];
|
||||
} break;
|
||||
case TUIMessageStatus_Send_Succ: {
|
||||
_msgStatusView.image = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_send_succ")];
|
||||
} break;
|
||||
case TUIMessageStatus_Some_People_Read: {
|
||||
_msgStatusView.image = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_some_people_read")];
|
||||
} break;
|
||||
case TUIMessageStatus_All_People_Read: {
|
||||
_msgStatusView.image = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"msg_status_all_people_read")];
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
self.status = status;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
#pragma mark - TUIMessageCellProtocol
|
||||
+ (CGFloat)getHeight:(TUIMessageCellData *)data withWidth:(CGFloat)width {
|
||||
NSAssert([data isKindOfClass:TUIMessageCellData.class], @"data must be kind of TUIMessageCellData");
|
||||
CGFloat height = [super getHeight:data withWidth:width];
|
||||
if (data.sameToNextMsgSender) {
|
||||
height -= kScale375(16);
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user