私信模块:支持接收图片消息

This commit is contained in:
zu
2021-12-02 20:31:29 +08:00
parent b78147c1e1
commit 186d4833df
9 changed files with 308 additions and 49 deletions

View File

@@ -101,6 +101,8 @@
18EE3FF12750D2AD00A452BF /* NIMTimeUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EE3FF02750D2AD00A452BF /* NIMTimeUtils.m */; };
18EE3FF42750FA3700A452BF /* UIView+NIM.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EE3FF32750FA3700A452BF /* UIView+NIM.m */; };
18EE401A2754BA9F00A452BF /* NIMMessageMaker.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EE40182754BA9F00A452BF /* NIMMessageMaker.m */; };
18F403CB2758C66800A6C548 /* MessageContentText.m in Sources */ = {isa = PBXBuildFile; fileRef = 18F403CA2758C66800A6C548 /* MessageContentText.m */; };
18F403EE2758CF2F00A6C548 /* MessageContentImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 18F403ED2758CF2F00A6C548 /* MessageContentImage.m */; };
73FFADDC93E195344047A2EC /* Pods_xplan_ios.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CACF623970097D653132D69A /* Pods_xplan_ios.framework */; };
9B0E1C5926E77022005D4442 /* BaseNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0E1C5826E77022005D4442 /* BaseNavigationController.m */; };
9B7D804A2753783D003DAC0C /* SessionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D80492753783D003DAC0C /* SessionViewController.m */; };
@@ -462,6 +464,11 @@
18EE3FF32750FA3700A452BF /* UIView+NIM.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+NIM.m"; sourceTree = "<group>"; };
18EE40182754BA9F00A452BF /* NIMMessageMaker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NIMMessageMaker.m; sourceTree = "<group>"; };
18EE40192754BA9F00A452BF /* NIMMessageMaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NIMMessageMaker.h; sourceTree = "<group>"; };
18F403A32758B5F900A6C548 /* MessageContentProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageContentProtocol.h; sourceTree = "<group>"; };
18F403C92758C66800A6C548 /* MessageContentText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageContentText.h; sourceTree = "<group>"; };
18F403CA2758C66800A6C548 /* MessageContentText.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageContentText.m; sourceTree = "<group>"; };
18F403EC2758CF2F00A6C548 /* MessageContentImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageContentImage.h; sourceTree = "<group>"; };
18F403ED2758CF2F00A6C548 /* MessageContentImage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageContentImage.m; sourceTree = "<group>"; };
7DB00EC07F1D0ADFF900B38D /* Pods-xplan-ios.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-xplan-ios.debug.xcconfig"; path = "Target Support Files/Pods-xplan-ios/Pods-xplan-ios.debug.xcconfig"; sourceTree = "<group>"; };
9B0E1C5726E77022005D4442 /* BaseNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseNavigationController.h; sourceTree = "<group>"; };
9B0E1C5826E77022005D4442 /* BaseNavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseNavigationController.m; sourceTree = "<group>"; };
@@ -1385,6 +1392,18 @@
path = NIMViews;
sourceTree = "<group>";
};
18F403A72758B67900A6C548 /* Content */ = {
isa = PBXGroup;
children = (
18F403A32758B5F900A6C548 /* MessageContentProtocol.h */,
18F403C92758C66800A6C548 /* MessageContentText.h */,
18F403CA2758C66800A6C548 /* MessageContentText.m */,
18F403EC2758CF2F00A6C548 /* MessageContentImage.h */,
18F403ED2758CF2F00A6C548 /* MessageContentImage.m */,
);
path = Content;
sourceTree = "<group>";
};
9B7D804727537819003DAC0C /* Session */ = {
isa = PBXGroup;
children = (
@@ -1394,6 +1413,7 @@
9B7D80552753C595003DAC0C /* SendMessageView.m */,
9B7D804B27537950003DAC0C /* MessageCell.h */,
9B7D804C27537950003DAC0C /* MessageCell.m */,
18F403A72758B67900A6C548 /* Content */,
);
path = Session;
sourceTree = "<group>";
@@ -2456,6 +2476,7 @@
189DD67E26E1FD8900AB55B1 /* UIImage+Utils.m in Sources */,
E824545626F5E51900BE8163 /* XPMineVerifIdentityViewController.m in Sources */,
186A534726FC6ED900D67B2C /* TTAlertConfig.m in Sources */,
18F403EE2758CF2F00A6C548 /* MessageContentImage.m in Sources */,
18E7B31E26F0984C0064BC9B /* UserLevelVo.m in Sources */,
E874B88B27215EAF003954B9 /* MicroQueueModel.m in Sources */,
E8EE827D272B9A2300A17217 /* XPRoomSendTextView.m in Sources */,
@@ -2536,6 +2557,7 @@
E8E70D8F26F2F5DB00F03460 /* XPMineMenuTableViewCell.m in Sources */,
187EEEE126E89BFB002833B2 /* AccountModel.m in Sources */,
E8AC722126F47E23007D6E91 /* XPMineAboutUsViewController.m in Sources */,
18F403CB2758C66800A6C548 /* MessageContentText.m in Sources */,
E88B5CC526FB42B000DA9178 /* XPMineUserInfoHeaderView.m in Sources */,
E8EEB8FB26FC2874007C6EBA /* XPMineUserInfoTableViewCell.m in Sources */,
E8AC721626F46B06007D6E91 /* XPMineSettingTableViewCell.m in Sources */,

View File

@@ -0,0 +1,17 @@
//
// MessageContentImage.h
// xplan-ios
//
// Created by zu on 2021/12/2.
//
#import <UIKit/UIKit.h>
#import "MessageContentProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface MessageContentImage : UIView<MessageContentProtocol>
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,86 @@
//
// MessageContentImage.m
// xplan-ios
//
// Created by zu on 2021/12/2.
//
#import "MessageContentImage.h"
#import "NetImageView.h"
#import <NIMSDK/NIMSDK.h>
#import <Masonry/Masonry.h>
#define MESSAGE_IMAGE_PADDING 10
#define MESSAGE_IMAGE_MAX_SIZE (CONTENT_WIDTH_MAX / 3 * 2)
@interface MessageContentImage()
@property (nonatomic, strong) NetImageView * messageImage;
@end
@implementation MessageContentImage
- (instancetype)init {
self = [super init];
if (self) {
[self addSubview:self.messageImage];
[self.messageImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self).with.insets(UIEdgeInsetsMake(MESSAGE_IMAGE_PADDING, MESSAGE_IMAGE_PADDING, MESSAGE_IMAGE_PADDING, MESSAGE_IMAGE_PADDING));
make.width.height.mas_equalTo(MESSAGE_IMAGE_MAX_SIZE);
}];
}
return self;
}
+ (CGFloat)measureHeight:(NIMMessage *)message {
if (!message || message.messageType != NIMMessageTypeImage) return 0;
NIMImageObject * imageObject = (NIMImageObject*) message.messageObject;
NSData *imageData = [[NSData alloc] initWithContentsOfFile:imageObject.thumbPath];
UIImage *image = [UIImage imageWithData:imageData scale:[UIScreen mainScreen].scale];
if (image && image.size.width > 0 && image.size.height > 0) {
return MIN(MESSAGE_IMAGE_MAX_SIZE, image.size.height / image.size.width * MESSAGE_IMAGE_MAX_SIZE) + CONTENT_PADDING_V_TOTAL;
}
return MESSAGE_IMAGE_MAX_SIZE + CONTENT_PADDING_V_TOTAL;
}
- (void)render:(NIMMessage *)message {
CGFloat height = MESSAGE_IMAGE_MAX_SIZE;
CGFloat imageHeight = height - MESSAGE_IMAGE_PADDING * 2;
CGFloat imageWidth = imageHeight;
UIImage *image;
if (message && !message.isOutgoingMsg
&& message.attachmentDownloadState == NIMMessageAttachmentDownloadStateNeedDownload) {
[[NIMSDK sharedSDK].chatManager fetchMessageAttachment:message error:nil];
} else {
NIMImageObject * imageObject = (NIMImageObject*) message.messageObject;
NSData *imageData = [[NSData alloc] initWithContentsOfFile:imageObject.thumbPath];
image = [UIImage imageWithData:imageData scale:[UIScreen mainScreen].scale];
if (image && image.size.width > 0 && image.size.height > 0) {
height = MIN(MESSAGE_IMAGE_MAX_SIZE, image.size.height / image.size.width * MESSAGE_IMAGE_MAX_SIZE);
imageHeight = height - MESSAGE_IMAGE_PADDING * 2;
imageWidth = image.size.width / image.size.height * imageHeight;
}
}
[self.messageImage mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(imageHeight);
make.width.mas_equalTo(imageWidth);
}];
if (image) {
self.messageImage.image = image;
}
}
- (NetImageView *)messageImage {
if (!_messageImage) {
_messageImage = [[NetImageView alloc] init];
}
return _messageImage;
}
@end

View File

@@ -0,0 +1,27 @@
//
// MessageContentProtocol.h
// xplan-ios
//
// Created by zu on 2021/12/2.
//
#import <Foundation/Foundation.h>
#import "XPMacro.h"
@class NIMMessage;
NS_ASSUME_NONNULL_BEGIN
#define AVATAR_SIZE 45
#define AVATAR_MARGIN_H 15
#define CONTENT_WIDTH_MAX (KScreenWidth - AVATAR_MARGIN_H * 2 * 2 - AVATAR_SIZE * 2)
#define CONTENT_PADDING_V_TOTAL (5 + 15 * 2)
@protocol MessageContentProtocol <NSObject>
+ (CGFloat)measureHeight:(NIMMessage *)message;
- (void)render:(NIMMessage *)message;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
//
// MessageContentText.h
// xplan-ios
//
// Created by zu on 2021/12/2.
//
#import <UIKit/UIKit.h>
#import "MessageContentProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface MessageContentText : UIView<MessageContentProtocol>
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,80 @@
//
// MessageContentText.m
// xplan-ios
//
// Created by zu on 2021/12/2.
//
#import "MessageContentText.h"
#import "ThemeColor.h"
#import <NIMSDK/NIMSDK.h>
#import <Masonry/Masonry.h>
#define MESSAGE_TEXT_PADDING 10
@interface MessageContentText()
/**
*/
@property (nonatomic, strong) UILabel * messageText;
@end
@implementation MessageContentText
+ (CGFloat)measureHeight:(NIMMessage *)message {
NSString * messageText = message.text;
if (!messageText) {
messageText = @"未知消息类型";
}
CGSize dstRect = CGSizeMake(CONTENT_WIDTH_MAX - MESSAGE_TEXT_PADDING * 2, MAXFLOAT);
CGFloat msgHeight = [messageText boundingRectWithSize:dstRect options:NSStringDrawingUsesLineFragmentOrigin attributes:[MessageContentText messageTextAttibutes] context:nil].size.height;
return msgHeight + MESSAGE_TEXT_PADDING * 2 + CONTENT_PADDING_V_TOTAL;
}
+ (NSDictionary<NSAttributedStringKey, id> *)messageTextAttibutes {
UIFont *font = [UIFont systemFontOfSize:13.f];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:2.5];
return @{
NSFontAttributeName:font,
NSParagraphStyleAttributeName: paragraphStyle
};
}
- (instancetype)init {
self = [super init];
if (self) {
[self addSubview:self.messageText];
[self.messageText mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self).with.insets(UIEdgeInsetsMake(MESSAGE_TEXT_PADDING, MESSAGE_TEXT_PADDING, MESSAGE_TEXT_PADDING, MESSAGE_TEXT_PADDING));
}];
}
return self;
}
- (void)render:(nonnull NIMMessage *)message {
NSString * messageText = message.text;
if (!messageText || (message.messageType != NIMMessageTypeTip && message.messageType != NIMMessageTypeText)) {
messageText = @"未知消息类型";
}
_messageText.attributedText = [[NSAttributedString alloc] initWithString:messageText attributes:[MessageContentText messageTextAttibutes]];
}
- (UILabel *)messageText {
if (!_messageText) {
_messageText = [[UILabel alloc]initWithFrame:CGRectZero];
_messageText.preferredMaxLayoutWidth = CONTENT_WIDTH_MAX - MESSAGE_TEXT_PADDING * 2;
_messageText.textColor = ThemeColor.mainTextColor;
_messageText.numberOfLines = 0;
}
return _messageText;
}
@end

View File

@@ -6,6 +6,10 @@
//
#import "MessageCell.h"
#import "MessageContentProtocol.h"
#import "MessageContentText.h"
#import "MessageContentImage.h"
#import "NetImageView.h"
#import "ThemeColor.h"
@@ -14,6 +18,8 @@
@interface MessageCell()
@property (nonatomic, assign) NIMMessageType messageType;
/**
*/
@@ -32,47 +38,34 @@
@property (nonatomic, strong) MASConstraint * messageBackgroundRight;
/**
*/
@property (nonatomic, strong) UILabel * messageText;
@property (nonatomic, strong) UIView<MessageContentProtocol> * messageContent;
@end
@implementation MessageCell
/**
Text Message
MeasureLayout NIMMessageType measure Message content view
*/
+ (CGFloat)measureHeight:(NIMMessage *)message {
CGFloat minHeight = 45 + 15 * 2;
CGFloat minHeight = AVATAR_SIZE + AVATAR_MARGIN_H * 2;
if (!message) {
return minHeight;
}
NSString * messageText = message.text;
if (!messageText || (message.messageType != NIMMessageTypeTip && message.messageType != NIMMessageTypeText)) {
messageText = @"未知消息类型";
CGFloat mesuredHeight = 0;
switch (message.messageType) {
case NIMMessageTypeText:
case NIMMessageTypeTip:
mesuredHeight = [MessageContentText measureHeight:message];
break;
case NIMMessageTypeImage:
mesuredHeight = [MessageContentImage measureHeight:message];
break;
default:
break;
}
CGSize dstRect = CGSizeMake(KScreenWidth - 15 * 2 * 2 - 45 * 2 - 10 * 2, MAXFLOAT);
CGFloat msgHeight = [messageText boundingRectWithSize:dstRect options:NSStringDrawingUsesLineFragmentOrigin attributes:[self messageTextAttibutes] context:nil].size.height;
CGFloat height = msgHeight + 5 + 15 * 2;
return MAX(minHeight, height);
}
+ (NSDictionary<NSAttributedStringKey, id> *)messageTextAttibutes {
UIFont *font = [UIFont systemFontOfSize:13.f];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:2.5];
return @{
NSFontAttributeName:font,
NSParagraphStyleAttributeName: paragraphStyle
};
return MAX(minHeight, mesuredHeight);
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
@@ -91,7 +84,6 @@
self.rightAvatar.backgroundColor = UIColor.blueColor;
[self.contentView addSubview:self.leftAvatar];
[self.contentView addSubview:self.rightAvatar];
[self.messageBackground addSubview:self.messageText];
[self.contentView addSubview:self.messageBackground];
}
@@ -112,10 +104,6 @@
self.messageBackgroundRight = make.right.mas_equalTo(self.rightAvatar.mas_left).offset(-15);
make.top.mas_equalTo(self).offset(20);
}];
[self.messageText mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.messageBackground).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];
}
- (void)renderWithMessage:(NIMMessage *)message {
@@ -136,12 +124,32 @@
self.leftAvatar.imageUrl = avatarUrl;
}
NSString * messageText = message.text;
if (!messageText || (message.messageType != NIMMessageTypeTip && message.messageType != NIMMessageTypeText)) {
messageText = @"未知消息类型";
if (self.messageType != message.messageType || !self.messageContent) {
if (self.messageContent) {
[self.messageContent removeFromSuperview];
}
switch (message.messageType) {
case NIMMessageTypeText:
case NIMMessageTypeTip:
self.messageContent = [[MessageContentText alloc] init];
break;
case NIMMessageTypeImage:
self.messageContent = [[MessageContentImage alloc] init];
break;
default:
self.messageContent = [[MessageContentText alloc] init];
break;
}
self.messageType = message.messageType;
[self.messageBackground addSubview:self.messageContent];
[self.messageContent mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.right.bottom.mas_equalTo(self.messageBackground);
}];
}
_messageText.attributedText = [[NSAttributedString alloc] initWithString:messageText attributes:[MessageCell messageTextAttibutes]];
[self.messageContent render:message];
}
- (NetImageView *)leftAvatar {
@@ -182,14 +190,4 @@
return _messageBackground;
}
- (UILabel *)messageText {
if (!_messageText) {
_messageText = [[UILabel alloc]initWithFrame:CGRectZero];
_messageText.preferredMaxLayoutWidth = KScreenWidth - 15 * 2 * 2 - 45 * 2 - 10 * 2;
_messageText.textColor = ThemeColor.mainTextColor;
_messageText.numberOfLines = 0;
}
return _messageText;
}
@end

View File

@@ -150,6 +150,18 @@
[self.sessionTableView nim_scrollToBottom:YES];
}
- (void)fetchMessageAttachment:(NIMMessage *)message didCompleteWithError:(NSError *)error {
if (![message.session isEqual:self.session]) return;
for (NIMMessage * msg in self.messages) {
if ([msg.messageId isEqualToString:message.messageId]) {
NSInteger index = [self.messages indexOfObject:msg];
[self.messages replaceObjectAtIndex:index withObject:message];
[self.sessionTableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
break;
}
}
}
#pragma mark - NIMConversationManagerDelegate
- (void)messagesDeletedInSession:(NIMSession *)session {
[self.messages removeAllObjects];

View File

@@ -159,7 +159,7 @@
me = [[XPMineViewController alloc] init];
} else {
game = [[BaseViewController alloc]init];
msg = [[BaseViewController alloc]init];
msg = [[SessionListViewController alloc]init];
me = [[BaseViewController alloc]init];
}