Files
real-e-party-iOS/YuMi/E-P/NewMoments/Views/EPMomentCell.m
edwinQQQ ceaeb5c951 feat: 添加 EPMomentPublishViewController 以支持图文发布功能
主要变更:
1. 新增 EPMomentPublishViewController.h 和 EPMomentPublishViewController.m 文件,提供图文发布页面的 UI 和逻辑。
2. 实现了发布按钮、文本输入框、图片选择功能,支持最多选择 9 张图片。
3. 集成了 TZImagePickerController 以便于用户选择图片。
4. 更新了 EPMomentViewController,添加了跳转到发布页面的逻辑。

此功能旨在提升用户体验,简化图文发布流程。
2025-10-10 19:06:06 +08:00

404 lines
14 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// NewMomentCell.m
// YuMi
//
// Created by AI on 2025-10-09.
// Copyright © 2025 YuMi. All rights reserved.
//
#import "EPMomentCell.h"
#import "MomentsInfoModel.h"
#import "AccountInfoStorage.h"
#import "Api+Moments.h"
#import "NetImageView.h"
@interface EPMomentCell ()
// MARK: - UI Components
/// 卡片容器
@property (nonatomic, strong) UIView *cardView;
/// 头像(网络)
@property (nonatomic, strong) NetImageView *avatarImageView;
/// 用户名
@property (nonatomic, strong) UILabel *nameLabel;
/// 时间标签
@property (nonatomic, strong) UILabel *timeLabel;
/// 内容标签
@property (nonatomic, strong) UILabel *contentLabel;
/// 图片容器(九宫格)
@property (nonatomic, strong) UIView *imagesContainer;
@property (nonatomic, strong) NSMutableArray<NetImageView *> *imageViews;
/// 底部操作栏
@property (nonatomic, strong) UIView *actionBar;
/// 点赞按钮
@property (nonatomic, strong) UIButton *likeButton;
/// 评论按钮
@property (nonatomic, strong) UIButton *commentButton;
// 分享按钮已移除
/// 当前数据模型
@property (nonatomic, strong) MomentsInfoModel *currentModel;
@end
@implementation EPMomentCell
// MARK: - Lifecycle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.backgroundColor = [UIColor clearColor];
[self setupUI];
}
return self;
}
// MARK: - Setup UI
- (void)setupUI {
// 卡片容器(圆角矩形 + 阴影)
[self.contentView addSubview:self.cardView];
[self.cardView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(15);
make.right.equalTo(self.contentView).offset(-15);
make.top.equalTo(self.contentView).offset(8);
make.bottom.equalTo(self.contentView).offset(-8);
}];
// 头像(圆角矩形,不是圆形!)
[self.cardView addSubview:self.avatarImageView];
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(15);
make.top.equalTo(self.cardView).offset(15);
make.size.mas_equalTo(CGSizeMake(40, 40));
}];
// 用户名
[self.cardView addSubview:self.nameLabel];
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.avatarImageView.mas_right).offset(10);
make.top.equalTo(self.avatarImageView);
make.right.equalTo(self.cardView).offset(-15);
}];
// 时间
[self.cardView addSubview:self.timeLabel];
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.nameLabel);
make.bottom.equalTo(self.avatarImageView);
make.right.equalTo(self.cardView).offset(-15);
}];
// 内容
[self.cardView addSubview:self.contentLabel];
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(15);
make.right.equalTo(self.cardView).offset(-15);
make.top.equalTo(self.avatarImageView.mas_bottom).offset(12);
}];
// 图片九宫格
[self.cardView addSubview:self.imagesContainer];
[self.imagesContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(15);
make.right.equalTo(self.cardView).offset(-15);
make.top.equalTo(self.contentLabel.mas_bottom).offset(12);
}];
// 底部操作栏
[self.cardView addSubview:self.actionBar];
[self.actionBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.cardView);
make.top.equalTo(self.imagesContainer.mas_bottom).offset(12);
make.height.mas_equalTo(50);
make.bottom.equalTo(self.cardView).offset(-8);
}];
// 点赞按钮
[self.actionBar addSubview:self.likeButton];
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.actionBar).offset(15);
make.centerY.equalTo(self.actionBar);
make.width.mas_greaterThanOrEqualTo(60);
}];
// 评论按钮
[self.actionBar addSubview:self.commentButton];
[self.commentButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.actionBar);
make.centerY.equalTo(self.actionBar);
make.width.mas_greaterThanOrEqualTo(60);
}];
// 右侧占位(去掉分享按钮后,右边保持留白)
}
// MARK: - Public Methods
- (void)configureWithModel:(MomentsInfoModel *)model {
self.currentModel = model;
// 配置用户名
self.nameLabel.text = model.nick ?: @"匿名用户";
// 配置时间
self.timeLabel.text = model.publishTime;
// 配置内容
self.contentLabel.text = model.content ?: @"";
// 配置图片九宫格
[self renderImages:model.dynamicResList];
// 配置点赞/评论数(安全整型,避免负数和溢出)
NSInteger likeCnt = MAX(0, model.likeCount.integerValue);
NSInteger cmtCnt = MAX(0, model.commentCount.integerValue);
[self.likeButton setTitle:[NSString stringWithFormat:@"👍 %ld", (long)likeCnt] forState:UIControlStateNormal];
[self.commentButton setTitle:[NSString stringWithFormat:@"💬 %ld", (long)cmtCnt] forState:UIControlStateNormal];
self.avatarImageView.imageUrl = model.avatar;
}
// MARK: - Images Grid
- (void)renderImages:(NSArray *)resList {
// 清理旧视图
for (UIView *iv in self.imageViews) { [iv removeFromSuperview]; }
[self.imageViews removeAllObjects];
if (resList.count == 0) {
[self.imagesContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(15);
make.right.equalTo(self.cardView).offset(-15);
make.top.equalTo(self.contentLabel.mas_bottom).offset(0);
make.height.mas_equalTo(0);
}];
return;
}
NSInteger columns = 3;
CGFloat spacing = 6.0;
CGFloat totalWidth = [UIScreen mainScreen].bounds.size.width - 30 - 30; // 左右各 15 内边距,再减卡片左右 15
CGFloat itemW = floor((totalWidth - spacing * (columns - 1)) / columns);
for (NSInteger i = 0; i < resList.count && i < 9; i++) {
NetImageConfig *config = [[NetImageConfig alloc] init];
config.placeHolder = [UIImageConstant defaultBannerPlaceholder];
NetImageView *iv = [[NetImageView alloc] initWithConfig:config];
iv.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];
iv.layer.cornerRadius = 6;
iv.layer.masksToBounds = YES;
iv.contentMode = UIViewContentModeScaleAspectFill;
[self.imagesContainer addSubview:iv];
[self.imageViews addObject:iv];
NSInteger row = i / columns;
NSInteger col = i % columns;
[iv mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.imagesContainer).offset((itemW + spacing) * col);
make.top.equalTo(self.imagesContainer).offset((itemW + spacing) * row);
make.size.mas_equalTo(CGSizeMake(itemW, itemW));
}];
// 绑定网络图片
NSString *url = nil;
id item = resList[i];
if ([item isKindOfClass:[NSDictionary class]]) {
url = [item valueForKey:@"resUrl"] ?: [item valueForKey:@"url"];
} else if ([item respondsToSelector:@selector(resUrl)]) {
url = [item valueForKey:@"resUrl"];
}
iv.imageUrl = url;
}
NSInteger rows = ((MIN(resList.count, 9) - 1) / columns) + 1;
CGFloat height = rows * itemW + (rows - 1) * spacing;
[self.imagesContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(15);
make.right.equalTo(self.cardView).offset(-15);
make.top.equalTo(self.contentLabel.mas_bottom).offset(12);
make.height.mas_equalTo(height);
}];
}
/// 格式化时间戳为相对时间
- (NSString *)formatTimeInterval:(NSInteger)timestamp {
if (timestamp <= 0) return @"刚刚";
NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] - timestamp / 1000.0;
if (interval < 60) {
return @"刚刚";
} else if (interval < 3600) {
return [NSString stringWithFormat:@"%.0f分钟前", interval / 60];
} else if (interval < 86400) {
return [NSString stringWithFormat:@"%.0f小时前", interval / 3600];
} else if (interval < 604800) {
return [NSString stringWithFormat:@"%.0f天前", interval / 86400];
} else {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
return [formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:timestamp / 1000.0]];
}
}
// MARK: - Actions
- (void)onLikeButtonTapped {
if (!self.currentModel) return;
NSLog(@"[NewMomentCell] 点赞动态: %@", self.currentModel.dynamicId);
NSString *uid = [[AccountInfoStorage instance] getUid];
NSString *dynamicId = self.currentModel.dynamicId;
NSString *status = self.currentModel.isLike ? @"0" : @"1"; // 0=取消1=点赞
NSString *likedUid = self.currentModel.uid;
NSString *worldId = self.currentModel.worldId > 0 ? @(self.currentModel.worldId).stringValue : @"";
[Api momentsLike:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
if (code == 200) {
// 更新点赞状态
self.currentModel.isLike = !self.currentModel.isLike;
NSInteger likeCount = [self.currentModel.likeCount integerValue];
likeCount += self.currentModel.isLike ? 1 : -1;
self.currentModel.likeCount = @(likeCount).stringValue;
// 更新 UI
[self.likeButton setTitle:[NSString stringWithFormat:@"👍 %ld", (long)self.currentModel.likeCount] forState:UIControlStateNormal];
NSLog(@"[NewMomentCell] 点赞成功");
} else {
NSLog(@"[NewMomentCell] 点赞失败: %@", msg);
}
} dynamicId:dynamicId uid:uid status:status likedUid:likedUid worldId:worldId];
}
- (void)onCommentButtonTapped {
NSLog(@"[NewMomentCell] 评论");
// TODO: 实现评论逻辑
}
- (void)onShareButtonTapped {
NSLog(@"[NewMomentCell] 分享");
// TODO: 实现分享逻辑
}
// MARK: - Lazy Loading
- (UIView *)cardView {
if (!_cardView) {
_cardView = [[UIView alloc] init];
_cardView.backgroundColor = [UIColor whiteColor];
_cardView.layer.cornerRadius = 12; // 圆角
_cardView.layer.shadowColor = [UIColor blackColor].CGColor;
_cardView.layer.shadowOffset = CGSizeMake(0, 2);
_cardView.layer.shadowOpacity = 0.1;
_cardView.layer.shadowRadius = 8;
_cardView.layer.masksToBounds = NO;
}
return _cardView;
}
- (UIImageView *)avatarImageView {
if (!_avatarImageView) {
NetImageConfig *config = [[NetImageConfig alloc] init];
config.imageType = ImageTypeUserIcon;
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
_avatarImageView = [[NetImageView alloc] initWithConfig:config];
_avatarImageView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
_avatarImageView.layer.cornerRadius = 8; // 圆角矩形,不是圆形!
_avatarImageView.layer.masksToBounds = YES;
_avatarImageView.contentMode = UIViewContentModeScaleAspectFill;
}
return _avatarImageView;
}
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [[UILabel alloc] init];
_nameLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium];
_nameLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1.0];
}
return _nameLabel;
}
- (UILabel *)timeLabel {
if (!_timeLabel) {
_timeLabel = [[UILabel alloc] init];
_timeLabel.font = [UIFont systemFontOfSize:12];
_timeLabel.textColor = [UIColor colorWithWhite:0.6 alpha:1.0];
}
return _timeLabel;
}
- (UILabel *)contentLabel {
if (!_contentLabel) {
_contentLabel = [[UILabel alloc] init];
_contentLabel.font = [UIFont systemFontOfSize:15];
_contentLabel.textColor = [UIColor colorWithWhite:0.3 alpha:1.0];
_contentLabel.numberOfLines = 0;
_contentLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
return _contentLabel;
}
- (UIView *)actionBar {
if (!_actionBar) {
_actionBar = [[UIView alloc] init];
_actionBar.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1.0];
}
return _actionBar;
}
- (UIButton *)likeButton {
if (!_likeButton) {
_likeButton = [self createActionButtonWithTitle:@"👍 0"];
[_likeButton addTarget:self action:@selector(onLikeButtonTapped) forControlEvents:UIControlEventTouchUpInside];
}
return _likeButton;
}
- (UIButton *)commentButton {
if (!_commentButton) {
_commentButton = [self createActionButtonWithTitle:@"💬 0"];
[_commentButton addTarget:self action:@selector(onCommentButtonTapped) forControlEvents:UIControlEventTouchUpInside];
}
return _commentButton;
}
- (UIButton *)shareButton {
return nil;
}
- (UIButton *)createActionButtonWithTitle:(NSString *)title {
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:title forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:13];
[button setTitleColor:[UIColor colorWithWhite:0.5 alpha:1.0] forState:UIControlStateNormal];
return button;
}
- (UIView *)imagesContainer {
if (!_imagesContainer) {
_imagesContainer = [[UIView alloc] init];
_imagesContainer.backgroundColor = [UIColor clearColor];
}
return _imagesContainer;
}
- (NSMutableArray<NetImageView *> *)imageViews {
if (!_imageViews) {
_imageViews = [NSMutableArray array];
}
return _imageViews;
}
@end