私信模块:私信页面
This commit is contained in:
@@ -102,6 +102,10 @@
|
||||
18EE3FF42750FA3700A452BF /* UIView+NIM.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EE3FF32750FA3700A452BF /* UIView+NIM.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 */; };
|
||||
9B7D804D27537950003DAC0C /* MessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D804C27537950003DAC0C /* MessageCell.m */; };
|
||||
9B7D80502753AA9D003DAC0C /* UITableView+NIMScrollToBottom.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D804E2753AA9D003DAC0C /* UITableView+NIMScrollToBottom.m */; };
|
||||
9B7D80562753C595003DAC0C /* SendMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D80552753C595003DAC0C /* SendMessageView.m */; };
|
||||
E80487652717DDD9008595F2 /* XPRoomMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = E80487642717DDD9008595F2 /* XPRoomMenuItem.m */; };
|
||||
E811FFF72742367B00918544 /* XPGiftEmptyCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E811FFF62742367B00918544 /* XPGiftEmptyCollectionViewCell.m */; };
|
||||
E8133916273E532D00708B66 /* XPGiftItemCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E8133915273E532D00708B66 /* XPGiftItemCollectionViewCell.m */; };
|
||||
@@ -458,6 +462,14 @@
|
||||
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>"; };
|
||||
9B7D80482753783D003DAC0C /* SessionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SessionViewController.h; sourceTree = "<group>"; };
|
||||
9B7D80492753783D003DAC0C /* SessionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SessionViewController.m; sourceTree = "<group>"; };
|
||||
9B7D804B27537950003DAC0C /* MessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageCell.h; sourceTree = "<group>"; };
|
||||
9B7D804C27537950003DAC0C /* MessageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageCell.m; sourceTree = "<group>"; };
|
||||
9B7D804E2753AA9D003DAC0C /* UITableView+NIMScrollToBottom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+NIMScrollToBottom.m"; sourceTree = "<group>"; };
|
||||
9B7D804F2753AA9D003DAC0C /* UITableView+NIMScrollToBottom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+NIMScrollToBottom.h"; sourceTree = "<group>"; };
|
||||
9B7D80542753C595003DAC0C /* SendMessageView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SendMessageView.h; sourceTree = "<group>"; };
|
||||
9B7D80552753C595003DAC0C /* SendMessageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SendMessageView.m; sourceTree = "<group>"; };
|
||||
9BB865B4272076140029CDE0 /* RtcImplDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RtcImplDelegate.h; sourceTree = "<group>"; };
|
||||
B66633E061B1B34177CD011C /* Pods-xplan-ios.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-xplan-ios.release.xcconfig"; path = "Target Support Files/Pods-xplan-ios/Pods-xplan-ios.release.xcconfig"; sourceTree = "<group>"; };
|
||||
CACF623970097D653132D69A /* Pods_xplan_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_xplan_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -1288,18 +1300,13 @@
|
||||
18A61BCC274F72ED00A09A54 /* Message */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
18A61BE6274F9CF000A09A54 /* SessionListViewController.h */,
|
||||
18A61BE7274F9CF000A09A54 /* SessionListViewController.m */,
|
||||
18EE3FDD2750C1F700A452BF /* SessionListCell.h */,
|
||||
18EE3FDE2750C1F700A452BF /* SessionListCell.m */,
|
||||
18EE3FE02750C29D00A452BF /* NIMBadgeView.h */,
|
||||
18EE3FE12750C29D00A452BF /* NIMBadgeView.m */,
|
||||
18EE3FF72754B01D00A452BF /* NIMViews */,
|
||||
18EE3FF52754AFD900A452BF /* SessionList */,
|
||||
9B7D804727537819003DAC0C /* Session */,
|
||||
18EE3FEC2750CE6D00A452BF /* NIMMessageUtils.h */,
|
||||
18EE3FED2750CE6D00A452BF /* NIMMessageUtils.m */,
|
||||
18EE3FEF2750D2AD00A452BF /* NIMTimeUtils.h */,
|
||||
18EE3FF02750D2AD00A452BF /* NIMTimeUtils.m */,
|
||||
18EE3FF22750FA3700A452BF /* UIView+NIM.h */,
|
||||
18EE3FF32750FA3700A452BF /* UIView+NIM.m */,
|
||||
);
|
||||
path = Message;
|
||||
sourceTree = "<group>";
|
||||
@@ -1349,6 +1356,43 @@
|
||||
path = XplanFrameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
18EE3FF52754AFD900A452BF /* SessionList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
18A61BE6274F9CF000A09A54 /* SessionListViewController.h */,
|
||||
18A61BE7274F9CF000A09A54 /* SessionListViewController.m */,
|
||||
18EE3FDD2750C1F700A452BF /* SessionListCell.h */,
|
||||
18EE3FDE2750C1F700A452BF /* SessionListCell.m */,
|
||||
);
|
||||
path = SessionList;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
18EE3FF72754B01D00A452BF /* NIMViews */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
18EE3FE02750C29D00A452BF /* NIMBadgeView.h */,
|
||||
18EE3FE12750C29D00A452BF /* NIMBadgeView.m */,
|
||||
9B7D804F2753AA9D003DAC0C /* UITableView+NIMScrollToBottom.h */,
|
||||
9B7D804E2753AA9D003DAC0C /* UITableView+NIMScrollToBottom.m */,
|
||||
18EE3FF22750FA3700A452BF /* UIView+NIM.h */,
|
||||
18EE3FF32750FA3700A452BF /* UIView+NIM.m */,
|
||||
);
|
||||
path = NIMViews;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9B7D804727537819003DAC0C /* Session */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9B7D80482753783D003DAC0C /* SessionViewController.h */,
|
||||
9B7D80492753783D003DAC0C /* SessionViewController.m */,
|
||||
9B7D80542753C595003DAC0C /* SendMessageView.h */,
|
||||
9B7D80552753C595003DAC0C /* SendMessageView.m */,
|
||||
9B7D804B27537950003DAC0C /* MessageCell.h */,
|
||||
9B7D804C27537950003DAC0C /* MessageCell.m */,
|
||||
);
|
||||
path = Session;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BFB922F5D81845AC32D1E1ED /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2318,6 +2362,7 @@
|
||||
E824544E26F5BC1A00BE8163 /* XPMineModifPayPwdView.m in Sources */,
|
||||
E8B825CA26EA1231009E8E9F /* LoginVerifCodeViewController.m in Sources */,
|
||||
189DD76226E60DDC00AB55B1 /* Api+Login.m in Sources */,
|
||||
9B7D80502753AA9D003DAC0C /* UITableView+NIMScrollToBottom.m in Sources */,
|
||||
18E7B22626E8CDCF0064BC9B /* XplanFlutterBoostDelegate.m in Sources */,
|
||||
E8EEB8F326FC2050007C6EBA /* SDWaitingView.m in Sources */,
|
||||
E8788942273A55AD00BF1D57 /* XPGiftUsersView.m in Sources */,
|
||||
@@ -2340,6 +2385,7 @@
|
||||
E890BC0D273D09A50007C46B /* XPGiftCountView.m in Sources */,
|
||||
E8AC722F26F49610007D6E91 /* XPMineNotificationItemModel.m in Sources */,
|
||||
E8E70D7A26F2F16600F03460 /* XPMinePresent.m in Sources */,
|
||||
9B7D80562753C595003DAC0C /* SendMessageView.m in Sources */,
|
||||
E84B0E3F2727EDF6008818C6 /* XPRoomMessageTableViewCell.m in Sources */,
|
||||
E8EEB8F226FC2050007C6EBA /* SDPhotoBrowser.m in Sources */,
|
||||
E81C27AB26EF2D920031E639 /* ThirdUserInfo.m in Sources */,
|
||||
@@ -2368,6 +2414,7 @@
|
||||
186A534E26FC6ED900D67B2C /* TTPopupService.m in Sources */,
|
||||
18A61BD7274F7F6900A09A54 /* NetImageConfig.m in Sources */,
|
||||
E8AC722426F47E5E007D6E91 /* XPMineFeedbackViewController.m in Sources */,
|
||||
9B7D804D27537950003DAC0C /* MessageCell.m in Sources */,
|
||||
E81366E326F0A1FC0076364C /* LoginBindPhoneViewController.m in Sources */,
|
||||
189DD68426E1FDBB00AB55B1 /* XCHUDTool.m in Sources */,
|
||||
189DD73F26E21C3F00AB55B1 /* YYUtility+Carrier.m in Sources */,
|
||||
@@ -2468,6 +2515,7 @@
|
||||
E824546426F5FF1C00BE8163 /* XPMineResetPayPasswordPresenter.m in Sources */,
|
||||
E884C3722743AEDE00E1EBED /* CustomAttachmentDecoder.m in Sources */,
|
||||
18EE3FEE2750CE6D00A452BF /* NIMMessageUtils.m in Sources */,
|
||||
9B7D804A2753783D003DAC0C /* SessionViewController.m in Sources */,
|
||||
E8B846BC26FD7C1200A777FE /* UploadImage.m in Sources */,
|
||||
186A534D26FC6ED900D67B2C /* TTActionSheetView.m in Sources */,
|
||||
E83DB481274649FB00D8CBD1 /* XPGiftBannerUserInfoModel.m in Sources */,
|
||||
|
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// UITableView+NTESScrollToBottom.h
|
||||
// NIMDemo
|
||||
//
|
||||
// Created by chris.
|
||||
// Copyright (c) 2015年 Netease. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UITableView (NIMKit)
|
||||
|
||||
- (void)nim_scrollToBottom:(BOOL)animation;
|
||||
@end
|
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// UITableView+NTESScrollToBottom.m
|
||||
// NIMDemo
|
||||
//
|
||||
// Created by chris.
|
||||
// Copyright (c) 2015年 Netease. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UITableView+NIMScrollToBottom.h"
|
||||
|
||||
@implementation UITableView (NIMKit)
|
||||
|
||||
- (void)nim_scrollToBottom:(BOOL)animation
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
NSInteger row = [self numberOfRowsInSection:0] - 1;
|
||||
if (row > 0)
|
||||
{
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
|
||||
[self scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:animation];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@end
|
20
xplan-ios/Main/Message/Session/MessageCell.h
Normal file
20
xplan-ios/Main/Message/Session/MessageCell.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// MessageCell.h
|
||||
// xplan-ios
|
||||
//
|
||||
// Created by zu on 2021/11/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <NIMSDK/NIMSDK.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MessageCell : UITableViewCell
|
||||
|
||||
+ (CGFloat)measureHeight:(NIMMessage *)message;
|
||||
- (void)renderWithMessage:(NIMMessage *)message;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
193
xplan-ios/Main/Message/Session/MessageCell.m
Normal file
193
xplan-ios/Main/Message/Session/MessageCell.m
Normal file
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// MessageCell.m
|
||||
// xplan-ios
|
||||
//
|
||||
// Created by zu on 2021/11/28.
|
||||
//
|
||||
|
||||
#import "MessageCell.h"
|
||||
#import "NetImageView.h"
|
||||
#import "ThemeColor.h"
|
||||
|
||||
#import "XPMacro.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface MessageCell()
|
||||
|
||||
/**
|
||||
左侧头像(私聊对象)
|
||||
*/
|
||||
@property (nonatomic, strong) NetImageView * leftAvatar;
|
||||
|
||||
/**
|
||||
右侧头像(自己)
|
||||
*/
|
||||
@property (nonatomic, strong) NetImageView * rightAvatar;
|
||||
|
||||
/**
|
||||
消息背景
|
||||
*/
|
||||
@property (nonatomic, strong) UIView * messageBackground;
|
||||
@property (nonatomic, strong) MASConstraint * messageBackgroundLeft;
|
||||
@property (nonatomic, strong) MASConstraint * messageBackgroundRight;
|
||||
|
||||
/**
|
||||
消息文本
|
||||
*/
|
||||
@property (nonatomic, strong) UILabel * messageText;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MessageCell
|
||||
|
||||
/**
|
||||
当前仅支持 Text Message。
|
||||
|
||||
扩展方向:
|
||||
新增Measure(Layout)工具类,按照 NIMMessageType 进行 measure 和生成对应的 Message content view。
|
||||
*/
|
||||
+ (CGFloat)measureHeight:(NIMMessage *)message {
|
||||
CGFloat minHeight = 45 + 15 * 2;
|
||||
if (!message) {
|
||||
return minHeight;
|
||||
}
|
||||
|
||||
NSString * messageText = message.text;
|
||||
if (!messageText || (message.messageType != NIMMessageTypeTip && message.messageType != NIMMessageTypeText)) {
|
||||
messageText = @"未知消息类型";
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
if (self) {
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[self initViews];
|
||||
[self initLayout];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initViews {
|
||||
self.backgroundColor = UIColor.clearColor;
|
||||
self.leftAvatar.backgroundColor = UIColor.redColor;
|
||||
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];
|
||||
}
|
||||
|
||||
- (void)initLayout {
|
||||
[self.leftAvatar mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.top.mas_equalTo(self).offset(15);
|
||||
make.width.height.mas_equalTo(45);
|
||||
}];
|
||||
|
||||
[self.rightAvatar mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self).offset(15);
|
||||
make.right.mas_equalTo(self).offset(-15);
|
||||
make.width.height.mas_equalTo(45);
|
||||
}];
|
||||
|
||||
[self.messageBackground mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
self.messageBackgroundLeft = make.left.mas_equalTo(self.leftAvatar.mas_right).offset(15);
|
||||
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 {
|
||||
NSString * avatarUrl = [[NIMSDK sharedSDK].userManager userInfo:message.from].userInfo.avatarUrl;
|
||||
avatarUrl = [avatarUrl stringByReplacingOccurrencesOfString:@"https" withString:@"http"];
|
||||
BOOL isSelf = [[NIMSDK sharedSDK].loginManager.currentAccount isEqualToString:message.from];
|
||||
if (isSelf) {
|
||||
self.leftAvatar.hidden = YES;
|
||||
self.rightAvatar.hidden = NO;
|
||||
[self.messageBackgroundLeft uninstall];
|
||||
[self.messageBackgroundRight install];
|
||||
self.rightAvatar.imageUrl = avatarUrl;
|
||||
} else {
|
||||
self.leftAvatar.hidden = NO;
|
||||
self.rightAvatar.hidden = YES;
|
||||
[self.messageBackgroundLeft install];
|
||||
[self.messageBackgroundRight uninstall];
|
||||
self.leftAvatar.imageUrl = avatarUrl;
|
||||
}
|
||||
|
||||
NSString * messageText = message.text;
|
||||
if (!messageText || (message.messageType != NIMMessageTypeTip && message.messageType != NIMMessageTypeText)) {
|
||||
messageText = @"未知消息类型";
|
||||
}
|
||||
|
||||
_messageText.attributedText = [[NSAttributedString alloc] initWithString:messageText attributes:[MessageCell messageTextAttibutes]];
|
||||
}
|
||||
|
||||
- (NetImageView *)leftAvatar {
|
||||
if (!_leftAvatar) {
|
||||
NetImageConfig * config = [[NetImageConfig alloc] init];
|
||||
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
|
||||
config.radius = MAXFLOAT;
|
||||
_leftAvatar = [[NetImageView alloc] initWithConfig:config];
|
||||
_leftAvatar.layer.masksToBounds = YES;
|
||||
_leftAvatar.layer.cornerRadius = 45.f / 2;
|
||||
_leftAvatar.hidden = YES;
|
||||
}
|
||||
return _leftAvatar;
|
||||
}
|
||||
|
||||
- (NetImageView *)rightAvatar {
|
||||
if (!_rightAvatar) {
|
||||
NetImageConfig * config = [[NetImageConfig alloc] init];
|
||||
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
|
||||
config.radius = MAXFLOAT;
|
||||
_rightAvatar = [[NetImageView alloc] initWithConfig:config];
|
||||
_rightAvatar.layer.masksToBounds = YES;
|
||||
_rightAvatar.layer.cornerRadius = 45.f / 2;
|
||||
_rightAvatar.hidden = YES;
|
||||
}
|
||||
return _rightAvatar;
|
||||
}
|
||||
|
||||
- (UIView *)messageBackground {
|
||||
if (!_messageBackground) {
|
||||
_messageBackground = [[UIView alloc]init];
|
||||
_messageBackground.backgroundColor = ThemeColor.appCellBackgroundColor;
|
||||
_messageBackground.layer.masksToBounds = YES;
|
||||
_messageBackground.layer.cornerRadius = 8.f;
|
||||
}
|
||||
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
|
18
xplan-ios/Main/Message/Session/SendMessageView.h
Normal file
18
xplan-ios/Main/Message/Session/SendMessageView.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SendMessageView.h
|
||||
// xplan-ios
|
||||
//
|
||||
// Created by zu on 2021/11/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RoomHostDelegate.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SendMessageView : UIView
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
187
xplan-ios/Main/Message/Session/SendMessageView.m
Normal file
187
xplan-ios/Main/Message/Session/SendMessageView.m
Normal file
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// SendMessageView.m
|
||||
// xplan-ios
|
||||
//
|
||||
// Created by zu on 2021/11/28.
|
||||
//
|
||||
|
||||
#import "SendMessageView.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <NIMSDK/NIMSDK.h>
|
||||
#import "ThemeColor.h"
|
||||
#import "XPMacro.h"
|
||||
#import "UIImage+Utils.h"
|
||||
|
||||
@interface SendMessageView ()
|
||||
|
||||
@property (nonatomic, strong) UIStackView *stackView;
|
||||
@property (nonatomic, strong) UIView *inputBackgroundView;
|
||||
@property (nonatomic, strong) UITextField *inputView;
|
||||
@property (nonatomic, strong) UIButton *sendButton;
|
||||
|
||||
@end
|
||||
|
||||
#define VIEW_HEIGHT (kSafeAreaBottomHeight + 50)
|
||||
|
||||
@implementation SendMessageView
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super initWithFrame:CGRectMake(0, KScreenHeight - VIEW_HEIGHT, KScreenWidth, VIEW_HEIGHT)];
|
||||
if (self) {
|
||||
[self addNotification];
|
||||
[self initViews];
|
||||
[self initLayout];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Response
|
||||
|
||||
- (void)sendButtonDidClick:(UIButton *)sender {
|
||||
|
||||
}
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification {
|
||||
[self.superview bringSubviewToFront:self];
|
||||
NSDictionary *info = [notification userInfo];
|
||||
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
NSNumber *curve = [info objectForKey:UIKeyboardAnimationCurveUserInfoKey];
|
||||
CGFloat duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
|
||||
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.y = self.superview.frame.size.height - keyboardFrame.size.height - 50;
|
||||
|
||||
UIViewAnimationOptions options = (UIViewAnimationOptions)curve << 16;
|
||||
[UIView animateWithDuration:duration delay:0.0 options:options animations:^{
|
||||
self.frame = newFrame;
|
||||
[self mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.superview);
|
||||
make.bottom.equalTo(self.superview).offset(-keyboardFrame.size.height + kSafeAreaBottomHeight);
|
||||
make.height.equalTo(@(VIEW_HEIGHT));
|
||||
}];
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)keyboardWillHidden:(NSNotification *)notification {
|
||||
NSDictionary *info = [notification userInfo];
|
||||
NSNumber *curve = [info objectForKey:UIKeyboardAnimationCurveUserInfoKey];
|
||||
CGFloat duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
|
||||
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.y = self.superview.frame.size.height - VIEW_HEIGHT;
|
||||
|
||||
UIViewAnimationOptions options = (UIViewAnimationOptions)curve << 16;
|
||||
[UIView animateWithDuration:duration delay:0.0 options:options animations:^{
|
||||
self.frame = newFrame;
|
||||
[self mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.left.right.equalTo(self.superview);
|
||||
make.height.equalTo(@(VIEW_HEIGHT));
|
||||
}];
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
-(void)textFieldEditChanged:(NSNotification *)notification{
|
||||
self.sendButton.enabled = self.inputView.text.length > 0;
|
||||
}
|
||||
|
||||
- (void)initViews {
|
||||
self.backgroundColor = [ThemeColor appCellBackgroundColor];
|
||||
[self addSubview:self.stackView];
|
||||
[self.inputBackgroundView addSubview:self.inputView];
|
||||
[self.stackView addArrangedSubview:self.inputBackgroundView];
|
||||
[self.stackView addArrangedSubview:self.sendButton];
|
||||
}
|
||||
|
||||
- (void)initLayout {
|
||||
[self.stackView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self).offset(15);
|
||||
make.right.mas_equalTo(self).offset(-15);
|
||||
make.top.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(self).offset(-kSafeAreaBottomHeight);
|
||||
}];
|
||||
|
||||
[self.sendButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(50);
|
||||
make.top.bottom.mas_equalTo(self.stackView).inset(10);
|
||||
}];
|
||||
|
||||
[self.inputBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(36);
|
||||
make.left.mas_equalTo(self.stackView);
|
||||
make.right.mas_equalTo(self.sendButton.mas_left).offset(-15);
|
||||
}];
|
||||
|
||||
[self.inputView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(self.inputBackgroundView).offset(8);
|
||||
make.right.mas_equalTo(self.inputBackgroundView).offset(-8);
|
||||
make.centerY.mas_equalTo(self.inputBackgroundView);
|
||||
}];
|
||||
|
||||
[self mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(VIEW_HEIGHT);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)addNotification {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHidden:) name:UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldEditChanged:) name:UITextFieldTextDidChangeNotification object:self.inputView];
|
||||
}
|
||||
|
||||
- (UIStackView *)stackView {
|
||||
if (!_stackView) {
|
||||
_stackView = [[UIStackView alloc] init];
|
||||
_stackView.axis = UILayoutConstraintAxisHorizontal;
|
||||
_stackView.distribution = UIStackViewDistributionFill;
|
||||
_stackView.alignment = UIStackViewAlignmentCenter;
|
||||
_stackView.spacing = 10;
|
||||
}
|
||||
return _stackView;
|
||||
}
|
||||
|
||||
- (UITextField *)inputView{
|
||||
if (!_inputView) {
|
||||
_inputView = [[UITextField alloc] init];
|
||||
NSAttributedString * attribute = [[NSAttributedString alloc] initWithString:@"请输入消息" attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:15], NSForegroundColorAttributeName :UIColorFromRGB(0x555574)}];
|
||||
_inputView.attributedPlaceholder = attribute;
|
||||
_inputView.borderStyle = UITextBorderStyleNone;
|
||||
_inputView.tintColor = [ThemeColor appMainColor];
|
||||
_inputView.textColor = [ThemeColor mainTextColor];
|
||||
_inputView.font = [UIFont systemFontOfSize:13.f];
|
||||
[_inputView setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
|
||||
|
||||
}
|
||||
return _inputView;
|
||||
}
|
||||
|
||||
- (UIView *)inputBackgroundView {
|
||||
if (!_inputBackgroundView) {
|
||||
_inputBackgroundView = [[UIView alloc] init];
|
||||
_inputBackgroundView.backgroundColor = UIColorFromRGB(0x35354B);
|
||||
_inputBackgroundView.layer.masksToBounds = YES;
|
||||
_inputBackgroundView.layer.cornerRadius = 4.f;
|
||||
}
|
||||
return _inputBackgroundView;
|
||||
}
|
||||
|
||||
- (UIButton *)sendButton{
|
||||
if (!_sendButton) {
|
||||
_sendButton = [[UIButton alloc] init];
|
||||
[_sendButton setTitle:@"发送" forState:UIControlStateNormal];
|
||||
_sendButton.titleLabel.textColor = [ThemeColor mainTextColor];
|
||||
_sendButton.titleLabel.font = [UIFont systemFontOfSize:15];
|
||||
[_sendButton setBackgroundImage:[UIImage imageWithColor:[ThemeColor disableButtonColor] ]forState:UIControlStateDisabled];
|
||||
[_sendButton setBackgroundImage:[UIImage gradientColorImageFromColors:@[[ThemeColor confirmButtonGradientStartColor], [ThemeColor confirmButtonGradientEndColor]] gradientType:GradientTypeLeftToRight imgSize:CGSizeMake(10, 10)] forState:UIControlStateNormal];
|
||||
_sendButton.enabled = NO;
|
||||
_sendButton.layer.cornerRadius = 5.0;
|
||||
_sendButton.layer.masksToBounds = YES;
|
||||
[_sendButton addTarget:self action:@selector(sendButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _sendButton;
|
||||
}
|
||||
|
||||
@end
|
19
xplan-ios/Main/Message/Session/SessionViewController.h
Normal file
19
xplan-ios/Main/Message/Session/SessionViewController.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// SessionViewController.h
|
||||
// xplan-ios
|
||||
//
|
||||
// Created by zu on 2021/11/28.
|
||||
//
|
||||
|
||||
#import "MvpViewController.h"
|
||||
#import <NIMSDK/NIMSDK.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SessionViewController : MvpViewController
|
||||
|
||||
- (instancetype)initWithSession:(NIMSession *)session;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
173
xplan-ios/Main/Message/Session/SessionViewController.m
Normal file
173
xplan-ios/Main/Message/Session/SessionViewController.m
Normal file
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// SessionViewController.m
|
||||
// xplan-ios
|
||||
//
|
||||
// Created by zu on 2021/11/28.
|
||||
//
|
||||
|
||||
#import "SessionViewController.h"
|
||||
#import "MessageCell.h"
|
||||
#import "SendMessageView.h"
|
||||
#import "UITableView+NIMScrollToBottom.h"
|
||||
#import "XPMacro.h"
|
||||
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface SessionViewController ()<UITableViewDelegate, UITableViewDataSource, NIMChatManagerDelegate, NIMConversationManagerDelegate, NIMMediaManagerDelegate>
|
||||
|
||||
@property (nonatomic, strong) NIMSession * session;
|
||||
@property (nonatomic, strong) NSMutableArray<NIMMessage *> * messages;
|
||||
|
||||
@property (nonatomic, strong) UITableView * sessionTableView;
|
||||
@property (nonatomic, strong) SendMessageView * sendMessageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SessionViewController
|
||||
|
||||
- (void)dealloc {
|
||||
[[NIMSDK sharedSDK].chatManager removeDelegate:self];
|
||||
[[NIMSDK sharedSDK].conversationManager removeDelegate:self];
|
||||
[[NIMSDK sharedSDK].mediaManager removeDelegate:self];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSession:(NIMSession *)session {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_session = session;
|
||||
[self initViews];
|
||||
[self initLayout];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self initData];
|
||||
[[NIMSDK sharedSDK].chatManager addDelegate:self];
|
||||
[[NIMSDK sharedSDK].conversationManager addDelegate:self];
|
||||
}
|
||||
|
||||
- (void)initViews {
|
||||
NIMUser * user = [[NIMSDK sharedSDK].userManager userInfo:self.session.sessionId];
|
||||
if (user) {
|
||||
self.title = user.userInfo.nickName;
|
||||
} else {
|
||||
self.title = @"加载中……";
|
||||
}
|
||||
|
||||
|
||||
[self.view addSubview:self.sessionTableView];
|
||||
[self.view addSubview:self.sendMessageView];
|
||||
}
|
||||
|
||||
- (void)initLayout {
|
||||
[self.sessionTableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.mas_equalTo(self.view);
|
||||
make.bottom.mas_equalTo(self.sendMessageView.mas_top);
|
||||
}];
|
||||
|
||||
[self.sendMessageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.bottom.mas_equalTo(self.view);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)initData {
|
||||
NSArray<NIMMessage *> *messages = [[[NIMSDK sharedSDK] conversationManager] messagesInSession:self.session
|
||||
message:nil
|
||||
limit:1000];
|
||||
[self.messages addObjectsFromArray:messages.copy];
|
||||
[self.sessionTableView reloadData];
|
||||
[self.sessionTableView nim_scrollToBottom:NO];
|
||||
|
||||
[[NIMSDK sharedSDK].userManager fetchUserInfos:@[self.session.sessionId] completion:^(NSArray<NIMUser *> * _Nullable users, NSError * _Nullable error) {
|
||||
if (!error) {
|
||||
self.title = users[0].userInfo.nickName;
|
||||
}
|
||||
}];
|
||||
|
||||
[[NIMSDK sharedSDK].conversationManager markAllMessagesReadInSession:self.session];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.messages.count;
|
||||
}
|
||||
|
||||
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
MessageCell * cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MessageCell class])];
|
||||
if (cell == nil) {
|
||||
cell = [[MessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NSStringFromClass([MessageCell class])];
|
||||
}
|
||||
[cell renderWithMessage:[self.messages objectAtIndex:indexPath.row]];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NIMMessage *msg = [self.messages objectAtIndex:indexPath.row];
|
||||
return [MessageCell measureHeight:msg];
|
||||
}
|
||||
|
||||
#pragma mark - NIMChatManagerDelegate
|
||||
- (void)onRecvMessages:(NSArray<NIMMessage *> *)messages {
|
||||
NIMMessage *message = messages.firstObject;
|
||||
NIMSession *session = message.session;
|
||||
if (![session isEqual:self.session] || !messages.count) {
|
||||
return;
|
||||
}
|
||||
for (NIMMessage *message in messages) {
|
||||
if (message.isDeleted) {
|
||||
continue;
|
||||
}
|
||||
[self.messages addObject:message];
|
||||
}
|
||||
[self.sessionTableView reloadData];
|
||||
[self.sessionTableView nim_scrollToBottom:YES];
|
||||
|
||||
[[NIMSDK sharedSDK].conversationManager markAllMessagesReadInSession:self.session];
|
||||
}
|
||||
|
||||
#pragma mark - NIMConversationManagerDelegate
|
||||
- (void)messagesDeletedInSession:(NIMSession *)session {
|
||||
[self.messages removeAllObjects];
|
||||
[self initData];
|
||||
}
|
||||
|
||||
- (NSArray<NIMMessage *> *)messages {
|
||||
if (!_messages) {
|
||||
_messages = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return _messages;
|
||||
}
|
||||
|
||||
- (UITableView *)sessionTableView {
|
||||
if (!_sessionTableView) {
|
||||
_sessionTableView = [[UITableView alloc] init];
|
||||
_sessionTableView.delegate = self;
|
||||
_sessionTableView.dataSource = self;
|
||||
_sessionTableView.backgroundColor = UIColor.clearColor;
|
||||
_sessionTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyBoard)];
|
||||
[_sessionTableView addGestureRecognizer:tap];
|
||||
}
|
||||
return _sessionTableView;
|
||||
}
|
||||
|
||||
- (void)closeKeyBoard {
|
||||
[self.view endEditing:YES];
|
||||
[self.sessionTableView endEditing:YES];
|
||||
}
|
||||
|
||||
- (SendMessageView *)sendMessageView {
|
||||
if (!_sendMessageView) {
|
||||
_sendMessageView = [[SendMessageView alloc] init];
|
||||
}
|
||||
return _sendMessageView;
|
||||
}
|
||||
|
||||
@end
|
@@ -64,7 +64,7 @@
|
||||
self.badgeView.hidden = NO;
|
||||
self.badgeView.badgeValue = @(recent.unreadCount).stringValue;
|
||||
} else {
|
||||
self.badgeView.hidden = NO;
|
||||
self.badgeView.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#import "SessionListViewController.h"
|
||||
#import "SessionListCell.h"
|
||||
#import "SessionViewController.h"
|
||||
#import "ThemeColor.h"
|
||||
#import "XPMacro.h"
|
||||
|
||||
@@ -83,7 +84,9 @@
|
||||
#pragma mark - UITableViewDelegate
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
// TODO: 打开私聊
|
||||
NIMRecentSession *recentSession = self.recentSessions[indexPath.row];
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:recentSession.session];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
|
Reference in New Issue
Block a user