// // 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" #import "EPEmotionColorStorage.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 *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.leading.trailing.equalTo(self.contentView).inset(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.leading.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.leading.equalTo(self.avatarImageView.mas_trailing).offset(10); make.top.equalTo(self.avatarImageView); make.trailing.equalTo(self.cardView).offset(-15); }]; // 时间 [self.cardView addSubview:self.timeLabel]; [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(self.nameLabel); make.bottom.equalTo(self.avatarImageView); make.trailing.equalTo(self.cardView).offset(-15); }]; // 内容 [self.cardView addSubview:self.contentLabel]; [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.trailing.equalTo(self.cardView).inset(15); make.top.equalTo(self.avatarImageView.mas_bottom).offset(12); }]; // 图片九宫格 [self.cardView addSubview:self.imagesContainer]; [self.imagesContainer mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.trailing.equalTo(self.cardView).inset(15); make.top.equalTo(self.contentLabel.mas_bottom).offset(12); make.height.mas_equalTo(0); // 初始高度为0,renderImages 时会 remakeConstraints }]; // 底部操作栏 [self.cardView addSubview:self.actionBar]; [self.actionBar mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.trailing.equalTo(self.cardView); make.top.equalTo(self.imagesContainer.mas_bottom).offset(12); make.height.mas_equalTo(50); // 降低底部约束优先级,避免与图片容器高度冲突 make.bottom.equalTo(self.cardView).offset(-8).priority(UILayoutPriorityDefaultHigh); }]; // 点赞按钮 [self.actionBar addSubview:self.likeButton]; [self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.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; // 配置情绪颜色 border 和 shadow [self applyEmotionColorEffect:model.emotionColor]; } /// 应用情绪颜色视觉效果(Border + Shadow) - (void)applyEmotionColorEffect:(NSString *)emotionColorHex { NSString *displayColorHex = emotionColorHex; // 如果没有保存的颜色,使用随机颜色(不持久化) if (!displayColorHex) { displayColorHex = [EPEmotionColorStorage randomEmotionColor]; } UIColor *color = [self colorFromHex:displayColorHex]; // 设置 border self.cardView.layer.borderWidth = 3.0; self.cardView.layer.borderColor = color.CGColor; // 设置 shadow(使用情绪颜色) self.cardView.layer.shadowColor = color.CGColor; self.cardView.layer.shadowOffset = CGSizeMake(0, 2); self.cardView.layer.shadowOpacity = 0.5; self.cardView.layer.shadowRadius = 16.0; } /// Hex 转 UIColor - (UIColor *)colorFromHex:(NSString *)hexString { unsigned rgbValue = 0; NSScanner *scanner = [NSScanner scannerWithString:hexString]; [scanner setScanLocation:1]; // 跳过 # [scanner scanHexInt:&rgbValue]; return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0]; } // 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.leading.trailing.equalTo(self.cardView).inset(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.leading.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.leading.trailing.equalTo(self.cardView).inset(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; // 圆角 // Shadow 和 Border 将由 applyEmotionColorEffect 动态设置 _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 *)imageViews { if (!_imageViews) { _imageViews = [NSMutableArray array]; } return _imageViews; } @end